monads: Fix 'mapm' so that effects happen from left to right.

* guix/monads.scm (mapm): Don't reverse LST, so that items are processed
  from left to right.  Bind the result of 'foldm' and reverse it.
* tests/monads.scm ("sequence"): Change 'frob' so it performs its side
  effect within an 'mlet' body.  Adjust call accordingly.
This commit is contained in:
Ludovic Courtès 2014-07-12 17:16:36 +02:00
parent c2150d9ace
commit f62435e286
2 changed files with 17 additions and 13 deletions

View File

@ -209,13 +209,15 @@ monadic value seeded by INIT."
(define (mapm monad mproc lst) (define (mapm monad mproc lst)
"Map MPROC over LST, a list of monadic values in MONAD, and return a monadic "Map MPROC over LST, a list of monadic values in MONAD, and return a monadic
list." list. LST items are bound from left to right, so effects in MONAD are known
(foldm monad to happen in that order."
(lambda (item result) (mlet monad ((result (foldm monad
(mlet monad ((item (mproc item))) (lambda (item result)
(return (cons item result)))) (mlet monad ((item (mproc item)))
'() (return (cons item result))))
(reverse lst))) '()
lst)))
(return (reverse result))))
(define-inlinable (sequence monad lst) (define-inlinable (sequence monad lst)
"Turn the list of monadic values LST into a monadic list of values, by "Turn the list of monadic values LST into a monadic list of values, by

View File

@ -166,14 +166,16 @@
(let* ((input (iota 100)) (let* ((input (iota 100))
(order '())) (order '()))
(define (frob i) (define (frob i)
;; The side effect here is used to keep track of the order in (mlet monad ((foo (return 'foo)))
;; which monadic values are bound. ;; The side effect here is used to keep track of the order in
(set! order (cons i order)) ;; which monadic values are bound. Perform the side effect
i) ;; within a '>>=' so that it is performed when the return
;; value is actually bound.
(set! order (cons i order))
(return i)))
(and (equal? input (and (equal? input
(run (sequence monad (run (sequence monad (map frob input))))
(map (lift1 frob monad) input))))
;; Make sure this is from left to right. ;; Make sure this is from left to right.
(equal? order (reverse input))))) (equal? order (reverse input)))))