hackett icon indicating copy to clipboard operation
hackett copied to clipboard

A 'State' monad, and corresponding additions to the code by 'iitalic'

Open aaronmcdaid opened this issue 7 years ago • 3 comments

Maybe I've reinvented the wheel, but as an exercise here is an implemention of the State monad (state.rkt) with the relevant get, put and modify operations.

Also, based on that, I've added some relevant functions to random.rkt for drawing random numbers through State PRNG:

draw-double : (State PRNG Double)
draw-range : {Integer -> Integer -> (State PRNG Integer)}
draw-below : {Integer -> (State PRNG Integer)}

Demo of (State Integer):

(def stateInteger : (State Integer (List Integer))
  (do
    [i1 <- get]                  ; query the initial state
    (modify (+ 10))              ; modify the internal state, adding 10 to it
    [i2 <- get]                  ; query again
    (modify (+ 10))              ; modify again
    (pure {i1 :: i2 :: nil}))))) ; return the two intermediate internal states

(main {(runState stateInteger 42) & show & println})

This should demo this new functionality for random:

(def example-of-the-draw-functions : (State PRNG (List Double))
  (do
    [d0 <- draw-double]
    [d1 <- draw-double]
    (put (prng/seeded 1337))
    [d2 <- draw-double]
    [d3 <- draw-double]
    (put (prng/seeded 1337))
    [d4 <- draw-double]
    [d5 <- draw-double]
    (pure {d0 :: d1 :: d2 :: d3 :: d4 :: d5 :: nil })))

(main
  (do

    ; In IO, get a PRNG seeded by the current time:
    [prng <- make-io-prng]

    (println " First two numbers in the following are different, and different on each run of this program, confirming the IO-seed PRNG is \"proceeding\",")
    (println " and the third and fifth are the same, as as the fourth and sixth, to show the 'put' has reseeded deterministically")

    ; run an example State computation with the prng we just got from IO
  {(runState example-of-the-draw-functions prng) & fst & show & println}

    ; And finally, with a deterministally-seeded PRNG (i.e. not created in IO)
  {(runState example-of-the-draw-functions (prng/seeded 1337)) & fst & show & println}))

aaronmcdaid avatar Oct 20 '17 02:10 aaronmcdaid

By the way, I'm relatively new to working with others on github. I've just realised that maybe I should have sent a pull request to @iitalics instead, as this extends their code. I don't really know the etiquette around these things

aaronmcdaid avatar Oct 20 '17 02:10 aaronmcdaid

In an ideal world, I think the right thing to do here would be to define a StateT transformer, then define a RandomT transformer as a newtype-ish thing around StateT, with a variety of instances derived using something like GeneralizedNewtypeDeriving. However, Hackett has neither newtypes nor GND, so just writing StateT for now seems reasonable. I would put it in hackett/monad/state, however, much like how ErrorT and ReaderT are already defined.

lexi-lambda avatar Oct 26 '17 20:10 lexi-lambda

I haven't had any time for Hackett in recent weeks, partly because of a C++ conference I attended (Meeting C++ 2017, it was fantastic!). But maybe I will again in a few weeks. I'm going to Nepal on Thursday for three weeks trekking up to 5000m. In future, I may be able to follow up on this, if nobody else does so first. Thanks again for the excellent feedback :-)

aaronmcdaid avatar Nov 13 '17 15:11 aaronmcdaid