c 45:00 примерно

https://disk.yandex.ru/d/DUDkZ_UqdSBznQ/ФП5.mp4

<aside> 💡 Монада - это паттерн проектирования, который позволяет контролировать побочные эффекты. Она предоставляет абстракцию эффектов, и позволяет быть уверенными в том, что эффекты происходят в контролируемом порядке.

</aside>

<aside> 💡 Аппликатив - (насколько я понял) это паттерн проектирования, который позволяет реализовать применение функции к значению. Они не позволяют учесть порядок вычисления нескольких функций, т.к. результаты вычислений полностью независимы. Аппликатив является функтором, т.к. является модулем, который реализуется на основе модуля монады.(Последнее не стоит говорить Дмитрию Сергеевичу, это скорее то, как я понял).

</aside>

>>= - абстракция последовательного исполнения - исп. в монадах

<*> - абстрагированное применение - исп. в аппликативах

Аппликатив требует наличия в сигнатуре двух функций:

  1. apply (<*>)

  2. pure (retur)

Любая монада является аппликативом.

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

Используя монаду можно реализовать аппликатив, через bind.

module ApplicativeOfMonad (M : MONAD) : APPLICATIVE with type 'a t = 'a M.t = struct
  include M

  let pure = return

	  let ( <*> ) : ('a -> 'b) M.t -> 'a M.t -> 'b M.t =
	   fun f x ->
	    f >>= fun f ->
	    x >>= fun x -> return (f x)
end

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

module Eval (M : MONADERROR) = struct
  open M
  open ApplicativeOfMonad (M)

  let eval from_env : expr -> int M.t =
    let rec helper = function
      | Const n -> return n
      | Plus (l, r) ->
          return ( + ) <*> helper l <*> helper r
      | Asterisk (l, r) ->
          return ( * ) <*> helper l <*> helper r
      | Slash (l, r) -> (
          return (fun l r -> (l, r))
          <*> helper l <*> helper r
          >>= function
          | _, 0 -> fail "division by zero"
          | l, r -> return (l / r))
      | Var s -> from_env s
    in
    helper
end