Круто, но до чего же тяжелый синтаксис
От: Аноним  
Дата: 14.05.11 17:15
Оценка:
Не сочтите за троллинг. Решил таки сразиться с фобиями и расширить горизонты познания, но видимо с "N" не срастется у меня — наверное я недостаточно "функционален".
Сравните например Nemerle — Late.n и Boo — PropertyMacro.boo. Я честно скажу, что сейчас толком не понимаю происходящее ни в том ни в другом случае, но в Boo хотя бы можно поразбираться — вполне читаемый код для любого знакомого с шарпом. От кода немерля же начинают болеть глаза на 15 секунде. Тут конечно будет контраргумент, что макросы Бу и макросами то назвать нельзя по сравнению с Н, но хотя бы для основных сценариев использования подумайте над упрощенным читаемым синтаксисом.

ЗЫ Несмотря ни на что поздравляю с релизом! Понимаю что труд титанический, надеюсь на дальнейшее развитие языка.
Re: Круто, но до чего же тяжелый синтаксис
От: kochetkov.vladimir Россия https://kochetkov.github.io
Дата: 14.05.11 17:27
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>Не сочтите за троллинг. Решил таки сразиться с фобиями и расширить горизонты познания, но видимо с "N" не срастется у меня — наверное я недостаточно "функционален".


Тут есть два момента: насколько я люблю питон за его синтаксис на отступах, но попытки писать в нем на Nemerle я бросил довольно давно. В т.ч., потому что по непонятной мне причине, код на Nemerle на отступах я воспринимаю намного тяжелее. И я бы все же рекомендовал начинать знакомство с языком не с макросов. Там действительно глазоломные конструкции встречаются чаще, да и в плане понимания того, что делает код, макросы — самое сложное, что есть в языке.

Я не пытаюсь спорить, а просто советую что можно сделать прямо сейчас, чтобы было легче знакомиться с языком.

А>ЗЫ Несмотря ни на что поздравляю с релизом! Понимаю что труд титанический, надеюсь на дальнейшее развитие языка.



[Интервью] .NET Security — это просто
Автор: kochetkov.vladimir
Дата: 07.11.17
Re: Круто, но до чего же тяжелый синтаксис
От: hardcase Пират http://nemerle.org
Дата: 14.05.11 17:30
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Я честно скажу, что сейчас толком не понимаю происходящее ни в том ни в другом случае, но в Boo хотя бы можно поразбираться — вполне читаемый код для любого знакомого с шарпом


Наверно сперва нужно понимать, для чего применяется тот или иной макрос.
Макрос Late никак нельзя сравнивать с примитивным генератором свойств (аналог в Nemerle — Accessor, но он также покруче). Late выполняет переписывание кода на использование рефлексии при обращении к членам.
/* иЗвиНите зА неРовнЫй поЧерК */
Re: Круто, но до чего же тяжелый синтаксис
От: VladD2 Российская Империя www.nemerle.org
Дата: 14.05.11 17:45
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Не сочтите за троллинг. Решил таки сразиться с фобиями и расширить горизонты познания, но видимо с "N" не срастется у меня — наверное я недостаточно "функционален".


Просто не стоит залезать в сложные вещи не разобравшись в начале с базовыми.

А>Сравните например Nemerle &mdash; Late.n и Boo &mdash; PropertyMacro.boo.


PropertyMacro.boo я открыть так и не смог. Гугль тоже на него ссылку не дал.

