2 ms·
How does Clojure handle piping state through a series of functions? Is there anything like monads in Haskell to abstract it away? Haskell makes immutable data a
by thinkpad20 12y ago
How does Clojure handle piping state through a series of functions? Is there anything like monads in Haskell to abstract it away? Haskell makes immutable data a little bit more tenable because you don't need to explicitly thread your state. How does Clojure handle this? Does it provide escape hatches for mutable state, perhaps restricted to using Java libraries?
- weavejester 12y agoClojure has libraries that implement monads, but these aren't often used for threading state. I can't quite place my finger on why, but in Clojure I rarely find myself reaching for something like the state monad, as I would in Haskell. Clojure tends to view mutability as a concurrency problem, and the tools it provides to deal with mutability, such as atoms, refs, agents, channels and so forth, are not mechanisms to avoid mutation, as to provide various guarantees that restrict it in some fashion. It might be that in the cases where I'd use a state monad in Haskell, in Clojure I might instead use an atom. They're in no way equivalent, but they have some overlapping use-cases.
- oskarkv 12y agoFor very simple cases there are the threading macros, `->` et al., that you can use like this: (-> state (assoc :a val) (update-in [:b :c] f args) (dissoc :d) (some-other-fn args)) where :a - :d are keys. Or you could use monads in much the same way as you would in Haskell; there are libs for that. Or you could write a new macro (or maybe even function) that does exactly what you want. I did that for a game. It looked like this: (call-update-fns game-state hook (update-monster-positions) (update-monster-ai) (let-characters-attack) (some-other-stuff)) It would thread the game-state (immutable) through all the functions, and call hook (a function) in between all the functions to send network messages and stuff (to minimize latency), and also collect and return new events that the functions created that I needed to handle (e.g. someone died when the characters attacked). It's almost like the state monad but not quite.
- muhuk 12y agoAnd there's synthread[1] for more complex cases: (-> {:a 1 :b 2} (->/assoc :a inc) (->/as {:keys [b]} (->/when (> b 10) (->/assoc :large-b true)))) 1: https://github.com/LonoCloud/synthread https://github.com/LonoCloud/synthread