скажите, а именование переменных в виде одной или малого количества символов — это характеристика языка или просто привычка? я серьезно спрашиваю, без сарказма, интересно
характеристикой это назвать сложно, скорее (насколько я успел заметить) некоторая негласная договоренность программистов. Максимально полно именуются только верхнеуровневые функции. Может быть это подсознательная мысль: «ФП-код должен быть коротким» покоя не дает? :)
Переменные в лямбдах вообще обычно одним или двумя символами обозначают. Ну собственно, так же как и for (int i = 0… )
лямбды и итераторы цикла — это понятно
но в вышеприведенном коде такой подход — везде, я про это и спросил, поскольку с языком практически не знаком, а пытаться разобраться на сплошных r, t, e, l — просто не могу
Сорри за оффтоп, но очень не нравится когда 15 мин времени тратишь на чтение непонятных букв. Каково Вам будет читать текст, где слова сокращены до букв?
Клево. Тема теорката вообще интересна. :) (правда, я его не осиливаю)
Нельзя ли как-нибудь убрать побочные эффекты из Printer? (Пусть возвращает строку, которую затем можно будет вывести куда угодно.) Наверняка там (в F#) есть какой-нибудь «монадический катаморфизм» + монада Writer.
> P.S. Не знаю, стоит ли переносить в какой-то коллективный блог, все-таки тема специфическая.
Ну конечно стоит. Катаморфизм полезен же!
Следующая статья, наверное, будет о zipper'ах? :) Тоже очень полезная штука.
Да что-то я не думаю, что многим понравится.
— Нельзя ли как-нибудь убрать побочные эффекты из Printer? (Пусть возвращает строку, которую затем можно будет вывести куда угодно.)
— Она ровно это и делает — функция sprintf — это и есть «печать в строку», так что функция Printer имеет тип Expr -> string :)
А о чем еще писать? Очередное «я вот напейсал вот такой быдлокод, зацените результаты воздействия синдрома туннельного зрения»? (конечно, не все статьи на хабре такие, но много.)
/me ушел негодовать.
> Она ровно это и делает — функция sprintf — это и есть «печать в строку», так что функция Printer имеет тип Expr -> string :)
ну подобных вариантов море, никто спорит :)
к слову, отличие reduce от fold лично меня немного смущает. только то, что в reduce тип аккумулятора должен совпадать с типом элемента коллекции?
Что-то у меня противоречивые чувства по поводу поголовного переписывания рекурсии в CPS. Мы размениваем стек на выделение памяти в куче, причём сборщик мусора не может подобрать ни одно замыкание до завершения всей функции. Понятно, что CLR больнее бьёт по рукам за переполнение стека, но CPS-преобразование зачастую работает как обфускатор.
Спасибо за статью, надо сделать ещё один набег на бананы с колючей проволокой.
Но думаю, что стоит добавить при переходе от левосторонней свертке к правосторонней, что мы все равно и по любому теряем в памяти: fold_left бежит по списку и применяет функцию, а fold_right бежит по списку, запоминает его, а затем бежит обратно и применяет функцию. Просто в первом случае он запоминает его в стеке, а во втором в куче, но порядок расхода памяти одинаковый — чуда нет. При работе с деревом так же создается его копия.
В отличие от энергичного F# в ленивом Haskell благодаря deforestation связка генератор — map/filter — foldr может даже не порождать списки. И, разумеется, foldr не бежит по списку, запоминая его. В этом нет никакой необходимости — достаточно вспомнить, что foldr просто заменяет (::) на операцию, а [] на стартовый элемент. Если операция ленива (не +), то foldr очень даже выручает.
Катаморфизм в F#