Но судя по названию файла там лежит макра "превращающая" поле в свойство. Аналогичный макрос немерла выглядит так (и надо учитывать, что у этого макроса очень много наворотов):
  /// Adds property accessor for field.
  /// By default adds only getter.
  /// You can specify the following flags:
  /// WantSetter, Setter, Internal, Protected, Override, Virtual.
  /// Also you can specify the property name manualy (by default the name
  /// is generated from the field name).
  [Nemerle.MacroUsage (Nemerle.MacroPhase.BeforeInheritance,
                       Nemerle.MacroTargets.Field,
                       Inherited = false, AllowMultiple = true)]
  macro Accessor (current_type : TypeBuilder, storage_field : ParsedField, params args : list [PExpr])
  {
    def usage =
        "usage: Accessor (name, flags = MODIFIERS, get (MODIFIERS), set (MODIFIERS), "
        "attributes (LIST OF ATTRIBUTES)), where all sections are optional";

    mutable setterMods = NemerleAttributes.None;
    mutable getterMods = NemerleAttributes.Public;
    mutable want_setter = false;
    mutable attributes = [];
    mutable oname = None ();

    def parse_opts (expr, allow_deprec)
    {
      match (expr)
      {
        | <[ $("WantSetter" : dyn) ]>
        | <[ $("Setter"     : dyn) ]> =>
          unless (allow_deprec)
            Message.Error("WantSetter / Setter is not allowed outside 'flags' section");

          want_setter = true;
          NemerleAttributes.None

        | <[ $("Internal"  : dyn) ]>  => NemerleAttributes.Internal
        | <[ $("Protected" : dyn) ]>  => NemerleAttributes.Protected
        | <[ $("Override"  : dyn) ]>  => NemerleAttributes.Override
        | <[ $("Virtual"   : dyn) ]>  => NemerleAttributes.Virtual
        | <[ None ]>                  => NemerleAttributes.Extern // will be removed
        | <[ $e1 | $e2 ]> => (parse_opts(e1, allow_deprec) | parse_opts(e2, allow_deprec))
        | e => Message.FatalError($"bad accessor option, $e")
      }
    }

    foreach (a in args)
    {
      | <[ flags = $opts ]> =>
        def opts = parse_opts (opts, true);
        getterMods |= opts;

        when (want_setter)
          setterMods |= getterMods;

      | <[ $(n : dyn) ]>            => oname = Some(n)
      | <[ set ($opts) ]>           => setterMods |= parse_opts (opts, false)
      | <[ get ($opts) ]>           => getterMods |= parse_opts (opts, false)
      | <[ attributes (..$attrs) ]> => attributes += attrs
      | _ => Message.FatalError (usage);
    }

    // __some_foo__bar ==> SomeFooBar
    def transformed_name =
      {
        def sb = StringBuilder ();
        mutable next_upper = true;

        foreach (ch in storage_field.Name)
        {
          if (ch == '_')
            next_upper = true;
          else if (next_upper)
          {
            _ = sb.Append (char.ToUpperInvariant (ch));
            next_upper = false;
          }
          else
            _ = sb.Append (ch);
        }

        sb.ToString()
      };
    def name = oname.WithDefault(transformed_name);

    when (getterMods %&& NemerleAttributes.Extern)
      getterMods = NemerleAttributes.None;

    def take_minimum_access(mods)
    {
      if (mods %&& NemerleAttributes.Protected && !(mods %&& NemerleAttributes.Internal))
        NemerleAttributes.Protected
      else if (mods %&& NemerleAttributes.Internal && !(mods %&& NemerleAttributes.Protected))
        NemerleAttributes.Internal
      else if (mods %&& NemerleAttributes.Protected && mods %&& NemerleAttributes.Internal)
        NemerleAttributes.Internal | NemerleAttributes.Protected
      else if (mods %&& NemerleAttributes.Public)
        NemerleAttributes.Public
      else
        NemerleAttributes.None
    }

    getterMods = (getterMods & ~NemerleAttributes.AccessModifiers) | take_minimum_access(getterMods);
    setterMods = (setterMods & ~NemerleAttributes.AccessModifiers) | take_minimum_access(setterMods);

    def fieldref    = <[ $(storage_field.PName : name) ]>;
    def setterAttrs = Modifiers(setterMods, [<[ System.Diagnostics.DebuggerStepThroughAttribute ]>,<[System.Runtime.CompilerServices.CompilerGenerated]>]);
    def getterAttrs = Modifiers(getterMods, [<[ System.Diagnostics.DebuggerStepThroughAttribute ]>,<[System.Runtime.CompilerServices.CompilerGenerated]>]);
    def propAttrs   = Modifiers(NemerleAttributes.None, attributes);

    def prop =
      if (setterMods != NemerleAttributes.None && getterMods != NemerleAttributes.None)
        <[ decl:
          ..$propAttrs
          $(name : dyn) : $(storage_field.ty)
          {
            ..$setterAttrs set { $fieldref = value; }
            ..$getterAttrs get { $fieldref }
          }
        ]>
      else if (getterMods != NemerleAttributes.None)
        <[ decl:
          ..$propAttrs

          $(name : dyn) : $(storage_field.ty)
          {
            ..$getterAttrs get { $fieldref }
          }
        ]>;
      else if (setterMods != NemerleAttributes.None)
        <[ decl:
          ..$propAttrs

          $(name : dyn) : $(storage_field.ty)
          {
            ..$setterAttrs set { $fieldref = value }
          }
        ]>;
      else Message.FatalError ("no accessor will be visible with specified modifiers");

    prop.SetEnv(storage_field.Env);

    def totalMods = getterMods | setterMods;

    if (totalMods %&& NemerleAttributes.Public)
      prop.Attributes = (totalMods & ~NemerleAttributes.AccessModifiers) | NemerleAttributes.Public;
    else if (totalMods %&& NemerleAttributes.Internal && totalMods %&& NemerleAttributes.Protected)
      prop.Attributes = (totalMods & ~NemerleAttributes.AccessModifiers) | NemerleAttributes.Internal | NemerleAttributes.Protected;
    else if (totalMods %&& NemerleAttributes.Internal)
      prop.Attributes = (totalMods & ~NemerleAttributes.AccessModifiers) | NemerleAttributes.Internal;
    else if (totalMods %&& NemerleAttributes.Protected)
      prop.Attributes = (totalMods & ~NemerleAttributes.AccessModifiers) | NemerleAttributes.Protected;
    else
      prop.Attributes = (totalMods & ~NemerleAttributes.AccessModifiers) | NemerleAttributes.Private;

    when (storage_field.Attributes %&& NemerleAttributes.Static)
      prop.Attributes |= NemerleAttributes.Static;

    current_type.Define(prop);
  }


