/
Apply.purs
97 lines (82 loc) · 3.38 KB
/
Apply.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
module Control.Apply
( class Apply, apply, (<*>)
, applyFirst, (<*)
, applySecond, (*>)
, lift2, lift3, lift4, lift5
, module Data.Functor
) where
import Data.Functor (class Functor, map, void, ($>), (<#>), (<$), (<$>))
import Data.Function (const)
import Control.Category (identity)
import Type.Proxy (Proxy(..))
-- | The `Apply` class provides the `(<*>)` which is used to apply a function
-- | to an argument under a type constructor.
-- |
-- | `Apply` can be used to lift functions of two or more arguments to work on
-- | values wrapped with the type constructor `f`. It might also be understood
-- | in terms of the `lift2` function:
-- |
-- | ```purescript
-- | lift2 :: forall f a b c. Apply f => (a -> b -> c) -> f a -> f b -> f c
-- | lift2 f a b = f <$> a <*> b
-- | ```
-- |
-- | `(<*>)` is recovered from `lift2` as `lift2 ($)`. That is, `(<*>)` lifts
-- | the function application operator `($)` to arguments wrapped with the
-- | type constructor `f`.
-- |
-- | Put differently...
-- | ```
-- | foo =
-- | functionTakingNArguments <$> computationProducingArg1
-- | <*> computationProducingArg2
-- | <*> ...
-- | <*> computationProducingArgN
-- | ```
-- |
-- | Instances must satisfy the following law in addition to the `Functor`
-- | laws:
-- |
-- | - Associative composition: `(<<<) <$> f <*> g <*> h = f <*> (g <*> h)`
-- |
-- | Formally, `Apply` represents a strong lax semi-monoidal endofunctor.
class Functor f <= Apply f where
apply :: forall a b. f (a -> b) -> f a -> f b
infixl 4 apply as <*>
instance applyFn :: Apply ((->) r) where
apply f g x = f x (g x)
instance applyArray :: Apply Array where
apply = arrayApply
foreign import arrayApply :: forall a b. Array (a -> b) -> Array a -> Array b
instance applyProxy :: Apply Proxy where
apply _ _ = Proxy
-- | Combine two effectful actions, keeping only the result of the first.
applyFirst :: forall a b f. Apply f => f a -> f b -> f a
applyFirst a b = const <$> a <*> b
infixl 4 applyFirst as <*
-- | Combine two effectful actions, keeping only the result of the second.
applySecond :: forall a b f. Apply f => f a -> f b -> f b
applySecond a b = const identity <$> a <*> b
infixl 4 applySecond as *>
-- | Lift a function of two arguments to a function which accepts and returns
-- | values wrapped with the type constructor `f`.
-- |
-- | ```purescript
-- | lift2 add (Just 1) (Just 2) == Just 3
-- | lift2 add Nothing (Just 2) == Nothing
-- |```
-- |
lift2 :: forall a b c f. Apply f => (a -> b -> c) -> f a -> f b -> f c
lift2 f a b = f <$> a <*> b
-- | Lift a function of three arguments to a function which accepts and returns
-- | values wrapped with the type constructor `f`.
lift3 :: forall a b c d f. Apply f => (a -> b -> c -> d) -> f a -> f b -> f c -> f d
lift3 f a b c = f <$> a <*> b <*> c
-- | Lift a function of four arguments to a function which accepts and returns
-- | values wrapped with the type constructor `f`.
lift4 :: forall a b c d e f. Apply f => (a -> b -> c -> d -> e) -> f a -> f b -> f c -> f d -> f e
lift4 f a b c d = f <$> a <*> b <*> c <*> d
-- | Lift a function of five arguments to a function which accepts and returns
-- | values wrapped with the type constructor `f`.
lift5 :: forall a b c d e f g. Apply f => (a -> b -> c -> d -> e -> g) -> f a -> f b -> f c -> f d -> f e -> f g
lift5 f a b c d e = f <$> a <*> b <*> c <*> d <*> e