Pull to refresh

Comments 24

скажите, а именование переменных в виде одной или малого количества символов — это характеристика языка или просто привычка? я серьезно спрашиваю, без сарказма, интересно
Если переменная встречается всего на двух строчках, то зачем ей длинное имя?
характеристикой это назвать сложно, скорее (насколько я успел заметить) некоторая негласная договоренность программистов. Максимально полно именуются только верхнеуровневые функции. Может быть это подсознательная мысль: «ФП-код должен быть коротким» покоя не дает? :)
Переменные в лямбдах вообще обычно одним или двумя символами обозначают. Ну собственно, так же как и for (int i = 0… )
лямбды и итераторы цикла — это понятно
но в вышеприведенном коде такой подход — везде, я про это и спросил, поскольку с языком практически не знаком, а пытаться разобраться на сплошных r, t, e, l — просто не могу
ммм, наверно вы правы, сейчас попробую подправить.
вообще h, t — это обычно head и tail, r, l — right и left
так значительно лучше (на мой вкус) :)
спасибо
Сорри за оффтоп, но очень не нравится когда 15 мин времени тратишь на чтение непонятных букв. Каково Вам будет читать текст, где слова сокращены до букв?
Клево. Тема теорката вообще интересна. :) (правда, я его не осиливаю)

Нельзя ли как-нибудь убрать побочные эффекты из Printer? (Пусть возвращает строку, которую затем можно будет вывести куда угодно.) Наверняка там (в F#) есть какой-нибудь «монадический катаморфизм» + монада Writer.

> P.S. Не знаю, стоит ли переносить в какой-то коллективный блог, все-таки тема специфическая.

Ну конечно стоит. Катаморфизм полезен же!

Следующая статья, наверное, будет о zipper'ах? :) Тоже очень полезная штука.
Да что-то я не думаю, что многим понравится.
— Нельзя ли как-нибудь убрать побочные эффекты из Printer? (Пусть возвращает строку, которую затем можно будет вывести куда угодно.)
— Она ровно это и делает — функция sprintf — это и есть «печать в строку», так что функция Printer имеет тип Expr -> string :)
> Да что-то я не думаю, что многим понравится.

А о чем еще писать? Очередное «я вот напейсал вот такой быдлокод, зацените результаты воздействия синдрома туннельного зрения»? (конечно, не все статьи на хабре такие, но много.)

/me ушел негодовать.

> Она ровно это и делает — функция sprintf — это и есть «печать в строку», так что функция Printer имеет тип Expr -> string :)

Млин, я уже путаю printf и sprintf! O_O
Насчет суммирования элементов списка — а что если написать так:

myList |> Seq.of_list |> Seq.reduce (fun x y -> x + y)
ну подобных вариантов море, никто спорит :)
к слову, отличие reduce от fold лично меня немного смущает. только то, что в reduce тип аккумулятора должен совпадать с типом элемента коллекции?
И reduce не принимает пустые списки. Он не катаморфизм в этом плане :)
Потому что стартовый элемент берётся из коллекции.
Что-то у меня противоречивые чувства по поводу поголовного переписывания рекурсии в CPS. Мы размениваем стек на выделение памяти в куче, причём сборщик мусора не может подобрать ни одно замыкание до завершения всей функции. Понятно, что CLR больнее бьёт по рукам за переполнение стека, но CPS-преобразование зачастую работает как обфускатор.
Спасибо за статью, надо сделать ещё один набег на бананы с колючей проволокой.
> Что-то у меня противоречивые чувства по поводу поголовного переписывания рекурсии в CPS.

AFAIK компиляторы многих функциональных языков так и поступают. Так можно легко получить call/cc, например.
В компиляторе — на здоровье, но меньше всего охота в ФЯ делать работу компилятора руками :-)
Спасибо, хорошая статья. Узнал что-то новое.

Но думаю, что стоит добавить при переходе от левосторонней свертке к правосторонней, что мы все равно и по любому теряем в памяти: fold_left бежит по списку и применяет функцию, а fold_right бежит по списку, запоминает его, а затем бежит обратно и применяет функцию. Просто в первом случае он запоминает его в стеке, а во втором в куче, но порядок расхода памяти одинаковый — чуда нет. При работе с деревом так же создается его копия.
вы правы конечно.
что ж, чудеса в нашем мире случаются нечасто :)
В отличие от энергичного F# в ленивом Haskell благодаря deforestation связка генератор — map/filter — foldr может даже не порождать списки. И, разумеется, foldr не бежит по списку, запоминая его. В этом нет никакой необходимости — достаточно вспомнить, что foldr просто заменяет (::) на операцию, а [] на стартовый элемент. Если операция ленива (не +), то foldr очень даже выручает.
Sign up to leave a comment.

Articles