0% found this document useful (0 votes)
67 views10 pages

Monad (3) .Ps

The document discusses different approaches to enumerating the leaves of a binary tree in left-to-right depth-first order in a pure functional way, including using an assignment on a free variable, carrying state in an auxiliary data structure, and using monads to eliminate the need to explicitly pass state. It also introduces the concept of monads for imposing order in pure functional programs and defines monadic operations like return, bind, get, and set for representing state.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PS, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
67 views10 pages

Monad (3) .Ps

The document discusses different approaches to enumerating the leaves of a binary tree in left-to-right depth-first order in a pure functional way, including using an assignment on a free variable, carrying state in an auxiliary data structure, and using monads to eliminate the need to explicitly pass state. It also introduces the concept of monads for imposing order in pure functional programs and defines monadic operations like return, bind, get, and set for representing state.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PS, PDF, TXT or read online on Scribd
You are on page 1/ 10

monad.

scm Fri Feb 25 11:42:10 2011 1

;;;; Monads in Scheme

;;; Monads are a set of elegant design patterns


;;; for imposing predictable order in a pure
;;; functional program. (CPS is another way to
;;; accomplish this goal.) One may need to impose
;;; a predictable order to operate I/O or to
;;; simulate state with a functional "store"
;;; carried around in the program.

;;; Monads also provide plumbing for carrying the


;;; store in a way that does not impose itself on
;;; the users code, so that the result looks very
;;; much like a stateful program.

;;; A traditional example is to produce a binary


;;; tree isomorphic to a given one, but with the
;;; leaves replaced by a sequence of numbers in a
;;; left-to-right depth-first order. Here I
;;; investigate various ways to do this, starting
;;; with the most traditional use of assignment on
;;; a free variable.
monad.scm Fri Feb 25 11:42:10 2011 2

(define make-tree cons)


(define left car)
(define right cdr)
(define (terminal? x) (not (pair? x)))

;;; Statefully, with a free variable. This is the


;;; "natural" way to do the job in an imperative
;;; language.

(define (enumerate-tree tree)


(let ((n 0))
(define (walk tree)
(if (terminal? tree)
(let ((old-n n))
(set! n (+ n 1))
old-n)
(let* ((lt (walk (left tree)))
(rt (walk (right tree))))
(make-tree lt rt))))
(walk tree)))

#|
(enumerate-tree (a (b . c) . d))
;Value: (0 (1 . 2) . 3)
|#
monad.scm Fri Feb 25 11:42:10 2011 3

;;; Alternatively, one can use an auxiliary data


;;; structure to carry the state. This requires
;;; constructing and destructuring at each step.
;;; (This can be prettified with pattern-matching
;;; destructuring.)

(define (enumerate-tree tree)


(define (walk tree n)
(if (terminal? tree)
(cons n (+ n 1))
(let* ((ltn (walk (left tree) n))
(lt (car ltn)) (ln (cdr ltn))
(rtn (walk (right tree) ln))
(rt (car rtn)) (rn (cdr rtn)))
(cons (make-tree lt rt) rn))))
(car (walk tree 0)))

#|
(enumerate-tree (a (b . c) . d))
;Value: (0 (1 . 2) . 3)
|#
monad.scm Fri Feb 25 11:42:10 2011 4

;;; GJSs natural style, using continuation


;;; passing to eliminate the extra data structure.

(define (enumerate-tree tree)


(define (walk tree n cont)
(if (terminal? tree)
(cont n (+ n 1))
(walk (left tree)
n
(lambda (lt n)
(walk (right tree)
n
(lambda (rt n)
(cont (make-tree lt rt)
n)))))))
(walk tree 0 (lambda (tree n) tree)))

#|
(enumerate-tree (a (b . c) . d))
;Value: (0 (1 . 2) . 3)
|#
monad.scm Fri Feb 25 11:42:10 2011 5

;;; Notice that we must carry around that ugly


;;; "n", the state that was so neatly packaged in
;;; the imperative version. Is there some way we
;;; can retain the pure functional form but pipe
;;; it around, without having it clutter up our
;;; algorithm? The answer is yes. We set up a
;;; monad. Lets first do it with the auxiliary
;;; data structure.
monad.scm Fri Feb 25 11:42:10 2011 6

(define (return val)


(lambda (state)
(cons val state)))

(define (pipe first then) ;bind


(lambda (state)
(let* ((fvs (first state))
(first-val (car fvs))
(next-state (cdr fvs)))
((then first-val) next-state))))

(define (get)
(lambda (state)
(cons state state)))

(define (set new-state)


(lambda (old-state)
(cons #f new-state)))

(define (sequentially first then)


(lambda (state)
(let* ((fvs (first state))
(first-val (car fvs))
(next-state (cdr fvs)))
(then next-state))))

(define (run c initial-state)


(let* ((cvs (c initial-state))
(c-val (car cvs))
(next-state (cdr cvs)))
c-val))
monad.scm Fri Feb 25 11:42:10 2011 7

;;; And here is the enumerator using this


;;; plumbing. Notice that we have gotten rid of
;;; that annoying intrusion of the state into the
;;; non-terminal case of the walker.

(define (enumerate-tree tree)


(define (walk tree)
(if (terminal? tree)
(pipe (get)
(lambda (n)
(sequentially (set (+ n 1))
(return n))))
(pipe (walk (left tree))
(lambda (lt)
(pipe (walk (right tree))
(lambda (rt)
(return
(make-tree lt rt))))))))
(run (walk tree) 0))

(enumerate-tree (a (b . c) . d))
;Value: (0 (1 . 2) . 3)
monad.scm Fri Feb 25 11:42:10 2011 8

;;; Alternatively, we can get rid of the explicit


;;; construction of the value and state, using a
;;; continuation function:

(define (return val)


(lambda (state)
(lambda (cont)
(cont val state))))

(define (pipe first then) ;bind


(lambda (state)
((first state)
(lambda (first-val next-state)
((then first-val) next-state)))))

(define (get)
(lambda (state)
(lambda (cont)
(cont state state))))

(define (set new-state)


(lambda (old-state)
(lambda (cont)
(cont #f new-state))))

(define (sequentially first then)


(lambda (state)
((first state)
(lambda (first-val next-state)
(then next-state)))))

(define (run c initial-state)


((c initial-state)
(lambda (val next-state) val)))
monad.scm Fri Feb 25 11:42:10 2011 9

#|
;;; Monad laws, proved by symbolic evaluation.
;;; Monadic object above is : state -> (cont -> b)

;;; return : a -> M a


;;; pipe : M a -> ( (a -> M b) -> M b )

;;; We need to setup some objects

(define m ; m is a monadic object


(lambda (state)
(lambda (cont)
(cont b (list ms state)))))

(define f ; f : x -> M fx
(lambda (x)
(lambda (state)
(lambda (cont)
(cont (list f x)
(list fs state))))))

(define g ; g : x -> M gx
(lambda (x)
(lambda (state)
(lambda (cont)
(cont (list g x)
(list gs state))))))
monad.scm Fri Feb 25 11:42:10 2011 10

;;; Law 1: (pipe (return x) f) = (f x)

(equal? (run (pipe (return x) f) a)


(run (f x) a))
;Value: #t

;;; Law 2: (pipe f return) = f

(equal? (run (pipe f return) a)


(run (f a) uninteresting))
;Value: #t

;;; Law 3: (pipe (pipe m f) g)


;;; = (pipe m
;;; (lambda (x)
;;; (pipe (f x) g)))

(equal? (run (pipe (pipe m f) g) a)


(run (pipe m
(lambda (y)
(pipe (f y) g)))
a))
;Value: #t

You might also like