-
Notifications
You must be signed in to change notification settings - Fork 0
/
maybe.ex
106 lines (77 loc) · 2.82 KB
/
maybe.ex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# TODO: rewrite not to depend on `nil`
defmodule Cat.Maybe do
@moduledoc """
A value or nil.
Implements protocols:
* `Functor`
* `Applicative`
* `Monad`
"""
defmodule Just do
@enforce_keys [:val]
defstruct [:val]
end
defmodule Nothing do
defstruct []
end
@type just(a) :: %Just{val: a}
@type nothing :: %Nothing{}
@type t(a) :: just(a) | nothing
@spec new(a | nil) :: t(a) when a: var
def new(nil), do: %Nothing{}
def new(a), do: %Just{val: a}
@spec of(a) :: t(a) when a: var
def of(a), do: %Just{val: a}
@spec empty() :: t(none())
def empty(), do: %Nothing{}
@spec defined?(t(any)) :: boolean
def defined?(%Nothing{}), do: false
def defined?(_), do: true
@spec empty?(t(any)) :: boolean
def empty?(%Nothing{}), do: true
def empty?(_), do: false
@spec get(t(a)) :: a when a: var
def get(%Just{val: val}), do: val
@spec sample() :: t(none)
def sample(), do: %Nothing{}
#############################################
########## PROTOCOL IMPLEMENTATIONS #########
#############################################
alias Cat.Maybe
alias Cat.Maybe.{Just, Nothing}
defimpl Cat.Functor, for: [Maybe, Just, Nothing] do
@type t(a) :: Maybe.t(a)
@spec map(t(a), (a -> b)) :: t(b) when a: var, b: var
def map(%Nothing{}, _), do: %Nothing{}
def map(%Just{val: a}, f), do: %Just{val: f.(a)}
@spec as(t(any), a) :: t(a) when a: var
defdelegate as(t, a), to: Cat.Functor.Default
end
defimpl Cat.Applicative, for: [Maybe, Just, Nothing] do
@type t(a) :: Maybe.t(a)
@spec pure(t(any), a) :: t(a) when a: var
def pure(_, a), do: %Just{val: a}
@spec ap(t((a -> b)), t(a)) :: t(b) when a: var, b: var
def ap(%Nothing{}, _), do: %Nothing{}
def ap(_, %Nothing{}), do: %Nothing{}
def ap(f, %Just{val: a}), do: f.(a)
@spec product(t(a), t(b)) :: t({a, b}) when a: var, b: var
defdelegate product(ta, tb), to: Cat.Applicative.Default
@spec product_l(t(a), t(any)) :: t(a) when a: var
defdelegate product_l(ta, tb), to: Cat.Applicative.Default
@spec product_r(t(any), t(b)) :: t(b) when b: var
defdelegate product_r(ta, tb), to: Cat.Applicative.Default
@spec map2(t(a), t(b), (a, b -> c)) :: t(c) when a: var, b: var, c: var
defdelegate map2(ta, tb, f), to: Cat.Applicative.Default
end
defimpl Cat.Monad, for: [Maybe, Just, Nothing] do
@type t(a) :: Maybe.t(a)
@spec flat_map(t(a), (a -> t(b))) :: t(b) when a: var, b: var
def flat_map(%Nothing{}, _), do: %Nothing{}
def flat_map(%Just{val: a}, f), do: f.(a)
@spec flat_tap(Maybe.t(a), (a -> Maybe.t(no_return))) :: Maybe.t(a) when a: var
defdelegate flat_tap(ta, f), to: Cat.Monad.Default
@spec flatten(Maybe.t(Maybe.t(a))) :: Maybe.t(a) when a: var
defdelegate flatten(tta), to: Cat.Monad.Default
end
end