Обновить
59

Пользователь

22
Подписчики
Отправить сообщение
Кому нужна лишняя связность там, где её может не быть?
Haskell сам вместо map f. map g делает map (f. g)
Можно вообще задавать свои правила оптимизации, язык-то чистый и есть гарантии отсутствия побочных эффектов :)
А разве этот map не пробежится по всему списку? А затем filter не пробежится ещё раз?
Тогда как в ленивом будет всего один проход.
Итераторы нужны не для усложнения, а для разделения алгоритмов.
Куда как проще и понятнее написать:
filterData = filter somePredicate
translateData = map someOp
И затем
filterData. translateData $ data
и всё это выльется в один цикл.

Нежели
for (… )
{
if (somePredicate(*b))
result.push_back(someOp(*b))
}

Так как в первом случае код разнесён в разные места (а что если эти обработки пишут разные люди?), а во втором — всё намешано в кучу.
Мы, конечно, во втором случае тоже можем разнести в разные места, но тогда в энергичном языке у нас получится 2 цикла, а не один. А если обработок будет больше, чем 2? То и циклов будет сотня. Вот и придумывают всякие yield'ы, и отнюдь не ради забавы.
В неленивых языках поэтому куча абстракций типа итератор и енумератор. Так что на деле не всё так просто.
Если бы всё было так просто, не было бы таких понятий, как итератор.
Никто этого не говорил.
Дабы было проще понять:
head $ sort lst
Выдаст минимальный элемент.
Сравните, во что это выльется ленивому и энергичному языку?
Ну дак его ж не надо досортировывать до конца.
Спасибо за статью.

Ссылочная прозрачность же, а не мемоизация?

Было бы интересно ещё про Fusion (как несколько map/filter/… выливаются в один цикл). Это, так сказать, обратный случай, где в обычных языках мы платим, а в ленивом — нет, за счёт высокой абстракции.
Есть мнение (далеко не только моё), что FP в D добавлено на редкость неудачно.
Не в каком-то, а во всех. Со стороны влияния не психику могу напомнить белую горячку.
Пропатчил стандартный HsColour, чтобы можно было указывать произвольные цвета в файле конфигурации (а не только 16 стандартных), им и пользуюсь.

Я лично пишу новую монаду тогда, когда она может значительно сократить код, как, например, тут
В статье, правда, не видно сравнения того, что было (а были вызовы с передачей лямбды, внутри которой были такие же вызовы с передачей новых лямбд, выглядело это как большая развесистая лестница) с тем, что стало (фактически простой линейный код).
По поводу второго варианта. У вас получается тип IO (IO ())
Т.е. test2 ничего не печатает, он возвращает монадное действие, которое уже печатает. Чтобы реально напечатать надо сделать так:
do
    action <- test2
    action

Или проще:
join test2

Не совсем понял, что значит «на стандартных функциях»? Klesli же стандартные.
Если интересует, как они внутри устроены, то код здесь. Внутри там есть bind, конечно.
Стрелки не для того, чтоб не использовать bind, про них имеет смысл почитать отдельно :)
Можно ещё упомянуть, что
a -- [IO] -> b
это стрелки Клейсли, и используя их, можно писать вполне себе:
test :: String -> IO ()
test = runKleisli (Klesli purStrLn . arr (map toUpper) . Kleisli readFile)

Напрягает, правда, необходимость оборачивать функцию.
Таким образом, конечно, можно.
Кстати, если data-accessor сделать инстансом Control.Category, то можно будет писать
(tail.head.second ^= 12) [('x', 125), ('a', 11)]
:)
Так ведь
fmap : (a -> b) -> f a -> f b
обязан работать на любых типах и морфизмах.

В Control.Category есть класс Category, так что должно было быть так:
fmap : g a b -> h (f a) (f b)

Стоит заметить, что в Functor в Haskell — это эндофунктор.

Информация

В рейтинге
Не участвует
Откуда
Россия
Дата рождения
Зарегистрирован
Активность