I just built a state monad "object", and would like to be able to bind steps to variables, and link up successive computations, as if with bind
/>>=
, like how haskell works with monads, and like how clojure's various monad libs work. Here's my monad:
(def state-m
(let [pure (fn [x] (fn [s] [x s]))
bind (fn [mv mf] (fn [s] ; mv :: s -> (a, s) || mf :: a -> (s -> (b, s))
(let [[a s'] (mv s)]
((mf a) s'))))
then (fn [mv mf] (bind mv (fn [_] mf))) ; eg `>>`
get-s (fn [s] [s s])
put-s (fn [s] (fn [_] [nil s]))
update-s (fn [f] (fn [s] [nil (f s)]))] ; f :: s->s
{:pure pure
:bind bind
:then then
:get-s get-s
:put-s put-s
:update-s update-s}))
Here's an example of using it:
(let [pure (:pure state-m)
>>= (:bind state-m)
>> (:then state-m)
get-s (:get-s state-m)
put-s (:put-s state-m)
update-s (:update-s state-m)]
(and (= [:v :s] ((pure :v) :s))
(= [5 :state] ((>>= (pure 3)
(fn [x] (pure (+ 2 x))))
:state))
(= [3 3] ((>>= get-s (fn [n] (pure n))) 3))
(= [4 5] ((>>= get-s (fn [n] (>> (put-s (+ n 1))
(pure n)))) 4))
(= [4 8] ((>>= get-s (fn [n] (>> (update-s (partial * 2))
(pure n)))) 4))))
It's a little verbose. I don't mind right now, but I would like to be able to use do
syntax, eg:
(my-do [a (get-s)
_ (put-s 33)
b (* 2 a)
_ (put-s 44)
c (* a b)]
c)
Or even some thready kind of function (although I know clj's threads are macros), eg:
(my-> (pure 1)
(>>= (fn [a] ...))
(>>= (fn [b] ...))
(>> (* a b))) ; notice non-local bindings `a` and `b` are available here
I can look at existing monad libs in clojure for how to accomplish this with macros, and that's fine. I'm curious how this could be achieved without the use of macros, even if just an exercise to experiment with how it could be done.
I am aware of binding
s in clojure, but haven't used them. How could I use this, or other appropriate constructs to achieve do
ish syntax?
Neither of those two styles are possible without a macro. Macros are the construct for introducing new syntactic structures in any lisp, so if you want a new syntax macros are the way to go.