Входные данные: OCaml-разработчик не может просто заварить чай. Нужно:
- Доказать, что чай существует (
Tea.t)- Проверить exhaustiveness pattern matching'а
- Убедиться, что чай иммутабельный
Functor Brewery: всё должно быть модулями:
module type TEA = sig
type t
val brew : int -> t option
end
module Make (S : SUGAR) : TEA
- 'a tea — полиморфный тип (но в runtime всё равно int)- Сахар опционален (
option), потому что "сахар — это зло"Monadic Layers: прежде чем выдать чай:
- Обернуть в
option (вдруг чайник пустой)- Сделать
bind (потому что монады — наше всё)- Запустить
map (преобразовать bitter в drinkable)Exception Handler: если что-то пошло не так:
-
Match_failure (не учли случай холодной воды)-
Stack_overflow (рекурсивное кипячение)- Или просто вернём
None (и сделаем вид, что так и задумано)Внешние эффекты: IO это боль:
Sys.command "boil_water" (но нужны права sudo)Unix.sleep 3600 (потому что тип int, а не float)Thread.yield() (пока ждём, можно почитать про алгебраические эффекты)Выходной результат: чистая функция вернула:
Some tea (но забыли, что это unit -> tea option)None (потому что "ленивые вычисления")Или вдруг
tea lazy_t (чай обещан, но не заварен)Из рабочих чатов:
"Почему чай холодный? 🤮 Потому что забыли
Lazy.force""Почему в чашке
TypeError? 💩 Sugar.t не совместим с Tea.t""Кто-то использовал
Obj.magic — теперь чай превратился в кофе 🤡""Рекурсивное заваривание:
let rec tea = brew tea in tea 🥶"Тимлид набрасывает на вечер пятницы, AFAIK:
- Блок с
ppx расширениями ([@@deriving brew])- GADT-версию (
type _ tea = Black : string tea | Green : int tea)- Сигнатуру
ASYNC_TEA с Lwt.tОсобые случаи:
let drink = function
| Hot -> "Чай готов!"
| Cold -> failwith "Недопустимое состояние"
(* | _ -> ... *) (* warning: неохватывающий паттерн *)
(1-я серия про java)
(2-я серия про с#)
(3-я серия про django)
