Generalized monad interface

This commit is contained in:
Correl Roush 2014-04-24 15:33:28 -04:00
parent ecd20c50ec
commit c0441ca1e7
5 changed files with 59 additions and 38 deletions

13
include/monads.lfe Normal file
View file

@ -0,0 +1,13 @@
(defmacro do args
(let ((monad (car args))
(statements (cdr args)))
(monad:do-transform monad statements)))
(defmacro >>= (monad m f)
`(: ,monad >>= ,m ,f))
(defmacro >> (monad m1 m2)
`(: ,monad >>= ,m1 (lambda (_) ,m2)))
(defmacro return (monad expr)
`(: ,monad return ,expr))

14
src/maybe-monad.lfe Normal file
View file

@ -0,0 +1,14 @@
(defmodule maybe-monad
(behaviour monad)
(export (>>= 2)
(return 1)
(fail 1)))
(defun >>=
(('nothing f)
'nothing)
(((tuple 'just x) f)
(funcall f x)))
(defun return (x) (tuple 'just x))
(defun fail (_) 'nothing)

View file

@ -1,25 +0,0 @@
(defmodule maybe
(export all))
(defun my-adder (x y)
(+ x (+ y 1)))
(defun >>=
(('nothing f)
'nothing)
(((tuple 'just x) f)
(funcall f x)))
(defun >> (a b)
(>>= a (lambda (_) b)))
(defun return (x) (tuple 'just x))
(defun fail (_) 'nothing)
(defun do-statement
(((cons h '())) h)
(((cons (list f '<- m) t)) (list ': 'maybe '>>=
m
(list 'lambda (list f) (do-statement t))))
(((cons h t)) (list ': 'maybe '>> h (do-statement t)))
)

17
src/monad.lfe Normal file
View file

@ -0,0 +1,17 @@
(defmodule monad
(export (behaviour-info 1)
(do-transform 2)))
(defun behaviour-info
(('callbacks) (list #(>>= 2)
#(return 1)
#(fail 1)))
((_) 'undefined))
(defun do-transform
((monad (cons h '())) h)
((monad (cons (list f '<- m) t)) (list ': monad '>>=
m
(list 'lambda (list f) (do-transform monad t))))
((monad (cons h t)) (list '>> monad h (do-transform monad t)))
)

View file

@ -1,4 +1,4 @@
(defmodule unit-maybe-tests (defmodule unit-maybe-monad-tests
(export all) (export all)
(import (import
(from lfeunit-util (from lfeunit-util
@ -6,27 +6,27 @@
(check-wrong-assert-exception 2)))) (check-wrong-assert-exception 2))))
(include-lib "deps/lfeunit/include/lfeunit-macros.lfe") (include-lib "deps/lfeunit/include/lfeunit-macros.lfe")
(include-lib "include/maybe.lfe") (include-lib "include/monads.lfe")
(deftest bind-nothing (deftest bind-nothing
(is-equal 'nothing (is-equal 'nothing
(maybe:>>= 'nothing (>>= maybe-monad 'nothing
(lambda (x) (+ 5 x))))) (lambda (x) (+ 5 x)))))
(deftest bind-nothing-error (deftest bind-nothing-error
(is-equal 'nothing (is-equal 'nothing
(maybe:>>= 'nothing (>>= maybe-monad 'nothing
(lambda (_) (error 'bad-func))))) (lambda (_) (error 'bad-func)))))
(deftest bind-five (deftest bind-five
(is-equal 10 (is-equal 10
(maybe:>>= (tuple 'just 5) (>>= maybe-monad (tuple 'just 5)
(lambda (x) (+ 5 x))))) (lambda (x) (+ 5 x)))))
(deftest bind-fold (deftest bind-fold
(is-equal #(just 3) (is-equal #(just 3)
(let ((minc (lambda (x) (maybe:return (+ 1 x)))) (let ((minc (lambda (x) (return maybe-monad (+ 1 x))))
(bind (lambda (f m) (maybe:>>= m f)))) (bind (lambda (f m) (>>= maybe-monad m f))))
(lists:foldr bind (lists:foldr bind
#(just 0) #(just 0)
(list minc (list minc
@ -35,15 +35,17 @@
(deftest >> (deftest >>
(is-equal #(just 3) (is-equal #(just 3)
(maybe:>> #(just 5) #(just 3)))) (>> maybe-monad #(just 5) #(just 3))))
(deftest do-bindings (deftest do-bindings
(is-equal #(just 3) (is-equal #(just 3)
(do (a <- #(just 1)) (do maybe-monad
(a <- #(just 1))
(b <- #(just 2)) (b <- #(just 2))
(maybe:return (+ a b))))) (return maybe-monad (+ a b)))))
(deftest do-nobindings (deftest do-nobindings
(is-equal #(just 3) (is-equal #(just 3)
(do #(just 5) (do maybe-monad
#(just 5)
#(just 3)))) #(just 3))))