Skip to content

Instantly share code, notes, and snippets.

@mgreenly
Created May 7, 2014 01:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mgreenly/808e8fb744cb59d76668 to your computer and use it in GitHub Desktop.
Save mgreenly/808e8fb744cb59d76668 to your computer and use it in GitHub Desktop.
; monads
;
; references:
; http://onclojure.com/2009/03/05/a-monad-tutorial-for-clojure-programmers-part-1/
; http://www.intensivesystems.net/tutorials/monads_101.html
; http://en.wikipedia.org/wiki/Monad_(functional_programming)
; http://moonbase.rydia.net/mental/writings/programming/monads-in-ruby/00introduction.html
; alternate syntax for make monad
(define-syntax return
(syntax-rules ()
((return m v)
(make m :value v))
((return m)
(make m))))
; alternate syntax for bind
(define-syntax >>=
(syntax-rules ()
((>>= function monad)
(bind function monad))))
;
; NOTHING
;
(define-class <nothing> () ())
(define-method value-of ((_ <nothing>)) 'nothing)
(define-method bind (function (monad <nothing>))
(return <nothing>))
(define nothing (return <nothing>))
;
; MAYBE
;
(define-class <maybe> ()
((value :init-keyword :value :accessor value-of)))
(define-method bind (function (monad <maybe>))
(let ((result (function (value-of monad))))
(if result
(return <maybe> result)
nothing)))
(define (f n) (+ n n))
(define (g n) (* n n))
(define (h n) (if (> n 10) #f n))
;
(f (g (h 3))) ; -> 18
((compose f g h) 3) ; -> 18
(bind f (bind g (bind h (return <maybe> 3)))) ; -> <maybe> 18
;
; bind composes functions that expect basic values so that they
; work with monadic values and returns the result as a monadic
; value so it's ready for the next bind in the chain.
;
; Monadic Parser
; This is PEG grammar (find references)
;seq takes a series of rules and expects each in order. If any rule
;fails the seq fails. This is essentially the maybe monad. It would
;be defined as syntax and look like this
(define (digits stream)
(seq stream
(digit
digit)))
;the seq syntax would expand into to someting like this
(define (digits stream)
(bind digit (bind digit stream)))
;takes n rules and returns the result of the first rule that does not return
;false. if they all return false it returns false.
(define (sel stream . rules)
rules)
;returns zero or more of rule
(define (rep* stream . rule)
rule)
;returns one or more of rule
(define (rep+ stream . rule)
rule)
;returns zero or one of rule
(define (rep? stream . rule)
rule)
;returns rule if pred follows it. does not consume pred
(define (and? stream rule pred)
(rule))
;returns rule if pred does not follow it. does not consume pred
(define (not? stream rule pred)
(rule)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment