]> gitweb.factorcode.org Git - factor.git/blob - extra/monads/monads.factor
Merge branch 'master' of git://factorcode.org/git/factor
[factor.git] / extra / monads / monads.factor
1 ! Copyright (C) 2008 Slava Pestov
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: arrays kernel sequences sequences.deep splitting
4 accessors fry locals combinators namespaces lists lists.lazy
5 shuffle ;
6 IN: monads
7
8 ! Functors
9 GENERIC# fmap 1 ( functor quot -- functor' ) inline
10
11 ! Monads
12
13 ! Mixin type for monad singleton classes, used for return/fail only
14 MIXIN: monad
15
16 GENERIC: monad-of ( mvalue -- singleton )
17 GENERIC: return ( value singleton -- mvalue )
18 GENERIC: fail ( value singleton -- mvalue )
19 GENERIC: >>= ( mvalue -- quot )
20
21 M: monad return monad-of return ;
22 M: monad fail   monad-of fail   ;
23
24 : bind ( mvalue quot -- mvalue' ) swap >>= call ;
25 : >>   ( mvalue k -- mvalue' ) '[ drop , ] bind ;
26
27 :: lift-m2 ( m1 m2 f monad -- m3 )
28     m1 [| x1 | m2 [| x2 | x1 x2 f monad return ] bind ] bind ;
29
30 :: apply ( mvalue mquot monad -- result )
31     mvalue [| value |
32         mquot [| quot |
33             value quot call monad return
34         ] bind
35     ] bind ;
36
37 M: monad fmap over '[ @ , return ] bind ;
38
39 ! 'do' notation
40 : do ( quots -- result ) unclip dip [ bind ] each ;
41
42 ! Identity
43 SINGLETON: identity-monad
44 INSTANCE:  identity-monad monad
45
46 TUPLE: identity value ;
47 INSTANCE: identity monad
48
49 M: identity monad-of drop identity-monad ;
50
51 M: identity-monad return drop identity boa ;
52 M: identity-monad fail   "Fail" throw ;
53
54 M: identity >>= value>> '[ , _ call ] ;
55
56 : run-identity ( identity -- value ) value>> ;
57
58 ! Maybe
59 SINGLETON: maybe-monad
60 INSTANCE:  maybe-monad monad
61
62 SINGLETON: nothing
63
64 TUPLE: just value ;
65 : just ( value -- just ) \ just boa ;
66
67 UNION: maybe just nothing ;
68 INSTANCE: maybe monad
69
70 M: maybe monad-of drop maybe-monad ;
71
72 M: maybe-monad return drop just ;
73 M: maybe-monad fail   2drop nothing ;
74
75 M: nothing >>= '[ drop , ] ;
76 M: just    >>= value>> '[ , _ call ] ;
77
78 : if-maybe ( maybe just-quot nothing-quot -- )
79     pick nothing? [ 2nip call ] [ drop [ value>> ] dip call ] if ; inline
80
81 ! Either
82 SINGLETON: either-monad
83 INSTANCE:  either-monad monad
84
85 TUPLE: left value ;
86 : left ( value -- left ) \ left boa ;
87
88 TUPLE: right value ;
89 : right ( value -- right ) \ right boa ;
90
91 UNION: either left right ;
92 INSTANCE: either monad
93
94 M: either monad-of drop either-monad ;
95
96 M: either-monad return  drop right ;
97 M: either-monad fail    drop left ;
98
99 M: left  >>= '[ drop , ] ;
100 M: right >>= value>> '[ , _ call ] ;
101
102 : if-either ( value left-quot right-quot -- )
103     [ [ value>> ] [ left? ] bi ] 2dip if ; inline
104
105 ! Arrays
106 SINGLETON: array-monad
107 INSTANCE:  array-monad monad
108 INSTANCE:  array monad
109
110 M: array-monad return  drop 1array ;
111 M: array-monad fail   2drop { } ;
112
113 M: array monad-of drop array-monad ;
114
115 M: array >>= '[ , _ map concat ] ;
116
117 ! List
118 SINGLETON: list-monad
119 INSTANCE:  list-monad monad
120 INSTANCE:  list monad
121
122 M: list-monad return drop 1list ;
123 M: list-monad fail   2drop nil ;
124
125 M: list monad-of drop list-monad ;
126
127 M: list >>= '[ , _ lazy-map lconcat ] ;
128
129 ! State
130 SINGLETON: state-monad
131 INSTANCE:  state-monad monad
132
133 TUPLE: state quot ;
134 : state ( quot -- state ) \ state boa ;
135
136 INSTANCE: state monad
137
138 M: state monad-of drop state-monad ;
139
140 M: state-monad return drop '[ , 2array ] state ;
141 M: state-monad fail   "Fail" throw ;
142
143 : mcall ( state -- ) quot>> call ;
144
145 M: state >>= '[ , _ '[ , mcall first2 @ mcall ] state ] ;
146
147 : get-st ( -- state ) [ dup 2array ] state ;
148 : put-st ( value -- state ) '[ drop , f 2array ] state ;
149
150 : run-st ( state initial -- ) swap mcall second ;
151
152 : return-st ( value -- mvalue ) state-monad return ;
153
154 ! Reader
155 SINGLETON: reader-monad
156 INSTANCE:  reader-monad monad
157
158 TUPLE: reader quot ;
159 : reader ( quot -- reader ) \ reader boa ;
160 INSTANCE: reader monad
161
162 M: reader monad-of drop reader-monad ;
163
164 M: reader-monad return drop '[ drop , ] reader ;
165 M: reader-monad fail   "Fail" throw ;
166
167 M: reader >>= '[ , _ '[ dup , mcall @ mcall ] reader ] ;
168
169 : run-reader ( reader env -- ) swap mcall ;
170
171 : ask ( -- reader ) [ ] reader ;
172 : local ( reader quot -- reader' ) swap '[ @ , mcall ] reader ;
173
174 ! Writer
175 SINGLETON: writer-monad
176 INSTANCE:  writer-monad monad
177
178 TUPLE: writer value log ;
179 : writer ( value log -- writer ) \ writer boa ;
180
181 M: writer monad-of drop writer-monad ;
182
183 M: writer-monad return drop { } writer ;
184 M: writer-monad fail   "Fail" throw ;
185
186 : run-writer ( writer -- value log ) [ value>> ] [ log>> ] bi ;
187
188 M: writer >>= '[ , run-writer _ '[ @ run-writer ] dip append writer ] ;
189
190 : pass ( writer -- writer' ) run-writer [ first2 ] dip swap call writer ;
191 : listen ( writer -- writer' ) run-writer [ 2array ] keep writer ;
192 : tell ( seq -- writer ) f swap writer ;