Кастомный оператор для `bind`.
Closed this issue · 1 comments
В девятом уроке написано следующие:
Увы, в Эликсире нельзя сделать как в Хаскеле, в префиксном виде:
f = validate_incoming_data >>= validate_cat >>= validate_address >>= validate_books >>= create_order
f test_data
Но в Эликсире же можно сделать кастомный оператор(если вы это, конечно, имели в виду :) ). Вариация не такая большая, как в Хаскеле, но всё же. Вот и я прикинул как это было бы:
defprotocol Monad do
@spec Monad.t() ~> (any() -> Monad.t()) :: Monad.t()
def x ~> fy
end
defmodule Maybe do
@type t(a) :: %Maybe{container: :error | {:ok, a}}
@type t :: Maybe.t(any())
@type some(a) :: %Maybe{container: {:ok, a}}
@type non() :: %Maybe{container: :error}
defstruct [:container]
@spec some(t) :: some(t) when t: any
def some(value), do: %Maybe{container: {:ok, value}}
@spec non() :: Maybe.non()
def non(), do: %Maybe{container: :error}
end
defimpl Monad, for: Maybe do
def x ~> fy do
case x do
%Maybe{container: {:ok, value}} -> fy.(value)
%Maybe{container: :error} -> :error
end
end
end
И использовать это можно след образом:
@spec foo(t) :: Maybe.t(t) when t: integer
def foo(x) when x > 7, do: Maybe.some(x)
def foo(_), do: Maybe.non()
@spec square(t) :: Maybe.some(t) when t: number
def square(x), do: Maybe.some(x ** 2)
foo(6) ~> (&square/1) ~> (&square/1) # => :error
foo(8) ~> (&square/1) ~> (&square/1) # => {:ok, 4096}
И, вспоминая пример из текста, можно его повторить примерно c оговорками:
f = fn x -> foo(x) ~> (&square/1) end
f.(data)
Стоит ли делать ремарку? И если да, то может просто указать в качестве ссылки этот issue? :)
Спасибо за комментарий. Да, многие элементы ФП, которых нет из коробки, можно реализовать. Или найти готовые библиотеки, в которых они реализованы.
Пожалуй, есть смысл указать в курсе такие библиотеки.