Не вижу в нем что-то не читаемое. Все что нужно знать для его понимания — это что такое квази-цитаты и каков их синтаксис.

Макрос же Late — это (с небольшой натяжкой) аналог dynamic из C# 4.0. Он позволяет ввести динамическую типизацию (отложить разрешение имен до рантайма). Так что сравнивать его с макрой создающей эксесоры не стоит.

Ну, а начинать изучение макросов нужно с макры типа if или using:
  macro @if (cond, e1, e2)
  syntax ("if", "(", cond, ")", e1, Optional (";"), "else", e2)
  {
    <[
      match ($cond : bool)
      {
        | true => $e1
        | _ => $e2
      }
    ]>
  }


В ней что-то непонятно?

А>Я честно скажу, что сейчас толком не понимаю происходящее ни в том ни в другом случае, но в Boo хотя бы можно поразбираться — вполне читаемый код для любого знакомого с шарпом.


Это именно от того, что что происходящее не понятно. Как только начинаешь разбираться, впечатление сразу же меняется.

А>От кода немерля же начинают болеть глаза на 15 секунде.


Возможно ты выбрал не лучший пример. Хотя для решаемой задачи код не так уж и сложен. В практически весь синтаксис выражений немерла переписывается в динамические вызовы на базе рефлексии. Не трудно понять, что объем работы не малый.

А>Тут конечно будет контраргумент, что макросы Бу и макросами то назвать нельзя по сравнению с Н, но хотя бы для основных сценариев использования подумайте над упрощенным читаемым синтаксисом.


Все тут нормально. Просто надо именно что понимать проходящее. А для этого нужно разобраться с паттерн-матчингом и квази-цитатами. Это можно сделать за пару часов.

А>ЗЫ Несмотря ни на что поздравляю с релизом! Понимаю что труд титанический, надеюсь на дальнейшее развитие языка.


Спасибо!
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: Круто, но до чего же тяжелый синтаксис
От: VladD2 Российская Империя www.nemerle.org
Дата: 14.05.11 18:58
Оценка:
Здравствуйте, Аноним, Вы писали:

А> Boo &mdash; PropertyMacro.boo. Я честно скажу, что сейчас толком не понимаю происходящее ни в том ни в другом случае, но в Boo хотя бы можно поразбираться — вполне читаемый код для любого знакомого с шарпом.


Таки смог открыть указанный файл. Там довольно простой макрос. Он сильно отличается от того что есть в Немерле, так что сравнивать их нельзя. Этот макрос по сути вводит автосвойство. Аналогичная функциональность встроена в компилятор немерла. По этому продемонстрирую "читаемость" этого кода разобрав его по частям. Далее я приведу гипотетический аналогичный код на немерле. Итак вот код макроса (инлайном даются пояснения):
macro property:

    # этот код генерирует исключение содержащее описание синтаксиса, если 
    # переданный макросу AST некорректный. PropertyMacroParser.IsValidProperty() проверяет корректность синтаксиса.
    raise "property <name> [as type] [= initialValue]" unless PropertyMacroParser.IsValidProperty(property)

    # Этот код извлекает значение параметра макроса (AST) и помещает его в переменную "argument".
    # В немерле это делать не надо, так как параметры указываются явно.
    argument = property.Arguments[0]
    # Этот код пытается привести ветку AST к типу BinaryExpression (бинарное выражение)
    initializationForm = argument as BinaryExpression
    if initializationForm is not null:
        # в случае успеха левую часть бинарного выражения пихает в переменную declaration
        declaration = initializationForm.Left
        # а правую в initializer
        initializer = initializationForm.Right
    else:
        # в случае если в argument находится не BinaryExpression...
        declaration = argument
        initializer = null
    # Код извлечения имени свойства из выражения вынесен в отдельный метод, так как это 
    # не элементарная операция.
    name = PropertyMacroParser.PropertyNameFrom(declaration)
    # Тоже самое с именем типа.
    type = PropertyMacroParser.PropertyTypeFrom(declaration)
    # Далее формируется уникальное имя для поля (которое создается макросом).
    # Так как гигиены у макросов (по всей видимости) нет, для генерации уникального имени
    # используется специальный API-вызов Context.GetUniqueName()
    backingField = ReferenceExpression(Name: Context.GetUniqueName(name.ToString()))

    # Далее с помощью квази-цитирования формируется код поля хранящего значение свойства
    # и код непосредственно свойства чьи эксесоры просто читают и пишут в/из поле.
    # По всей видимости синтаксиса квази-цитат ля нет, или это хитрый код с целью сэкономить 
    # место, по этому объявляется fake-класс "_" в котором и объявляются оба члена (поле и свойство).
    prototype = [|

        class _:

            private $backingField as $type = $initializer

            $name:
                get: return $backingField
                set: $backingField = value
    |]

    # В качестве возвращаемого значения макроса, возвращаются все члены этого класса.
    yieldAll prototype.Members 

