-
Notifications
You must be signed in to change notification settings - Fork 88
/
Bind.purs
150 lines (131 loc) · 4.12 KB
/
Bind.purs
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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
module Control.Bind
( class Bind
, bind
, (>>=)
, bindFlipped
, (=<<)
, class Discard
, discard
, join
, composeKleisli
, (>=>)
, composeKleisliFlipped
, (<=<)
, ifM
, module Data.Functor
, module Control.Apply
, module Control.Applicative
) where
import Control.Applicative (class Applicative, liftA1, pure, unless, when)
import Control.Apply (class Apply, apply, (*>), (<*), (<*>))
import Control.Category (identity)
import Data.Function (flip)
import Data.Functor (class Functor, map, void, ($>), (<#>), (<$), (<$>))
import Data.Unit (Unit)
import Type.Proxy (Proxy(..))
-- | The `Bind` type class extends the [`Apply`](#apply) type class with a
-- | "bind" operation `(>>=)` which composes computations in sequence, using
-- | the return value of one computation to determine the next computation.
-- |
-- | The `>>=` operator can also be expressed using `do` notation, as follows:
-- |
-- | ```purescript
-- | x >>= f = do y <- x
-- | f y
-- | ```
-- |
-- | where the function argument of `f` is given the name `y`.
-- |
-- | Instances must satisfy the following laws in addition to the `Apply`
-- | laws:
-- |
-- | - Associativity: `(x >>= f) >>= g = x >>= (\k -> f k >>= g)`
-- | - Apply Superclass: `apply f x = f >>= \f’ -> map f’ x`
-- |
-- | Associativity tells us that we can regroup operations which use `do`
-- | notation so that we can unambiguously write, for example:
-- |
-- | ```purescript
-- | do x <- m1
-- | y <- m2 x
-- | m3 x y
-- | ```
class Apply m <= Bind m where
bind :: forall a b. m a -> (a -> m b) -> m b
infixl 1 bind as >>=
-- | `bindFlipped` is `bind` with its arguments reversed. For example:
-- |
-- | ```purescript
-- | print =<< random
-- | ```
bindFlipped :: forall m a b. Bind m => (a -> m b) -> m a -> m b
bindFlipped = flip bind
infixr 1 bindFlipped as =<<
instance bindFn :: Bind ((->) r) where
bind m f x = f (m x) x
-- | The `bind`/`>>=` function for `Array` works by applying a function to
-- | each element in the array, and flattening the results into a single,
-- | new array.
-- |
-- | Array's `bind`/`>>=` works like a nested for loop. Each `bind` adds
-- | another level of nesting in the loop. For example:
-- | ```
-- | foo :: Array String
-- | foo =
-- | ["a", "b"] >>= \eachElementInArray1 ->
-- | ["c", "d"] >>= \eachElementInArray2
-- | pure (eachElementInArray1 <> eachElementInArray2)
-- |
-- | -- In other words...
-- | foo
-- | -- ... is the same as...
-- | [ ("a" <> "c"), ("a" <> "d"), ("b" <> "c"), ("b" <> "d") ]
-- | -- which simplifies to...
-- | [ "ac", "ad", "bc", "bd" ]
-- | ```
instance bindArray :: Bind Array where
bind = arrayBind
foreign import arrayBind :: forall a b. Array a -> (a -> Array b) -> Array b
instance bindProxy :: Bind Proxy where
bind _ _ = Proxy
-- | A class for types whose values can safely be discarded
-- | in a `do` notation block.
-- |
-- | An example is the `Unit` type, since there is only one
-- | possible value which can be returned.
class Discard a where
discard :: forall f b. Bind f => f a -> (a -> f b) -> f b
instance discardUnit :: Discard Unit where
discard = bind
instance discardProxy :: Discard (Proxy a) where
discard = bind
-- | Collapse two applications of a monadic type constructor into one.
join :: forall a m. Bind m => m (m a) -> m a
join m = m >>= identity
-- | Forwards Kleisli composition.
-- |
-- | For example:
-- |
-- | ```purescript
-- | import Data.Array (head, tail)
-- |
-- | third = tail >=> tail >=> head
-- | ```
composeKleisli :: forall a b c m. Bind m => (a -> m b) -> (b -> m c) -> a -> m c
composeKleisli f g a = f a >>= g
infixr 1 composeKleisli as >=>
-- | Backwards Kleisli composition.
composeKleisliFlipped :: forall a b c m. Bind m => (b -> m c) -> (a -> m b) -> a -> m c
composeKleisliFlipped f g a = f =<< g a
infixr 1 composeKleisliFlipped as <=<
-- | Execute a monadic action if a condition holds.
-- |
-- | For example:
-- |
-- | ```purescript
-- | main = ifM ((< 0.5) <$> random)
-- | (trace "Heads")
-- | (trace "Tails")
-- | ```
ifM :: forall a m. Bind m => m Boolean -> m a -> m a -> m a
ifM cond t f = cond >>= \cond' -> if cond' then t else f