Monads

A native Scheme implementation of monads, with notation similar to Haskell's. Enables the user to define custom monads through defmonad, and provides ready to use implementations of some simple monads like Maybe. Support for the "do" notation (here called perform) is included.

Procedures

assert-monad name

Checks whether a monad is defined, and signals an error if it's not

defmonad name user-return user->>=

Defines a new monad by specifying the name, the return and the bind (>>=) operations. For example, here's how the Maybe monad might be defined:

 (define (just x) (list 'just x)) 
 (define (nothing) (list 'nothing))  

 (define just? (t? 'just))
 (define nothing? (t? 'nothing))

 (defmonad 'maybe
  just
  (lambda (m1 f)
    (if (just? m1)
        (f (cadr m1))
        m1)))
 
And here's how we can use it (without the "do" notation):
 (define *current-monad* 'maybe)
 ;Value: *current-monad*

 (>>= (just 50) (lambda (x) (return (* 2 x))))
 ;Value 33: (just 100)
 
 (>> (nothing) (>>= (just 50) (lambda (x) (return (* 2 x)))))
 ;Value 34: (nothing)
 

just x

creates a "just" instance of the Maybe monad

nothing

creates a "nothing" instance of the Maybe monad

just? x

checks whether an object is a "just" instance of the maybe monad

nothing? x

checks whether an object is a "nothing" instance of the maybe monad

mapM monad-name func lst

The monadic equivalent of map. Example:

 (mapM 'maybe (lambda (x) (perform 'maybe (return (* 2 x)))) '(1 2 3 4))
 ;Value 17: (just (2 4 6 8))
 

filterM monad-name pred lst

Monadic equivalent of filter. Example:

 (filterM 'maybe (lambda (x) (perform 'maybe (return (even? x)))) '(1 2 3 4 5 6 7 8))
 ;Value 19: (just (2 4 6 8))
 

foldM monad-name func init lst

Monadic left fold (fold-left). Example:

 (foldM 'maybe (lambda (a b) (perform 'maybe (return (+ a b)))) 0 '(1 2 3 4 5))
 ;Value 20: (just 15)
 


Generic Operators

monad? monad-name

Checks whether a monad is defined. For example:

(monad? 'maybe) => #t


Macros

return x

the monadic return operator. Maps an underlying value to a monadic type. For example if *current-monad* is set to 'maybe:
(return 10) => (just 10)

>>= m1 f

the monadic bind operator. Example:

 (define *current-monad* 'maybe)
 ;Value: *current-monad*

 (>>= (just 50) (lambda (x) (return (* 2 x))))
 ;Value 33: (just 100)
 

>> m1 m2

like >>=, but ignores the result. (>> (M x) (M y)) is equivalent to (>>= (M x) (lambda (x) (M y)))

perform monad {expressions}

Implements the "do" notation, which simplifies the monadic syntax. To bind monadic types to variables within a perform, use mlet.
Examples:

 (define (safe-div a b)
   (if (eqv? b 0)
       (nothing)
       (just (/ a b))))
 ;Value: safe-div
 
 (perform 'maybe
          (safe-div 10 5)
          (mlet ((x (safe-div 20 5))
                 (y (safe-div 30 5)))
                (return (* x y))))
 ;Value 15: (just 24)
 
 (perform 'maybe
          (safe-div 10 5)
          (mlet ((x (safe-div 20 0)) ;division by zero!
                 (y (safe-div 30 5)))
                (return (* x y))))
 ;Value 16: (nothing)
 

mlet

Monadic let - for use with the "do" notation. See the example for the "perform" macro.


Scheme Power Tools Documentation
(c) Maciej Pacula 2010-2011
http://mpacula.com