@@ -170,6 +170,51 @@ module ComputationExpressions =
170170
171171 ()
172172
173+ module Applicative =
174+ [<Test>]
175+ let applicateiveShortCircuits () =
176+
177+ // This should be the case for any lazy monad stack with short-circuit applicative (Collections, Options, short-circuits Eithers)
178+
179+ let mutable actions : string list = []
180+
181+ let getNumberO i : SeqT < Task < _ >, int > = monad.plus {
182+ let! _ =
183+ monad' {
184+ do ! Task.Delay 10 |> Task.ignore
185+ actions <- " init" :: actions
186+ }
187+ |> SeqT.lift
188+
189+ let! x =
190+ monad' {
191+ do ! Task.Delay 10 |> Task.ignore
192+ actions <- ( " read " + ( string i)) :: actions
193+ return ( string i)
194+ }
195+ |>> tryParse
196+ |>> Option.toList
197+ |>> List.toSeq
198+ |> SeqT
199+ if x = i + 10 then yield x // will be always false
200+ }
201+
202+ let seqt = result (+) <*> getNumberO 1 <*> getNumberO 2
203+
204+ // Non-lazy stacks would have been executed at this point
205+ CollectionAssert.AreEqual ( actions, [])
206+
207+ let res = SeqT.run seqt
208+
209+ // Still executing
210+ CollectionAssert.AreEqual ( actions, [])
211+
212+ // Now we block until it finish
213+ CollectionAssert.AreEqual ( res.Result, [])
214+
215+ // Since the first value was an empty list, no further effect should be expected
216+ CollectionAssert.AreEqual ( actions, [ " read 1" ; " init" ])
217+
173218
174219 module AsyncSeq =
175220
@@ -280,4 +325,4 @@ module ComputationExpressions =
280325 let expected = Seq.zip la lb |> Seq.map ((<||) (+)) |> SeqT.ofSeq
281326 Assert.True ( EQ expected actual)
282327
283-
328+
0 commit comments