Monad Operations¶
hymn.operations
provide operations and macros for monad computations
Macros¶

domonad [bindingforms expr]
macro for sequencing monadic computations, with automatic return
=> (require hymn.operations)
=> (import [hymn.types.maybe [Just]])
=> (domonad [a (Just 41)] (inc a))
Just(42)

domonadm [bindingforms expr]
macro for sequencing monadic computations, a.k.a do notation in haskell
=> (require hymn.operations)
=> (import [hymn.types.maybe [Just]])
=> (domonad [a (Just 41)] (mreturn a))
Just(42)

domonadwith [monad bindingforms expr]
macro for sequencing monadic composition, with said monad as default.
useful when the only binding form is
:when
, we do not know which monad we are working with otherwise
=> (require hymn.operations)
=> (import [hymn.types.maybe [maybem]])
=> (domonadwith maybem [:when true] 42)
Just(42)
=> (domonadwith maybem [:when false] 42)
Nothing
All do monad macros support :let
binding, like this:
=> (require hymn.operations)
=> (import [hymn.types.maybe [Just]])
=> (defn half [x]
... (domonad
... [:let [[two 2]]
... a x
... :let [[b (/ a two)]]]
... b))
=> (half (Just 42))
Just(21.0)
All do monad macros support :when
if the monad is of type
MonadPlus
.
=> (require hymn.operations)
=> (import [hymn.types.maybe [maybem]])
=> (defn div [a b] (domonadwith maybem [:when (not (zero? b))] (/ a b)))
=> (div 1 2)
Just(0.5)
=> (div 1 0)
Nothing

mfor [[n seq] &rest expr]
macro for sequencing monadic actions
=> (require hymn.operations)
=> ;; with simple monad, e.g. maybe
=> (import [hymn.types.maybe [maybem]])
=> (mfor [a (range 3)] (maybem.unit a))
Just([0, 1, 2])
=> ;; with reader monad
=> (import [hymn.types.reader [<]])
=> (def readers
... (mfor [a (range 5)]
... (print "create reader" a)
... (< a)))
create reader 0
create reader 1
create reader 2
create reader 3
create reader 4
=> (.run readers [11 12 13 14 15 16])
[11, 12, 13, 14, 15]
=> (.run readers "abcdefg")
['a', 'b', 'c', 'd', 'e']
=> ;; with writer monad
=> (import [hymn.types.writer [tell]])
=> (.execute (mfor [a (range 1 101)] (tell a)))
5050

mwhen [test mexpr]
conditional execution of monadic expressions

withmonad [monad &rest exprs]
provide default function mreturn as the unit of the monad
=> (require hymn.operation)
=> (import [hymn.types.maybe [maybem]])
=> (withmonad maybem (mwhen (even? 1) (mreturn 42)))
Just(None)
=> (withmonad maybem (mwhen (even? 2) (mreturn 42)))
Just(42)

monadcomp [expr bindingforms &optional condition]
different syntax for
domonad
, in the style of list/dict/set comprehensions, thecondition
part is optional and can only be used withMonadPlus
as indomonad
=> (require hymn.operations)
=> (import [hymn.types.maybe [Just]])
=> (monadcomp (+ a b) [a (Just 1) b (Just 2)])
Just(3)
=> (monadcomp (/ a b) [a (Just 1) b (Just 0)] (not (zero? b)))
Nothing
=> (import [hymn.types.list [listm]])
=> (list (monadcomp (/ a b) [a (listm [1 2]) b (listm [4 8])]))
[0.25, 0.125, 0.5, 0.25]
=> (list (monadcomp (/ a b) [a (listm [1 2]) b (listm [0 1])] (not (zero? b))))
[1.0, 2.0]
Reader Macros¶

^ [f]
lift()
reader macro,#^f
is expanded to(lift f)
=> (require hymn.operations)
=> (import [hymn.types.maybe [Just Nothing]])
=> (#^+ (Just 1) (Just 2))
Just(3)
=> (#^+ (Just 1) Nothing)
Nothing

= [value]
reader macro for
mreturn
, theunit
inside domonad macros,#=v
is expanded to(mreturn v)
=> (require hymn.operations)
=> (import [hymn.types.maybe [Just maybem]])
=> (domonadwith maybem [a #=1 b #=2] (+ a b))
Just(3)
=> (domonadm [a (Just 1)] #=(inc a))
Just(2)
Operation on Monads¶

hymn.operations.
k_compose
(*monadic_funcs)¶ righttoleft Kleisli composition of monads.

<=<
alias of
k_compose()
=> (import [hymn.operations [kcompose <=<]])
=> (import [hymn.types.maybe [Just Nothing]])
=> (defn mdouble [x] (if (numeric? x) (Just (* x 2)) Nothing))
=> (defn minc [x] (if (numeric? x) (Just (inc x)) Nothing))
=> (def +1*2 (kcompose mdouble minc))
=> (+1*2 1)
Just(4)
=> (def *2+1 (<=< minc mdouble))
=> (*2+1 2)
Just(5)
=> (*2+1 "two")
Nothing

hymn.operations.
k_pipe
(*monadic_funcs)¶ lefttoright Kleisli composition of monads.

>=>
alias of
k_compose()
=> (import [hymn.operations [kpipe >=>]])
=> (import [hymn.types.maybe [Just Nothing maybe]])
=> (def mint (maybe int))
=> (defn marray [n] (if (> n 0) (Just (* [0] n)) Nothing))
=> (def makearray (kpipe mint marray))
=> (makearray 0)
Nothing
=> (makearray 3)
Just([0, 0, 0])
=> (def makearray (>=> mint marray))
=> (makearray 2)
Just([0, 0])

hymn.operations.
lift
(f)¶ promote a function to a monad
=> (import [hymn.operations [lift]])
=> (import [hymn.types.maybe [Just]])
=> (def m+ (lift +))
=> (m+ (Just 1) (Just 2))
Just(3)

hymn.operations.
m_map
(mf, seq)¶ map monadic function
mf
to a sequence, then execute that sequence of monadic values

mmap
alias of
m_map()
=> (import [hymn.operations [mmap]])
=> (import [hymn.types.maybe [maybem]])
=> (mmap maybem.unit (range 5))
Just([0, 1, 2, 3, 4])
=> (mmap (maybem.monadic inc) (range 5))
Just([1, 2, 3, 4, 5])
=> (import [hymn.types.writer [tell]])
=> (.execute (mmap tell (range 1 101)))
5050

hymn.operations.
replicate
(n, m)¶ perform the monadic action n times, gathering the results
=> (import [hymn.operations [replicate]])
=> (import [hymn.types.list [listm]])
=> (list (replicate 2 (listm [0 1])))
[[0, 0], [0, 1], [1, 0], [1, 1]]

hymn.operations.
sequence
(m_values)¶ evaluate each action in the sequence, and collect the results
=> (import [hymn.operations [sequence]])
=> (import [hymn.types.writer [tell]])
=> (.execute (sequence (map tell (range 1 101))))
5050