Created
September 2, 2014 14:27
-
-
Save ritalin/67ccbbf36f7956ef5801 to your computer and use it in GitHub Desktop.
型クラスっぽく見える何か by Elixir
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule Option do | |
defmodule None, do: defstruct [] | |
defmodule Some, do: defstruct [:value] | |
def none(), do: %None{} | |
def some(x), do: %Some{ value: x } | |
end | |
defprotocol FunctorSpec do | |
@type t :: term | |
@type result :: term | |
@type mapper :: (any -> term) | |
@spec fmap(t, mapper) :: result | |
def fmap(t, mapper) | |
end | |
defimpl FunctorSpec, for: Option.None do | |
def fmap(%Option.None{} = t, _mapper), do: t | |
end | |
defimpl FunctorSpec, for: Option.Some do | |
def fmap(%Option.Some{ value: x }, mapper) when is_function(mapper, 1) do | |
%Option.Some{ value: mapper.(x) } | |
end | |
end | |
defimpl FunctorSpec, for: List do | |
def fmap(list, mapper) when is_function(mapper, 1) do | |
list |> Enum.map mapper | |
end | |
end | |
defimpl FunctorSpec, for: Function do | |
def fmap(fun, mapper) when is_function(fun, 1) and is_function(mapper, 1) do | |
fn x -> apply mapper, [apply(fun, [x])] end | |
end | |
end | |
defprotocol ApplicativeSpec do | |
@type a :: term | |
@type b :: term | |
@type tc(term) :: term | |
@type mapper :: (a -> b) | |
@spec fmap(a, mapper) :: tc(b) | |
def fmap(x, mapper) | |
@spec bind(tc(a), tc(mapper)) :: tc(b) | |
def bind(tc, mapper) | |
end | |
defimpl ApplicativeSpec, for: Option.None do | |
def fmap(%Option.None{} = tc, _mapper) do | |
tc | |
end | |
def bind(tc, _ap) do | |
tc | |
end | |
end | |
defimpl ApplicativeSpec, for: Option.Some do | |
def fmap(%Option.Some{} = tc, mapper) do | |
tc |> bind Option.some mapper | |
end | |
def bind(%Option.Some{ value: x }, %Option.Some{ value: mapper }) when is_function(mapper, 1) do | |
apply(mapper, [x]) |> Option.some | |
end | |
end | |
defimpl ApplicativeSpec, for: List do | |
def fmap(list, mapper) when is_list(list) do | |
list |> bind [mapper] | |
end | |
def bind(list, mappers) when is_list(list) and is_list(mappers) do | |
mappers |> Enum.flat_map fn mapper -> list |> Enum.map mapper end | |
end | |
end | |
defprotocol MonadSpec do | |
def bind(tc, fun) | |
end | |
defimpl MonadSpec, for: Option.None do | |
def bind(%Option.None{} = tc, _fun) do | |
tc | |
end | |
end | |
defimpl MonadSpec, for: Option.Some do | |
def bind(%Option.Some{ value: x}, fun) when is_function(fun, 1) do | |
apply(fun, [x]) | |
end | |
end | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment