@@ -25,6 +25,37 @@ public struct IO<A> {
2525 }
2626}
2727
28+ /// Wraps up a closure in a lazy IO action.
29+ ///
30+ /// Do-notation is a special syntax taken from Haskell. In Haskell, one uses do-notation as a
31+ /// shorthand for chains of Monadic operators, and for more "imperative-looking" code. While Swift
32+ /// does not allow us to define a DSL that specific, we can use the implicit sequencing of its
33+ /// imperative statements and call execution of those statements our "desugaring".
34+ ///
35+ /// Generally, do-notation in the Basis is used around side-effecting code. Do-blocks in Swift are
36+ /// therefore more useful as a means of delimiting pure and side-effecting code from one another,
37+ /// while also retaining the benefits of the lazy IO monad.
38+ ///
39+ /// It is important to note that IO actions returned are lazy. This means the provided block will
40+ /// not be executed until the values inside are requested, either with an extract (`<-`) or a call
41+ /// to `unsafePerformIO()`
42+ public func do_< A> ( fn: ( ) -> IO < A > ) -> IO < A > {
43+ return IO < A > ( { rw in ( rw, !fn( ) ) } )
44+ }
45+
46+ /// Wraps up a closure returning a value in a lazy IO action.
47+ ///
48+ /// This variant of do-blocks allows one to write more natural looking code. The return keyword
49+ /// becomes monadic return.
50+ public func do_< A> ( fn: ( ) -> A ) -> IO < A > {
51+ return IO < A > ( { rw in ( rw, fn ( ) ) } )
52+ }
53+
54+ /// An more convenient form of unsafePerformIO.
55+ public prefix func ! < A> ( m: IO < A > ) -> A {
56+ return m. unsafePerformIO ( )
57+ }
58+
2859/// Writes a character to standard output.
2960public func putChar( c : Character ) -> IO < Void > {
3061 return IO . pure ( print ( c) )
@@ -126,6 +157,25 @@ public func <* <A, B>(a : IO<A>, b : IO<B>) -> IO<A> {
126157 return const <%> a <*> b
127158}
128159
160+ extension IO : ApplicativeOps {
161+ typealias C = Any
162+ typealias FC = IO < C >
163+ typealias D = Any
164+ typealias FD = IO < D >
165+
166+ public static func liftA< B> ( f : A -> B ) -> IO < A > -> IO < B > {
167+ return { a in IO < A -> B > . pure ( f) <*> a }
168+ }
169+
170+ public static func liftA2< B, C> ( f : A -> B -> C ) -> IO < A > -> IO < B > -> IO < C > {
171+ return { a in { b in f <%> a <*> b } }
172+ }
173+
174+ public static func liftA3< B, C, D> ( f : A -> B -> C -> D ) -> IO < A > -> IO < B > -> IO < C > -> IO < D > {
175+ return { a in { b in { c in f <%> a <*> b <*> c } } }
176+ }
177+ }
178+
129179extension IO : Monad {
130180 public func bind< B> ( f: A -> IO < B > ) -> IO < B > {
131181 return IO < B > ( { rw in
@@ -145,73 +195,46 @@ public func >><A, B>(x: IO<A>, y: IO<B>) -> IO<B> {
145195 } )
146196}
147197
148- public prefix func ! < A> ( m: IO < A > ) -> A {
149- return m. unsafePerformIO ( )
150- }
198+ extension IO : MonadOps {
199+ typealias MLA = IO < [ A ] >
200+ typealias MLB = IO < [ B ] >
201+ typealias MU = IO < ( ) >
151202
152- /// Wraps up a closure in a lazy IO action.
153- ///
154- /// Do-notation is a special syntax taken from Haskell. In Haskell, one uses do-notation as a
155- /// shorthand for chains of Monadic operators, and for more "imperative-looking" code. While Swift
156- /// does not allow us to define a DSL that specific, we can use the implicit sequencing of its
157- /// imperative statements and call execution of those statements our "desugaring".
158- ///
159- /// Generally, do-notation in the Basis is used around side-effecting code. Do-blocks in Swift are
160- /// therefore more useful as a means of delimiting pure and side-effecting code from one another,
161- /// while also retaining the benefits of the lazy IO monad.
162- ///
163- /// It is important to note that IO actions returned are lazy. This means the provided block will
164- /// not be executed until the values inside are requested, either with an extract (`<-`) or a call
165- /// to `unsafePerformIO()`
166- public func do_< A> ( fn: ( ) -> IO < A > ) -> IO < A > {
167- return IO < A > ( { rw in ( rw, !fn( ) ) } )
168- }
203+ public static func mapM< B> ( f : A -> IO < B > ) -> [ A ] -> IO < [ B ] > {
204+ return { xs in IO< B> . sequence( map ( f) ( xs) ) }
205+ }
169206
170- /// Wraps up a closure returning a value in a lazy IO action.
171- ///
172- /// This variant of do-blocks allows one to write more natural looking code. The return keyword
173- /// becomes monadic return.
174- public func do_< A> ( fn: ( ) -> A ) -> IO < A > {
175- return IO < A > ( { rw in ( rw, fn ( ) ) } )
176- }
207+ public static func mapM_< B> ( f : A -> IO < B > ) -> [ A ] -> IO < ( ) > {
208+ return { xs in IO< B> . sequence_( map ( f) ( xs) ) }
209+ }
177210
178- /// Executes a list of IO actions sequentially, accumulating their results in a list in another IO
179- /// action
180- public func sequence< A> ( ms : [ IO < A > ] ) -> IO < [ A ] > {
181- return foldr ( { m in { n in
182- do_ { ( ) -> [ A ] in
183- let x : A = !m
184- let xs : [ A ] = !n
185- return [ x] + xs
186- }
187- } } ) ( IO . pure ( [ ] ) ) ( ms)
188- }
211+ public static func forM< B> ( xs : [ A ] ) -> ( A -> IO < B > ) -> IO < [ B ] > {
212+ return flip ( IO . mapM) ( xs)
213+ }
189214
190- /// Executes a list of IO actions sequentially, discarding the result of each along the way.
191- public func sequence_< A> ( ms : [ IO < A > ] ) -> IO < Void > {
192- return foldr ( { x, y in x. bind ( { _ in y } ) } ) ( IO< Void> . pure( Void ( ) ) ) ( ms)
193- }
215+ public static func forM_< B> ( xs : [ A ] ) -> ( A -> IO < B > ) -> IO < ( ) > {
216+ return flip ( IO . mapM_) ( xs)
217+ }
218+
219+ public static func sequence( ls : [ IO < A > ] ) -> IO < [ A ] > {
220+ return foldr ( { m, m2 in m >>- { x in m2 >>- { xs in IO< [ A] > . pure( cons ( x) ( xs) ) } } } ) ( IO< [ A] > . pure( [ ] ) ) ( ls)
221+ }
194222
195- /// Maps a function over a list, then sequences the resulting IO actions together, accumulating
196- /// their results in a list in another IO action.
197- public func mapM< A, B> ( f : A -> IO < B > ) -> [ A ] -> IO < [ B ] > {
198- return { ms in sequence ( ms. map ( f) ) }
223+ public static func sequence_( ls : [ IO < A > ] ) -> IO < ( ) > {
224+ return foldr ( >>) ( IO < ( ) > . pure ( ( ) ) ) ( ls)
225+ }
199226}
200227
201- /// Maps a function over a list, then sequences the resulting IO actions together, discarding the
202- /// result of each along the way.
203- public func mapM_< A, B> ( f : A -> IO < B > ) -> [ A ] -> IO < Void > {
204- return { ms in sequence_ ( ms. map ( f) ) }
228+ public func -<< < A, B> ( f : A -> IO < B > , xs : IO < A > ) -> IO < B > {
229+ return xs. bind ( f)
205230}
206231
207- /// mapM with its arguments flipped around.
208- public func forM< A, B> ( l: [ A ] ) ( f : A -> IO < B > ) -> IO < [ B ] > {
209- return mapM ( f) ( l)
232+ public func >-> < A, B, C> ( f : A -> IO < B > , g : B -> IO < C > ) -> A -> IO < C > {
233+ return { x in f ( x) >>- g }
210234}
211235
212- /// mapM_ with its arguments flipped around.
213- public func forM_< A, B> ( l: [ A ] ) ( f : A -> IO < B > ) -> IO < Void > {
214- return mapM_ ( f) ( l)
236+ public func <-< < A, B, C> ( g : B -> IO < C > , f : A -> IO < B > ) -> A -> IO < C > {
237+ return { x in f ( x) >>- g }
215238}
216239
217240extension IO : MonadFix {
0 commit comments