smalltalk-tng

annotate experiments/monad/general-monad.scm @ 323:454c18798969

merger
author Tony Garnock-Jones <tonygarnockjones@gmail.com>
date Tue Feb 07 11:34:20 2012 -0500 (3 months ago)
parents 9e14ff21779b
children
rev   line source
tonyg@68 1 (require (lib "match.ss")
tonyg@84 2 (lib "etc.ss")
tonyg@84 3 (lib "errortrace.ss" "errortrace")
tonyg@88 4 (lib "1.ss" "srfi")
tonyg@68 5 (lib "9.ss" "srfi"))
tonyg@68 6
tonyg@84 7 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
tonyg@84 8
tonyg@84 9 (print-struct #t)
tonyg@84 10 (define previous-inspector (current-inspector))
tonyg@84 11 (current-inspector (make-inspector))
tonyg@84 12
tonyg@84 13 (define-record-type <monad-class>
tonyg@84 14 (make-monad-class name binder returner failer)
tonyg@84 15 monad-class?
tonyg@84 16 (name monad-class-name)
tonyg@84 17 (binder monad-class-binder)
tonyg@84 18 (returner monad-class-returner)
tonyg@84 19 (failer monad-class-failer))
tonyg@84 20
tonyg@68 21 (define-record-type <monad>
tonyg@68 22 (make-monad kind value)
tonyg@68 23 monad?
tonyg@68 24 (kind monad-kind)
tonyg@68 25 (value monad-value))
tonyg@68 26
tonyg@84 27 (current-inspector previous-inspector)
tonyg@84 28
tonyg@84 29 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
tonyg@84 30
tonyg@84 31 (define (determined? m)
tonyg@84 32 (monad-class? (monad-kind m)))
tonyg@84 33
tonyg@84 34 (define (monadize m)
tonyg@84 35 (cond
tonyg@84 36 ((pair? m) (make-monad *list* m))
tonyg@84 37 ((null? m) (make-monad *list* m))
tonyg@94 38 ((monad? m) m)
tonyg@84 39 (else (error "not a monad" m))))
tonyg@84 40
tonyg@68 41 (define (>>= ma a->mb)
tonyg@84 42 (let ((ma (monadize ma)))
tonyg@84 43 (if (determined? ma)
tonyg@84 44 ((monad-class-binder (monad-kind ma)) ma a->mb)
tonyg@84 45 (make-monad '_bind (list ma a->mb)))))
tonyg@68 46
tonyg@68 47 (define (return a)
tonyg@68 48 (make-monad '_return a))
tonyg@68 49
tonyg@84 50 (define (fail s)
tonyg@84 51 (make-monad '_fail s))
tonyg@84 52
tonyg@68 53 (define-syntax mlet*
tonyg@68 54 (syntax-rules ()
tonyg@68 55 ((_ () mexpN) mexpN)
tonyg@68 56 ((_ ((var mexp) rest ...) mexpN)
tonyg@68 57 (>>= mexp (lambda (var) (mlet* (rest ...) mexpN))))))
tonyg@68 58
tonyg@84 59 (define (wrong-mclass mclass m)
tonyg@84 60 (error "wrong monad-class" `((mclass ,mclass) (m ,m))))
tonyg@84 61
tonyg@84 62 (define (determine mclass m)
tonyg@68 63 (let continue ((m m))
tonyg@84 64 (let* ((m (monadize m))
tonyg@84 65 (kind (monad-kind m)))
tonyg@87 66 (if (determined? m)
tonyg@87 67 (if (eq? kind mclass)
tonyg@87 68 m
tonyg@87 69 (wrong-mclass mclass m))
tonyg@87 70 (continue
tonyg@87 71 (case kind
tonyg@87 72 ((_bind) ((monad-class-binder mclass)
tonyg@87 73 (continue (car (monad-value m)))
tonyg@87 74 (cadr (monad-value m))))
tonyg@87 75 ((_return) ((monad-class-returner mclass) (monad-value m)))
tonyg@87 76 ((_fail) ((monad-class-failer mclass) (monad-value m)))
tonyg@87 77 (else
tonyg@87 78 (error "invalid monad-kind" m))))))))
tonyg@68 79
tonyg@84 80 (define (monad-arg mclass)
tonyg@87 81 (lambda (m) (monad-value (determine mclass m))))
tonyg@68 82
tonyg@84 83 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
tonyg@84 84
tonyg@84 85 (define *list* (make-monad-class 'list
tonyg@84 86 (lambda (L f) (append-map (compose run-list f) (run-list L)))
tonyg@84 87 (lambda (x) (list x))
tonyg@84 88 (lambda (s) '())))
tonyg@84 89
tonyg@87 90 (define run-list (monad-arg *list*))
tonyg@84 91
tonyg@84 92 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
tonyg@84 93
tonyg@84 94 (define *io* (make-monad-class 'io
tonyg@94 95 (lambda (io1 f) (make-monad *io* (cons (io-action io1) f)))
tonyg@84 96 (lambda (v) (make-monad *io* (lambda () v)))
tonyg@84 97 error))
tonyg@84 98
tonyg@84 99 (define io-action (monad-arg *io*))
tonyg@84 100
tonyg@84 101 (define (run-io m)
tonyg@94 102 (let run-action ((action (io-action m)))
tonyg@94 103 (if (pair? action)
tonyg@94 104 (let ((previous-action (car action))
tonyg@94 105 (continuation (cdr action)))
tonyg@94 106 (run-io (continuation (run-action previous-action))))
tonyg@94 107 (action))))
tonyg@68 108
tonyg@68 109 (define (mdisplay x)
tonyg@84 110 (make-monad *io* (lambda () (display x) 'done)))
tonyg@68 111
tonyg@69 112 (define mread
tonyg@84 113 (make-monad *io* (lambda () (read))))
tonyg@69 114
tonyg@84 115 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
tonyg@68 116
tonyg@84 117 (define *state* (make-monad-class 'state
tonyg@84 118 (lambda (st1 f)
tonyg@84 119 (make-monad *state*
tonyg@84 120 (lambda (s0)
tonyg@87 121 (let* ((inp (run-st st1 s0))
tonyg@84 122 (v (car inp))
tonyg@84 123 (s1 (cdr inp)))
tonyg@84 124 (run-st (f v) s1)))))
tonyg@84 125 (lambda (a)
tonyg@84 126 (make-monad *state*
tonyg@84 127 (lambda (s0) (cons a s0))))
tonyg@84 128 error))
tonyg@84 129
tonyg@84 130 (define state-xformer (monad-arg *state*))
tonyg@84 131
tonyg@84 132 (define (run-st m initial)
tonyg@87 133 ((state-xformer m) initial))
tonyg@68 134
tonyg@68 135 (define sget
tonyg@84 136 (make-monad *state* (lambda (s0) (cons s0 s0))))
tonyg@68 137
tonyg@68 138 (define (sput a)
tonyg@84 139 (make-monad *state* (lambda (s0) (cons 'unit a))))
tonyg@69 140
tonyg@69 141 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
tonyg@69 142
tonyg@69 143 (define (mixed-monad-demo)
tonyg@69 144 (run-io (mlet* ((_ (mdisplay "Enter a number\n"))
tonyg@69 145 (n mread)
tonyg@69 146 (all-n (return (iota n)))
tonyg@69 147 (_ (mdisplay "Numbers: "))
tonyg@69 148 (_ (mdisplay all-n))
tonyg@69 149 (_ (mdisplay "\n")))
tonyg@69 150 (return 'nothing))))
tonyg@84 151
tonyg@84 152 (define oleg-example-mixed-monad
tonyg@84 153 (mlet* ((_ (mdisplay "Enter a number: "))
tonyg@84 154 (n mread)
tonyg@84 155 (all-n (return (iota n)))
tonyg@84 156 (evens (return (run-list (mlet* ((i all-n))
tonyg@84 157 (if (even? i)
tonyg@84 158 (return i)
tonyg@84 159 (fail "odd"))))))
tonyg@84 160 (_ (mdisplay "Computed "))
tonyg@84 161 (_ (mdisplay (length evens)))
tonyg@84 162 (_ (mdisplay " evens\n")))
tonyg@84 163 (return evens)))