Account Options

  1. Sign in
The old Google Groups will be going away soon, but your browser is incompatible with the new version.
Google Groups Home
« Groups Home
Message from discussion Should I better use a state monad (and how)?

Received: by 10.101.137.21 with SMTP id p21mr3924421ann.26.1334561815716;
        Mon, 16 Apr 2012 00:36:55 -0700 (PDT)
X-BeenThere: clojure@googlegroups.com
Received: by 10.236.114.50 with SMTP id b38ls8080865yhh.1.gmail; Mon, 16 Apr
 2012 00:36:41 -0700 (PDT)
MIME-Version: 1.0
Received: by 10.236.115.169 with SMTP id e29mr730181yhh.16.1334561800993; Mon,
 16 Apr 2012 00:36:40 -0700 (PDT)
Authentication-Results: ls.google.com; spf=pass (google.com: domain of
 a...@malloys.org designates internal as permitted sender)
 smtp.mail=a...@malloys.org; dkim=pass
 header...@malloys.org
Received: by x17g2000yqj.googlegroups.com with HTTP; Mon, 16 Apr 2012 00:36:40
 -0700 (PDT)
Date: Mon, 16 Apr 2012 00:36:40 -0700 (PDT)
In-Reply-To: <22375032.995.1334546721535.JavaMail.geo-discussion-forums@vbmq16>
References: <22375032.995.1334546721535.JavaMail.geo-discussion-forums@vbmq16>
User-Agent: G2/1.0
X-HTTP-UserAgent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:11.0) Gecko/20100101 Firefox/11.0,gzip(gfe)
Message-ID: <cfd950ea-53d1-4fba-a531-1f91f932c57a@x17g2000yqj.googlegroups.com>
Subject: Re: Should I better use a state monad (and how)?
From: Alan Malloy <a...@malloys.org>
To: Clojure <clojure@googlegroups.com>
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

On Apr 15, 8:25=A0pm, Nicolas Buduroi <nbudu...@gmail.com> wrote:
> I'm working on a turn-based game and I'm looking for a good way to manage
> states. In the game each turn is composed of multiple phases. I started b=
y
> using atoms for the phases field (this is a sequence of functions) in a
> record and realized that it wouldn't be ideal to keep track of states in
> the case where I'd need to keep a snapshot of every phases. Here's the
> original code I had:
>
> (defrecord Game [phases]
> =A0 (next-phase [this]
> =A0 =A0 (stop-timer)
> =A0 =A0 (swap! phases #(conj (vec (rest %)) (first %)))
> =A0 =A0 (log :info "change phase to %s" (key (first @phases)))
> =A0 =A0 (start-phase this))
>
> I then started to think that this would be a good opportunity to use a
> state monad. I've tried to reimplement the above code using the algo.mona=
ds
> library but the result was less than satisfactory (probably due to my own
> shortcoming), here's the monadic version:
>
> (defrecord Game [phases]
>
> =A0 (next-phase [this]
> =A0 =A0 (->
> =A0 =A0 =A0((domonad state-m
> =A0 =A0 =A0 =A0 [_ (fn [s] (stop-timer) [s s])
> =A0 =A0 =A0 =A0 =A0_ (update-state
> =A0 =A0 =A0 =A0 =A0 =A0 (fn [s]
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 (update-in s [:phases]
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0#(conj (vec (rest %)) =
(first %)))))
> =A0 =A0 =A0 =A0 =A0_ (fn [s]
> =A0 =A0 =A0 =A0 =A0 =A0 =A0(log :info "change phase to %s" (key (first (:=
phases s)))) [s s])]
> =A0 =A0 =A0 =A0 nil)
> =A0 =A0 =A0 state)
> =A0 =A0 =A0second
> =A0 =A0 =A0start-phase))
>
> As my code probably doesn't need the full power of the state monad, I tri=
ed
> to write a lighter-weight version using the following macro:
>
> (defmacro >> [& state-and-forms]
> =A0 (reduce #(list (if ('#{fn fn*} (first %2))
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0%2
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0`(fn [s#] ~%2 s#)) %)
> =A0 =A0 =A0 =A0 =A0 state-and-forms))
>
> Which let me write:
>
> =A0 (next-phase [state]
> =A0 =A0 (>> state
> =A0 =A0 =A0(stop-timer)
> =A0 =A0 =A0(fn [s] (update-in s [:phases] #(conj (vec (rest %)) (first %)=
)))
> =A0 =A0 =A0#(do (log :info "change phase to %s" (key (first (:phases %)))=
) %)
> =A0 =A0 =A0#(start-phase %)))
>
> With some more helper macro this version looks promising. In the end I
> wonder if there's some Clojure feature I'm overlooking or if I should
> rethink the whole solution? Is there a better way to accomplish this?

 #(conj (vec (rest %)) (first %)) is a really awful way to implement a
queue. Just use clojure.lang.PersistentQueue, which works with the