# Класс-помощник. В него вынесен код проверок и т.п. чтобы сделать основной код более читабельным.
internal static class PropertyMacroParser:

    # Извлечение имени (ссылки на имя).
    def PropertyNameFrom(e as Expression) as ReferenceExpression:
        # Если выражение это TryCastExpression...
        declaration = e as TryCastExpression (т.е. "x as y")
        if declaration is not null:
            # то возвращаем Target (т.е. "x")
            return declaration.Target
        return e # иначе возвращаем все выражение

    # Извлекает имя типа. Код почти аналогичен PropertyNameFrom. Можно сказать копипэст.
    def PropertyTypeFrom(e as Expression):
        declaration = e as TryCastExpression
        if declaration is not null:
            return declaration.Type
        return null

    # Код проверки корректности AST. 
    def IsValidProperty(property as MacroStatement):
        if len(property.Arguments) != 1: # проверяем, что параметр ровно один (шиза)
            return false
        if not property.Body.IsEmpty: # проверяем, что Body не пусто (не знаю уж что в этом Body)
            return false
        argument = property.Arguments[0] # копируем AST из первого аргумента в переменную argument
        # Если в argument бинарное выражение...
        initializationForm = argument as BinaryExpression
        if initializationForm is not null:
            # ... то убеждаемся, что это оператор присвоения "="
            if initializationForm.Operator != BinaryOperatorType.Assign:
                return false
            # проверяем левую часть выражения...
            return IsValidPropertyDeclaration(initializationForm.Left)
        # если это не оператор присвоения, проверяем аргумент...
        return IsValidPropertyDeclaration(argument)

    def IsValidPropertyDeclaration(e as Expression):
        # если выражение "e" - это ссылка на имя...
        if e.NodeType == NodeType.ReferenceExpression:
            return true # проверка успешна.
        # иначе, "e" - это операция приведения типа?
        declaration = e as TryCastExpression 
        if declaration is null: return false # если нет, то неудача.
        # если да, то убеждаемся что у правая часть (т.е. у "x" в "x as y") 
        # имеет тип ссылка на имя. Тогда успех.
        return declaration.Target.NodeType == NodeType.ReferenceExpression


Итого мы имеем кучу императивного кода цель которого декомпозиция выражений и проверки корректности выражений.

Теперь я попытаюсь написать код аналогичный приведенному выше. Написать полный аналог я не могу, так как подходы в макросистемах отличаются.
// параметры передаются в явном виде. Нам не надо их вынимать с помощью Property.Arguments[0].
// В argument уже нужный нам AST. Количество параметров так же проверять не нужно.
macro Property(typeBuilder : TypeBuilder, argument)
{
  // Для декомпозиции выражения используем паттерн-матчинг:
  match (argument)
  {
    // Паттерн ниже разбирает ситуацию "x = y", т.е. когда тип не задан. 
    // При этом propertyType помещается плэйсхолдер "_" означающий - "любой тип".
    | <[ $(propName : name) = $initializer ]> with propertyType = <[ _ ]>
    // Следующий паттерн разбирает ситуацию когда тип задан (т.е. "x : t = y").
    | <[ $(propName : name) : $propertyType = $initializer ]> 
    // аналогично, два паттерна для случаев когда не задано инициализирующее выражение и тип
    | <[ $(propName : name) : $propertyType ]> with initializer = null 
    | <[ $(propName : name) ]> with (initializer = null, propertyType = <[ _ ]>) =>
      def field    = 
        if (initializer == null)
          // мы можем использовать любые имена, так как макро-система немерла поддерживает 
          // гигиеничность. Это значит что имена из квази-цитат ни с чем не пересекутся 
          // и нам на надо их генерировать в ручную (как в Буу).
          <[ decl: backField : $propertyType; ]>
        else
          <[ decl: backField : $propertyType = $initializer; ]>;

      def property = <[ decl:
                        public $(propName : name) : $propertyType 
                        {
                          get { $backField }
                          set { $backField = value }
                        }
                     ]>;
      // Мы использували квази-цитаты для объявления отдельных членов, а не целого класса,
      // так что остается только добавить их в текущий класс.
      typeBuilder.Add(field);
      typeBuilder.Add(property);

    | _ => Message.FatalError("property <name> [: type] [= initialValue]")
  }
}


