Обновить

Комментарии 9

Каждый раз, когда читаю про тру кошерный правоверный ФП, радуюсь, что Джаву и родственный Котлин делают дальновидные люди. Затащили в язык ровно столько ФП, сколько нужно для реальных потребностей. А ведь у Jetbrains явно руки чесались затащить побольше.

Каждый раз, когда читаю про тру кошерный правоверный ФП

То самое тру кошерное правоверное ФП на джаве...

радуюсь, что Джаву и родственный Котлин делают дальновидные люди. Затащили в язык ровно столько ФП, сколько нужно для реальных потребностей. А ведь у Jetbrains явно руки чесались затащить побольше.

ЯП неприспособлен к ФП ->
ФП в нём выглядит плохо ->
"Правильно неприспособили, посмотрите как ФП плохо выглядит"

К слову, посмотрите как-нибудь как выглядит реализация ООП в том же си

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

Примерно так, да. Оно возникло вот почему: берём Haskell, в котором всё иммутабельное, начинаем писать код. Из-за иммутабельности код становится скучным и многословным: любой цикл превращается в рекурсию, и добавить какое-то действие в цикл означает добавление параметров в рекурсивную функцию. Через какое-то время вас достанет писать однообразные рекурсивные перекладывания из списка в список, и вы придумаете fmap. Аналогично с монадами: очень утомляет делать цепочки действий и на каждом шаге выполнять одни и те же вспомогательные операции, научились их прятать. Если у вас нет иммутабельности и есть циклы, то таких проблем не возникает.

Из-за иммутабельности код становится скучным и многословным: любой цикл превращается в рекурсию, и добавить какое-то действие в цикл означает добавление параметров в рекурсивную функцию.

Не понял, зачем? Если у вас всё пока что иммутабельное, то не нужно ничего никуда добавлять. Замыкания, все дела:

addEach :: Int -> [Int] -> [Int]
addEach n = go
  where
  go [] = []
  go (x:xs) = x + n : go xs

Через какое-то время вас достанет писать однообразные рекурсивные перекладывания из списка в список, и вы придумаете fmap.

fmap работает на произвольных функторах, а вот конкретно на списках map был ещё в лиспе в бородатых 60-х, когда хаскеля и в проекте не было (и лисп не то чтобы славится иммутабельностью).

Интересно, зачем в C++ придумали std::transform или std::for_each? Наверное, тоже иммутабельность виновата?

Аналогично с монадами: очень утомляет делать цепочки действий и на каждом шаге выполнять одни и те же вспомогательные операции, научились их прятать.

Какие вспомогательные операции в общем случае для монад?

И почему в те же плюсы добавили монадические операции для std::optional и std::expected? Хаскелисты покусали плюсистов?

Неплохая попытка, очень нравится чувствовать опыт живого человека.

Не очень понял, почему вы назвали Function , List и Optional тайпклассами на основании того, что у них есть generic-параметры. Хаскелевский тайпкласс ближе всего к Java-интерфейсам, поэтому Function - да, тайпкласс, List - тоже, но потому, что у него есть разные реализации (ArrayList, LinkedList), а Optional - вполне себе хаскелевский data .

Лично мне всегда казалось, что проще всего объяснить, какой тип можно считать монадой, через join: например, можно же схлопнуть список списков в плоский список, значит монада, зачем это нужно - другой разговор. Вы вроде тоже зашли через join, но быстро перепрыгнули на bind, ну пусть так.

Может быть через "join" было бы проще. Мне почему-то казалось что bind - это тот основной метод, который используется для реализации монад. Возможно это не так, у меня нет реального опыта в Хаскеле. Плюс в конце хотелось подвести к IO, а там как раз используются binds разных видов

Лично мне всегда казалось, что проще всего объяснить, какой тип можно считать монадой, через join: например, можно же схлопнуть список списков в плоский список, значит монада

Парсер — это монада. Какова операционная семантика схлопывания… парсера парсеров? Парсера, возвращающего парсер? Блин, да это даже не выговоришь.

State s — это монада. Какова операционная семантика схлопывания State s (State s a)?

Вероятности — это монада. Какова операционная семантика схлопывания MonadDistribution m ⇒ m (m a)?

Есть, в конце концов, свободные монады поверх произвольных функторов, data Free f a = Pure a | Roll (f (Free f a)). Схлопнете тут?

Про Cont я и говорить не хочу, это исчадие ада.

Понятно, что это всё можно описать (и кое-что — даже весьма просто, если у вас есть достаточный опыт — скажем, я второй десяток лет развлекаюсь ФП и когда-то занимался статами, поэтому представить себе вероятностное распределение на распределениях и их маргинализацию я вполне могу). Но вы правда считаете, что это всё интуитивнее, чем делать через bind?

join, конечно, является основой, если вы начнёте заниматься теоркатом (потому что там это естественное преобразование T² ⇒ T). Но если вы всё-таки пишете код, то bind ИМХО проще.

И, возвращаясь к вашему соседнему комментарию, как наличие циклов в языке поможет избежать монад в случае парсеров или, скажем, вероятностного программирования?

Лють лютая. Что интересно,там на каждом манипуляции и логические противоерчия лишь, бы натянуть эту сову на глобус.
Интересно,конечно, но зачем?

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации