Re[4]: Может лучше создать макрос "find"?
От: VladD2 Российская Империя www.nemerle.org
Дата: 28.07.10 14:13
Оценка:
Здравствуйте, hardcase, Вы писали:

H>Тогда не слишком понятно зачем нужен таковой макрос. Слишком уж задача специфическая мне кажется...


Задача постоянно встречающаяся. А смысл в том, чтобы решать ее проще и с меньшим количеством кода.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: Может лучше создать макрос "find"?
От: SergASh  
Дата: 29.07.10 07:33
Оценка:
Здравствуйте, VladD2, Вы писали:

SAS>>Но если notfound указан, то option будет только мешать. Кажется логичным отдавать option[T] в первом случае и T во втором.


VD>Мне кажется, что option[T] лишний. Если нужна обработка, то проще просто не указывать notfound и сделать нужные действия в теле find.


Для императивного стиля сойдет, но для функционального не очень. Получается, что как выражение в целом find без notfound может иметь только тип void. Это слишком ограничительно для такого полезного макроса. Да и подставить непосредственно в вызов функции такой find не получится. В общем, option напрашивается для find без notfound.
Re[6]: Может лучше создать макрос "find"?
От: VladD2 Российская Империя www.nemerle.org
Дата: 29.07.10 18:43
Оценка:
Здравствуйте, SergASh, Вы писали:

SAS>Для императивного стиля сойдет, но для функционального не очень. Получается, что как выражение в целом find без notfound может иметь только тип void. Это слишком ограничительно для такого полезного макроса. Да и подставить непосредственно в вызов функции такой find не получится. В общем, option напрашивается для find без notfound.


Меня как-то не зацепила пропаганда функционального стиля. Что удобнее делать функционально, то конечно лучше делать функционально. Но это не панацея. Если мы ищем что-то чтобы потом произвести какие-то действия, то что нам озираться на ФП? Ведь действия — это и есть императив!

По сути у нас есть три реакции на результат поиска:
1. Мы что-то делаем с найденным значением — эмпиратив.
2. Мы возвращаем найденное значение или какое-то другое.
3. Мы заворачиваем результат поиска в структуру данных и разберемся с реальным результатом в другом месте.

Четвертого не дано!

Так вот у нас уже есть функциональная функция Find которая предоставляет решение 3. Мы можем использовать оператор ?? для отработки второго сценария. И мы вынуждены городить кучу кода когда нам нужен первый сценарий.

Если бы у нас был макрос find, то мы так же могли предоставить все три сценария. Первый — требует от нас просто не указывать notfound. Второй — возвратить в notfound нужное значение используемое в качестве значения по умолчанию. Третий — вернуть значение завернутое в Some (или nullable) из тела find и None (или null) в секции notfound.

По моему опыту чаще приходится использовать поиск для выполнения неких императивных действий, так как в противном случае проще пользоваться Filter или еще чем-то.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[9]: Может лучше создать макрос "find"?
От: catbert  
Дата: 12.08.10 18:57
Оценка:
Здравствуйте, VladD2, Вы писали:

C>>Вот именно это можно сделать в макросе linq.


VD>В одном слове — нельзя.


Жаль.

C>>Нет, они встроенные. Потому что option — не коллекция.


Тут я лоханулся. Но ума не приложу, почему так решили сделать.

C>>Лямбды должны инлайнится


VD>Это очень не просто, особенно если функция в которую они передаются является библиотечной. Ведь для инлайнинга лябд нужно инлайнить и фукнцию которая их получает. Плюс при инлайнинге возникает очень много вопросов. Ведь язык императивный (хотя бы на половину). Так что многие предположения могут оказаться неверны.


Это до меня уже дошло

VD>Это и есть мифическая чистота. Макрос вроде foreach, when и т.п. тоже бесполезны, если смотреть на макросы в таком ключе. Однако на практике их используют значительно чаще чем аналогичные функции, так как это проще, быстрее и удобнее. В общем, если макрос решает некоторую проблему лучше чем функция, то он имеет право на жизнь. И на мой взгляд тут макрос find ничем не отличается от макроса foreach, к примеру. И то и другое автоматизация паттерна программирования.


Ну, проблема довольно специфична: найти первый элемент в последовательности и выполнить с ним какое-то действие, а если его в последовальности нету, то выполнить другое. Я могу тут ошибаться, но вряд ли она того уровня распостраненности, чтобы её решать в стандартной библиотеке. К тому же дважды.

VD>>>Мы поддерживаем уже кучу макросов и как-то не испытываем от этого неудобств.

VD>>>Меня больше заботит простота чтения кода и эффективность получаемых программ. Именно это я и имею в виду под словом "оверхэд".

Давайте сравним простоту чтения для существующего реального кода (из macros/assertions.n), и предполагаемой замены:

    def existing =
      NList.Find (ty.LookupMember ("_N_invariant"), fun (x : IMember) {
        x.DeclaringType.Equals (ty) && x is IMethod
      });

    match (existing) {
      | None =>
        def methods = ty.GetMethods (BindingFlags.Public %|
                                     BindingFlags.Instance %|
                                     BindingFlags.DeclaredOnly);
        foreach (m :> MethodBuilder in methods)
        {
          def newBody = Util.locate(m.Body.Location,
            <[ InvariantExpose (this, $(m.Body)) ]>);
          m.Body = newBody;
        }
        ty.Define ( <[ decl:
          public mutable _N_invariant_lock : bool;
        ]> );
        ty.Define ( <[ decl:
          public virtual _N_invariant () : void
          {
            assert ($body, "The class invariant has been violated.")
          }
        ]> );
      | Some (m) =>
        def m = m :> MethodBuilder;
        def newBody = Util.locate(m.Body.Location, <[
          $(m.Body);
          assert ($body, "The class invariant has been violated.");
        ]>);
        m.Body = newBody;
    }


С макросом find:


    find (m : IMember when x.DeclaringType.Equals (ty) && x is IMethod in ty.LookupMember("_N_invariant"))
    {
        def m = m :> MethodBuilder;
        def newBody = Util.locate(m.Body.Location, <[
          $(m.Body);
          assert ($body, "The class invariant has been violated.");
        ]>);
        m.Body = newBody;
    }
    otherwise 
    {
        def methods = ty.GetMethods (BindingFlags.Public %|
                                     BindingFlags.Instance %|
                                     BindingFlags.DeclaredOnly);
        foreach (m :> MethodBuilder in methods)
        {
          def newBody = Util.locate(m.Body.Location,
            <[ InvariantExpose (this, $(m.Body)) ]>);
          m.Body = newBody;
        }
        ty.Define ( <[ decl:
          public mutable _N_invariant_lock : bool;
        ]> );
        ty.Define ( <[ decl:
          public virtual _N_invariant () : void
          {
            assert ($body, "The class invariant has been violated.")
          }
        ]> );
    }


Тут улучшение читаемости практически незаметно (на мой взгляд). Единственный плюс — более быстрый код. Но для более быстрого кода можна и цикл foreach написать.

В общем, я понимаю ситуацию так. У программиста Nemerle есть два подхода к выполнению некоторой задачи: императивный и функциональный-декларативный. Императивный неудобный (ну и вообще хреновый), а декларативный медленный и плохо поддерживается отладчиком. Макрос find позволяет выполнить задачу, генерируя императивный код, основанный на декларативном синтаксисе.

Если функциональный оверхэд (или разницу в читаемости императивного/декларативного стиля) мы считаем незначительным, тогда этот макрос просто не нужен.

Если find действительно окупается в плане эффективности и читаемости, то возникает вопрос: почему только find? Ведь для остальных операций (те же map, fold, group и т. д.) так же можно написать макросы, которые генерировали бы быстрый код, оставляя синтаксис декларативным. Потому-то я и писал про вариант изменить макрос linq так, чтобы он, где возможно, специализировался для массивов, списков. Тогда у пользователя языка осталось бы три варианта: императивщина, функциональщина и linq, причем linq объединял бы лучшие стороны первых двух вариантов.

А вне общего набора подобных макросов, отдельный find выглядит как-то не очень по-библиотечному.
Re[10]: Может лучше создать макрос "find"?
От: VladD2 Российская Империя www.nemerle.org
Дата: 17.08.10 18:25
Оценка:
Здравствуйте, catbert, Вы писали:

C>Если find действительно окупается в плане эффективности и читаемости, то возникает вопрос: почему только find? Ведь для остальных операций (те же map, fold, group и т. д.) так же можно написать макросы, которые генерировали бы быстрый код, оставляя синтаксис декларативным.


Совершенно резонный вопрос. Группировка операция весма редкая и он и так не плохо реализована в том же линке. А вот для fold и map такой макрос действительно напрашивается. Fold вообще очень мощная вещь но довольно не удобная в использовании. Если разработать для нее удобный синтаксис, можно было бы получить конфетку.

Вообще, fold, map, find и filter — это эдакий костяк ФП с помощью которого можно написать практически любую программу. Можно сказать, что это аналог операторов из императивного программирования. Так сделать для них удобные макрос было бы очень даже полезно. Вопрос только за синтаксисом. Для find я уже предложил вариант который мне нравится. Думаю, что для map и filter ничего лучше чем то что есть сейчас не придумаешь. А вот для fold точно можно придумать что-то лучшее.

C>А вне общего набора подобных макросов, отдельный find выглядит как-то не очень по-библиотечному.


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