Обрати внимание, что кода возящегося с объектной моделью AST в случае немерла вообще нет. Код декомпозиции выражений декларативен до нешльзя.
Возни с генерацией имен тоже нет.
Проверка структуры кода целиком реализована на квази-цитатах и полностью декларативна.
В итоге код получился в разы короче и в десятки раз понятнее. Вот только нужно понимать что такое паттерн-матчинг и как работает квази-цитирование.
Очевидно, что в Бу квази-цитирование не работает для декомпозиции кода. И Бу не имеет паттерн-матчинга (хотя что-то там вроде как пытались изобразить на макросах). Отсюда и такая разница.

Надеюсь этот пример четко демонстрирует какой из языков читабленьнее?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: Круто, но до чего же тяжелый синтаксис
От: Аноним  
Дата: 14.05.11 19:23
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Надеюсь этот пример четко демонстрирует какой из языков читабленьнее?

Если честно, шарпо-питоновый синтаксис ближе, но безусловно в немерле есть приятные вещи.

Вот думаю, на чём бы потренироваться.
Глядя на то, что парсер шарпа таки работает ( ) возникла такая идея — соорудить веб навигатор по коду шарпа.
Был такой проект — LXR (причем гляжу еще даже поддерживается).
Он индексирует код и позволяет осуществлять через веб осуществлять поиск как по идентификаторам так и полнотекстовый, плюс интегрируется с системой контроля версий. Вот подумалось может прибавить системе мозгов по первому пункту, т.е. сделать полноценные операции Find References и Go to definition для веб интерфейса с учетом контекста идентификаторов. С развитием ИДЕ надобность в подобном конечно почти пропала, но для just for fun сойдет.

В первом приближении надо распарсить код и для каждого идентификатора (с учетом контекста) сохранить места объявления и использования в базу. В принципе, насколько я понял парсер шарпа можно и из шарпа дергать, но раз уж на то пошло пусть будет немерле. Пробежаться по готовому АСТ и собрать идентификаторы не должна быть такая сложная задача. Как думаешь архитектура парсера такое?
Re: Круто, но до чего же тяжелый синтаксис
От: catbert  
Дата: 14.05.11 20:03
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Не сочтите за троллинг. Решил таки сразиться с фобиями и расширить горизонты познания, но видимо с "N" не срастется у меня — наверное я недостаточно "функционален".

А>Сравните например Nemerle &mdash; Late.n и Boo &mdash; PropertyMacro.boo.

Сравнил. Мне кажется, данный макрос очень упрощенный. Его на Немерле можно написать компактней и элегантней. Макросы стандартной библиотеки Немерле сложнее и универсальней (например, стандартный макрос Accessor в Немерле может создавать статические, приватные, гет-онли свойства и так далее).

Кроме того пример на Boo демонстрирует довольно простой макрос аксесора. Макрос late, с другой стороны, выполняет функцию посложнее.

Я приведу в пример свой макрос EventAccessor, который тоже генерирует свойство, но с событием, которое запускается при изменении значения свойства.

В нем (как и в приведенном примере на Boo) нету контроля видимости и других атрибутов свойства. Я их убрал для того, чтобы сделать условия сравнения равными.


//@nbuild:project.nbp

using System.Text

using Nemerle.Compiler
using Nemerle.Compiler.Parsetree


