Monad in Scheme (2)

ukaiさんが、書いて下さった。なるほど...素晴らしいっす!という事で、もう少し詰めてみることにする。Monad in Scheme (1)での僕の書き方は少し曖昧だったので、モナドが満たすべき3つの法則(モナド則)を満たすように書き直してみた。とはいっても、ukaiさんのを少しいじくっただけなので、基本的なアイデアは同じ。ちなみに、Haskellでの\x -> f xは、Schemeでの(lambda (x) (f x))で有る。これを満たすようにモナド関数return, >>=を書いてみた。

  • The monad laws
    • (return x) >>= f == f x
    • m >>= return == m
    • (m >>= f) >>= g == m >>= (\x -> f x >>= g)
; Monad Function
(define (>>= val args)
  (let ((m ((car args) val))
        (rest (cdr args)))
    (if (null? rest)
        m
        (apply m rest))))

(define (return val)
  (lambda (op . args)
    (op val args)))

; Util
(define (monad-val monad)
  (monad (lambda (val . args) val)))

; User Func                                                                                                                                    
(define (inc n) (return (+ n 1)))
(define (inc2 n) (return (+ n 2)))

; The monad laws                                                                                                                                       
; 1. ((return x) >>= f) == (f x)                                                                                                               
(print (monad-val ((return 1) >>= inc)))
(print (monad-val (inc 1)))

; 2. (m >>= return) == m                                                                                                                   
(print (monad-val ((return 1) >>= return)))
(print (monad-val (return 1)))

; 3. ((m >>= f) >>= g) == (m >>= (lambda (x) ((f x) >>= g)))                                                                                   
(print (monad-val (((return 1) >>= inc) >>= inc2)))
(print (monad-val ((return 1) >>= (lambda (x) ((inc x) >>= inc2)))))

Monad in Scheme (3) : Maybeモナド

そうすると、Maybeモナドも書けるよねという話。Maybeモナドというのは、モナド計算の過程で計算がfaiする可能性がある場合に使われるもので、途中で計算がfailするとNothingという値がモナド計算の最後まで伝播していくというモナドである。下記コードのTestの2番目を見ていただけるとイメージが掴めると思う。詳しくはall about monad : Maybeというモナドを参考の事。

; Monad Function
(define (>>= val args)
  (let ((m (if (eq? val 'Nothing)
               (return 'Nothing)
               ((car args) val)))
        (rest (cdr args)))
    (if (null? rest)
        m
        (apply m rest))))

(define (return val)
  (lambda (op . args)
    (op val args)))

(define Nothing (gensym))

; Util                                                                                                                                         
(define (monad-val monad)
  (monad (lambda (val . args) val)))

; User Func                                                                                                                                    
(define (inc n) (return (+ n 1)))
(define (fail n) (return 'Nothing))

; Test                                                                                                                                         
(print (monad-val ((return 1) >>= inc >>= inc  >>= inc)))
(print (monad-val ((return 1) >>= inc >>= fail >>= inc)))

しかし、Monad in Schemeという内容モロかぶりなページを発見。でも、こっちの方が書き方的に格好良いな。説明は向こうの方が分かり易いけど^_^;