Pull to refresh
20
0
Юрий Сыровецкий @cblp

говорящий с машинами

Send message

Правильно, лучше переводить деньги через закрытый Свифт. Нет денег — нет проблем с легализацией.

Там что-то про функторы

Да, именно так, через функторы разжёвано. Это ссылка на середину книги, её надо читать с начала.

А можно ничего не читать, можно просто пользоваться монадами как flatMap, большинство программистов так делают. Это менее интересно, но тоже достаточно продуктивно.

А что такое "тип с параметром"?

Тип данных, зависящий от другого типа данных. Например, во статически типизированных языках вектор сам по себе не тип данных, но вектор строк или вектор целых — это тип данных. Значит, вектор — это такая штука, которой нужно дать параметр, чтобы она стала настоящим типом. Мы называем это параметрическим типом.

Если хотите, могу дать примеры на вашем любимом языке. Можем продолжить беседу в личке.

А разве композиция (функций) не лежит в основе самой парадигмы ФП?

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

Есть ещё много других видов композиции для разных видов сущностей.

Чем тогда монады отличаются от других "структур"?

Именно этим и отличается. Монады — это такие "структуры", которые можно связывать, выход одного со входом другого. Ну и там несколько математических требований к этому связыванию. Грубо говоря, оно должно вести себя предсказуемо.

можно ли все грязные побочные действия самому выполнять в виде вызовов сишных примитивов?

В Хаскеле по умолчанию нет примитивов, есть только много разных IO-операций в стандартной библиотеке.

Как тогда самому определить, какое действие является побочным? Можно ли по формальным признакам отделить монаду от чистого типа, например, от типа Int -> Int?

Да, это строгий термин с формальными признаками. Они хорошо описаны в документации и разжёваны в учебниках вроде этого.

Грубо говоря, это должен быть тип с параметром, должна быть функция для связывания, и связывание должно вести себя предсказуемо, по правилам.

Интересно, что тип чистой функции вроде Int -> Int (точнее, Int -> a) с формальной точки зрения тоже будет монадой, но это математический трюк, это знание не особо часто может пригодиться в работе.

А читать QR из файла всё так же неудобно без второго телефона.

Или взять вот такую штуку (по мотивам библиотеки wreq):

get :: String -> IO Response

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

Можно ровно то же самое сказать иными словами: это операция ввода-вывода (сходить в сеть и принести ответ), параметризованная строкой (урлом). Тоже формально.

Неформально на эту функцию с операцией можно посмотреть как на «функцию, обогащённую вводом-выводом», у которой на входе строка (урл), на выходе ответ (от сервера), а в побочных эффектах операции ввода-вывода (хождение по сети и возможное исключение, если не удастся достучаться до сервера).

Здесь тип IO — монада, потому что можно операции соединять между собой, например,

getOncePutTwice =
  getLine >>=
    (\s ->
      putStr s >> putStr s)

при этом при соединении не производится ввод или вывод, а только вычисляется новая операция.

Принцип монад — это способ композиции.

А сами монады — это типы, объекты которых можно монадически соединять.

Например, в Хаскеле есть объект getLine :: IO String, кодирующий ввод строки из потока ввода. Это операция ввода-вывода, как можно предположить по типу IO. Изнутри языка нельзя посмотреть, что там внутри (если интересно, внутри там вызов сишных примитивов, но это не важно). Но можно передать эту операцию на исполнение вместе с какой-то функцией-продолжением, операция исполнится, и в вашу функцию придёт строка из потока ввода.

Или вот есть функция putStr :: String -> IO (), она сама ничего не печатает, она только по строке вычисляет операцию вывода. Эту операцию можно исполнить или передать кому-то, кто умеет принимать операции ввода-вывода.

А "объекты-загончики" - это монады?

Нет. Монадой может быть тип такого объекта (например, Writer). А может и не быть (например, ввод-вывод в старом Хаскеле был просто списком действий).

К чему именно относится второй вопрос, я не понял. Переформулируйте, пожалуйста.

Если возникает partition, вы не можете взаимодейстовать с системой (в основном случае)

Таким образом, система не может продолжать работу в случае partition, но обеспечивает strong consistency и availability. Это система CA!

Вот тут противоречие. Какая же это доступность, если взаимодействовать нельзя?

А дело в том, что для availability достаточно локального взаимодействия, и локально с системой взаимодействовать можно!
Функциональное программирование требует отсутствия побочных эффектов (side effects)… побочные эффекты это то, ради чего мы программируем.

Вы, конечно, правы, но на самом деле всё наоборот.

Это популярное заблуждение, что в чистых языках или в ФП нет побочных эффектов.

В «грязных» языках побочные эффекты разрешены в любом месте и ими нельзя управлять. В чистых языках побочные эффекты живут только в специальных объектах-загончиках, только там, где они нужны, и ими можно управлять.
Большинство опытных хаскелистов получились как раз на таких местах, где надо совмещать г и Хаскель.
Если посмотреть на динамическую типизацию с точки зрения статической, можно считать все динамические типы одним статическим. Так что противоречия нет, можно внутри статически типизированной программы иметь динамический код.
2 классических:
CvRDT = полурешётка,
CmRDT — лог операций.

Потом ещё придумали Mergeable, Delta-state, и вот этот RON в статье можно считать отдельным видом CRDT.
В RON конфликты избегаются так же, как и в остальных CRDT — конфликтов просто нет.

Шучу, это непросто. Суть бесконфликтности в том, чтобы разрешить только такие операции, которые не вызывают конфликтов (при доставке в произвольном порядке). Придумывать такие структуры тяжело. Зато их можно легко комбинировать, вкладывать друг в друга, объединять в структуры.
Насколько я понял, CRDT — это тип-полурешетка.

Полурешётка — один из видов CRDT, есть и другие.

Можно ли рассматривать сам репозиторий (только не git, а какой-нибудь патчевой СКВ, где конфликтное состояние является возможным состоянием) как CRDT относительно операции pull/push?

Гит можно, но только относительно fetch и fast-forward.
Функторы в C++ являются сокращением от «функциональные объекты».
Что-то я не вижу, как тут сокращение получилось.

Насколько я помню, всё было немного иначе.

До С++ функторы появились в С, и там это было сокращение-гармошка (portmanteau) от «FUNCtion poinTER» (с поправкой на e/o, но это хотя бы какой-то смысл имеет, в отличие от «object»). Потом в С++ это понятие расширили на любое значение, которое можно вызывать как функцию.
Но ведь в статике бойлерплэйта, как правило, меньше. Можно одновременно получить и безопасность, и читаемость.
Всё отлично читается и по кусочкам. Я думаю, вы привыкли к Алгол-С-подобному синтаксису, а к ISWYM-подобному ещё не привыкли. Если поработаете с Хаскелем некоторое время, научитесь и ему.
1
23 ...

Information

Rating
Does not participate
Location
Москва, Москва и Московская обл., Россия
Date of birth
Registered
Activity