namespace Ukma.Macros

        // этот атрибут необходим для Немерле 1, ведь у него есть несколько видов макросов, несколько стадий раскрытия и так далее
    [Nemerle.MacroUsage (Nemerle.MacroPhase.BeforeInheritance,
                       Nemerle.MacroTargets.Field,
                       Inherited = false, AllowMultiple = true)] \
    macro EventAccessor (current_type : TypeBuilder, storage_field : ParsedField, params args : list [PExpr])


        def (name, flags) =
            match (args) 
                | [ <[ $n ]>, <[ $("flags" : dyn) = $opts ]> ] => // матч, списки и квазицитаты требуют
                                                                                  // некого понимания, но очень удобны
                    (Some (n), Some (opts))
                | [ <[ $("flags" : dyn) = $opts ]> ] => 
                    (None (), Some (opts))
                | [ <[ $n ]> ] => 
                    (Some (n), None ())
                | [] => 
                    (None (), None ())
                | _ => 
                    Message.FatalError ("usage: EventAccessor (name, flags = SOMEFLAGS), "
                                      "where both name and flags are optional")
        

        // __some_foo__bar ==> SomeFooBar; заметьте, что я не создаю отдельный класс для вспомогательных методов
        def transformed_name = 
            def sb = StringBuilder ()
            mutable next_upper = true
            foreach (ch in storage_field.Name)
                if (ch == '_')
                    next_upper = true
                else if (next_upper)
                    _ = sb.Append (char.ToUpper (ch))
                    next_upper = false
                else
                    _ = sb.Append (ch)
            sb.ToString ()

        
        def name = name.WithDefault (transformed_name)
        def want_static = storage_field.Attributes %&& NemerleAttributes.Static

        
        def fieldref = <[ $(storage_field.PName : name) ]>

        def eventName = name + "Changed"
        def onEventName = "On" + eventName
        
        def evnt = // ха-ха, попробуйте так в Boo :-)
                <[ decl:
                  public event $(eventName : dyn) : System.EventHandler;
                ]>
        def sender = <[ this ]>
        def onEvent = 
                <[ decl:                
                  protected virtual $(onEventName : dyn)() : void
                  {
                    def x = $(eventName : dyn);
                    when (x != null) x($sender, System.EventArgs.Empty);
                  }
                ]>
        
        def prop = 
                <[ decl:
                  public $(name : dyn) : $(storage_field.ty)
                  {
                    set 
                        { 
                            when ($fieldref != value) 
                            {
                                $fieldref = value; 
                                $(onEventName : dyn)();
                            }
                        }
                    get { $fieldref }
                  }
                ]>
                  
                
        storage_field.Attributes |= NemerleAttributes.Mutable
                  
        // код установки других атрибутов удален
        
        current_type.Define (evnt)
        current_type.Define (onEvent)
        current_type.Define (prop)



Мне кажется, что этот код совсем не уступает в читабельности приведенному вами примеру. Он проще, хоть и делает больше. И его намного приятнее писать, поскольку каждая строчка кода полезна, нету рутины создания вспомогательных классов, методов и так далее.

Если честно, многие части кода компилятора/библиотеки Немерле — вещь не для слабонервных Поэтому мы хотим его хорошенько отрефакторить во второй версии компилятора. Учите язык и помогайте, если хотите!
Re[3]: Круто, но до чего же тяжелый синтаксис
От: Аноним  
Дата: 14.05.11 20:08
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Глядя на то, что парсер шарпа таки работает ( ) возникла такая идея — соорудить веб навигатор по коду шарпа.

А>Был такой проект — LXR (причем гляжу еще даже поддерживается).
С другой стороны, как-то муторно всю эту перловую байду под виндой разводить. Придется обратиться к более возвышенным материям типа парсера калькулятора
Re[2]: Круто, но до чего же тяжелый синтаксис
От: Аноним  
Дата: 14.05.11 20:20
Оценка:
C>Здравствуйте, Аноним, Вы писали:

C>
C>    macro EventAccessor (current_type : TypeBuilder, storage_field : ParsedField, params args : list [PExpr])
C>        def (name, flags) =
C>            match (args) 
C>                | [ <[ $n ]>, <[ $("flags" : dyn) = $opts ]> ] => // матч, списки и квазицитаты требуют
C>                                                                                  // некого понимания, но очень удобны
C>                    (Some (n), Some (opts))
C>                | [ <[ $("flags" : dyn) = $opts ]> ] => 
C>                    (None (), Some (opts))
C>                | [ <[ $n ]> ] => 
C>                    (Some (n), None ())
C>                | [] => 
C>                    (None (), None ())
C>                | _ => 
C>                    Message.FatalError ("usage: EventAccessor (name, flags = SOMEFLAGS), "
C>                                      "where both name and flags are optional")
C>


C>Мне кажется, что этот код совсем не уступает в читабельности приведенному вами примеру. Он проще, хоть и делает больше. И его намного приятнее писать, поскольку каждая строчка кода полезна, нету рутины создания вспомогательных классов, методов и так далее.

Писать может быть и приятнее, но вот читать... например никак не могу сообразить при каких входных данных будет выдаваться FatalError

C>Учите язык и помогайте, если хотите!

Конечно поковыряю еще, но человечность как в том же Бу не помешала бы
Re[3]: Круто, но до чего же тяжелый синтаксис
От: hardcase Пират http://nemerle.org
Дата: 14.05.11 21:11
Оценка:
Здравствуйте, Аноним, Вы писали:

C>>Здравствуйте, Аноним, Вы писали:


C>>
C>>    macro EventAccessor (current_type : TypeBuilder, storage_field : ParsedField, params args : list [PExpr])
C>>        def (name, flags) =
C>>            match (args) 
C>>                | [ <[ $n ]>, <[ $("flags" : dyn) = $opts ]> ] => // матч, списки и квазицитаты требуют
C>>                                                                                  // некого понимания, но очень удобны
C>>                    (Some (n), Some (opts))
C>>                | [ <[ $("flags" : dyn) = $opts ]> ] => 
C>>                    (None (), Some (opts))
C>>                | [ <[ $n ]> ] => 
C>>                    (Some (n), None ())
C>>                | [] => 
C>>                    (None (), None ())
C>>                | _ => 
C>>                    Message.FatalError ("usage: EventAccessor (name, flags = SOMEFLAGS), "
C>>                                      "where both name and flags are optional")
C>>


C>>Мне кажется, что этот код совсем не уступает в читабельности приведенному вами примеру. Он проще, хоть и делает больше. И его намного приятнее писать, поскольку каждая строчка кода полезна, нету рутины создания вспомогательных классов, методов и так далее.

А>Писать может быть и приятнее, но вот читать... например никак не могу сообразить при каких входных данных будет выдаваться FatalError

Читать тоже приятно.... но только когда написано нормально. Приведенный кусок кода следует тформатировать:
def (name, flags) = match (args) 
{
    | [ name, <[ $("flags" : dyn) = $opts ]> ] => (Some(name), Some(opts))
    | [       <[ $("flags" : dyn) = $opts ]> ] => (None (),    Some(opts))
    | [ name ]                                 => (Some(name), None())
    | []                                       => (None(),     None())
    | _ => Message.FatalError("usage: EventAccessor (name, flags = SOMEFLAGS), "
                          "where both name and flags are optional")
};
/* иЗвиНите зА неРовнЫй поЧерК */
Re[4]: Круто, но до чего же тяжелый синтаксис
От: catbert  
Дата: 14.05.11 21:18
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, Аноним, Вы писали:


А>>Глядя на то, что парсер шарпа таки работает ( ) возникла такая идея — соорудить веб навигатор по коду шарпа.

А>>Был такой проект — LXR (причем гляжу еще даже поддерживается).
А>С другой стороны, как-то муторно всю эту перловую байду под виндой разводить. Придется обратиться к более возвышенным материям типа парсера калькулятора

Я не уверен, что в вашей ситуации LXR нужен. Просто соскребайте с AST все идентификаторы в таблицу, а таблицу сериализируйте/десериализируйте по мере надобности. Если проекты небольшие, все пройдет ок.
Re[3]: Круто, но до чего же тяжелый синтаксис
От: catbert  
Дата: 14.05.11 21:24
Оценка:
Здравствуйте, Аноним, Вы писали:

C>>Здравствуйте, Аноним, Вы писали:


А>Конечно поковыряю еще, но человечность как в том же Бу не помешала бы


Мне кажется, тут уже не столько человечность языка важна, сколько человечность автора. Этот кусок можно было бы переписать вместо матча на if...else, и тогда было бы ясно когда вызывается FatalError. Но я решил написать более коротко. Это мой выбор, так сказать

Чтобы прочитать этот код вам придется знать значения разных образцов. Образец "_" означает "все остальное". То есть если args — не
1) список из идентификатора и выражения flags = ....
2) выражение flags = ....
3) идентификатор
4) пустой список,

то вызывается FatalError.
Re[3]: Круто, но до чего же тяжелый синтаксис
От: VladD2 Российская Империя www.nemerle.org
Дата: 15.05.11 01:15
Оценка:
Здравствуйте, Аноним, Вы писали:

C>>Учите язык и помогайте, если хотите!

А>Конечно поковыряю еще, но человечность как в том же Бу не помешала бы

Это не человечность, а убогость.

Просто прочти статью где описывается паттерн-матчинг и напиши что-то с его использованием. Сразу поймешь его мощь.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: Круто, но до чего же тяжелый синтаксис
От: VladD2 Российская Империя www.nemerle.org
Дата: 15.05.11 01:31
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, VladD2, Вы писали:


VD>>Надеюсь этот пример четко демонстрирует какой из языков читабленьнее?

А>Если честно, шарпо-питоновый синтаксис ближе, но безусловно в немерле есть приятные вещи.

Это что за такой новый синтаксис? У Шарпа синтаксис свой. У Питона — свой. У Бу — свой. Бушный синтаксис ближе к питону, но никак ни к шарпу.

Немерловый синтаксис значительно ближе к синтаксису Шарпа нежели Бушный.

То что ты назваешь синтаксисом синтаксисом не является. На Немреле точно так же можно лезть к объектам и на if-ах разбираться со значениями их свойств и полей. Но это, в более менее сложных случаях, оказывается намного сложнее нежели воспользоваться паттерн-матчнигом (ПМ).

Проблема твоего непонимания — это проблема непонимания ПМ. Разберись с ПМ и поймешь, что код с ПМ не только более понятный, но и еще в разы более простой.

А>Вот думаю, на чём бы потренироваться.

А>Глядя на то, что парсер шарпа таки работает ( ) возникла такая идея — соорудить веб навигатор по коду шарпа.
А>Был такой проект — LXR (причем гляжу еще даже поддерживается).
А>Он индексирует код и позволяет осуществлять через веб осуществлять поиск как по идентификаторам так и полнотекстовый, плюс интегрируется с системой контроля версий. Вот подумалось может прибавить системе мозгов по первому пункту, т.е. сделать полноценные операции Find References и Go to definition для веб интерфейса с учетом контекста идентификаторов. С развитием ИДЕ надобность в подобном конечно почти пропала, но для just for fun сойдет.

Это перебор. Возьми более простую задачку. В прочем, был бы интерес, конечно же.


А>В первом приближении надо распарсить код и для каждого идентификатора (с учетом контекста) сохранить места объявления и использования в базу. В принципе, насколько я понял парсер шарпа можно и из шарпа дергать, но раз уж на то пошло пусть будет немерле. Пробежаться по готовому АСТ и собрать идентификаторы не должна быть такая сложная задача. Как думаешь архитектура парсера такое?


Вопрос какова цель. Если задача сделать максимально мощное решение за короткий промежуток времени, то проще воспользоваться движком компилятора немерла. Он не только изначально доступен как компонент (Compiler as service — CaS), но и позволяет разбирать код для последующего анализа. Поддержка IDE основана именно на этом.

Если же цель изучить возможности языка, то это идея может быть и не плохая. Но я бы для начала реализовал бы что-то по проще.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: Круто, но до чего же тяжелый синтаксис
От: VladD2 Российская Империя www.nemerle.org
Дата: 15.05.11 01:39
Оценка:
Здравствуйте, Аноним, Вы писали:

А>>Глядя на то, что парсер шарпа таки работает ( ) возникла такая идея — соорудить веб навигатор по коду шарпа.

А>>Был такой проект — LXR (причем гляжу еще даже поддерживается).
А>С другой стороны, как-то муторно всю эту перловую байду под виндой разводить. Придется обратиться к более возвышенным материям типа парсера калькулятора

"Перловая байда" для целей этой задачи не особо нужна. Но идея начать с примерчика по меньше — более здравая идея. Надо освоить базовые концепции и уже потом приступить к задаче по сложнее.

Для начала лучше просто прочесть эту статью
Автор(ы): Сергей Туленцев, Владислав Чистяков
Дата: 23.05.2006
Производительность труда программиста в основном зависит от самого программиста. Однако даже самый опытный и знающий программист мало что может без подходящего инструмента. Эта статья открывает цикл статей об одном из таких инструментов, еще мало известном среди программистов, но очень многообещающем. Язык Nemerle, о котором пойдет речь в этих статьях, на первый взгляд очень похож на слегка улучшенный C#, но привносит многое из передовых исследовательских языков. Данная статья рассказывает об отличиях Nemerle от C# (как наиболее близкого языка)и является неформальным введением в язык.
или эти три и просто поиграться с примерами. Создать новые проекты в студии, воспроизвести примеры, по изменять их и посмотреть что получится.

Ну, а там уже взяться за реальную задачу.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: Круто, но до чего же тяжелый синтаксис
От: _nn_ www.nemerleweb.com
Дата: 16.05.11 14:04
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Не сочтите за троллинг. Решил таки сразиться с фобиями и расширить горизонты познания, но видимо с "N" не срастется у меня — наверное я недостаточно "функционален".

А>Сравните например Nemerle &mdash; Late.n и Boo &mdash; PropertyMacro.boo. Я честно скажу, что сейчас толком не понимаю происходящее ни в том ни в другом случае, но в Boo хотя бы можно поразбираться — вполне читаемый код для любого знакомого с шарпом. От кода немерля же начинают болеть глаза на 15 секунде. Тут конечно будет контраргумент, что макросы Бу и макросами то назвать нельзя по сравнению с Н, но хотя бы для основных сценариев использования подумайте над упрощенным читаемым синтаксисом.

А>ЗЫ Несмотря ни на что поздравляю с релизом! Понимаю что труд титанический, надеюсь на дальнейшее развитие языка.


Насчет отступов:
http://rsdn.ru/forum/nemerle/4040612.1.aspx
Автор:
Дата: 16.11.10


Не всем нравятся отступы, не всем нравятся скобки. Всем не угодишь.
Так уж вышло, что в Nemerle есть 2 синтаксиса, при чем скобочный он оригинальный и поэтому лучше поддерживается.

Я не вижу в обозримом будущем переход на отступы, разве что все захотят.
Имейте ввиду, на сегодня со скобочным синтаксисом студия работает хуже чем с отступами.
http://rsdn.nemerleweb.com
http://nemerleweb.com
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.