DeBruijn Sequences pt.3 – The “Prefer Opposite” algorithm

2/12/2009

This is the third post of mine on DeBruijn sequences, and is in preparation for another post to come which I hope should be an interesting investigation into a possible parallel algorithm. The first two posts are here and here.
Read the rest of this article »

No Comments

The State Monad: a tutorial for the confused?

24/10/2009

I’ve written this brief tutorial on haskell’s State monad to help bridge some of the elusive gaps that I encountered in other explanations I’ve read, and to try to cut through all the sticky abstraction. This is written for someone who has a good understanding of the Maybe and List monads, but has gotten stuck trying to understand State. I hope it’s helpful!

The Data Declaration:

To understand a monad you look at it’s datatype and then at the definition for bind (>>=). Most monad tutorials start by showing you the data declaration of a State s a in passing, as if it needed no explanation:


newtype State s a = State { runState :: s -> (a, s) }

But this does need explanation! This is crazy stuff and nothing like what we’ve seen before in the list monad or the Maybe monad:

  1. The constructor State holds a function, not just a simple value like Maybe’s Just. This looks weird.
  2. Furthermore there is an accessor function runState with a weirdly imperative-sounding name.
  3. Finally, there are two free variables on the left side, not just one.

Yikes! Let’s try to get our head on straight and figure this out:

First of all the State monad is just an abstraction for a function that takes a state and returns an intermediate value and some new state value. To formalize this abstraction in haskell, we wrap the function in the newtype State allowing us to define a Monad instance.

Stepping back from the abstract and conceptual, what we have is the State constructor acting as a container for a function :: s -> (a,s), while the definition for bind just provides a mechanism for “composing” a function state -> (val,state) within the State wrapper.

Just as you can chain together functions using (.) as in (+1) . (*3) . head :: (Num a) => [a] -> a, the state monad gives you (>>=) to chain together functions that look essentially like :: a -> s -> (a,s) into a single function :: s -> (a,s).

Let’s bring the discussion back to actual code and try to make sure we understand those three points of weirdness outlined above. Here’s a stupid example of a function that can be “contained” in our state type:


-- look at our counter and return "foo" or "bar"
-- along with the incremented counter:
fromStoAandS :: Int -> (String,Int)
fromStoAandS c | c `mod` 5 == 0 = ("foo",c+1)
               | otherwise      = ("bar",c+1)

If we just wrap that in a State constructor, we’re in the State monad:


stateIntString :: State Int String
stateIntString = State fromStoAandS

But what about runState? All that does of course is give us the “contents” of our State constructor: i.e. a single function :: s -> (a,s). It could have been named stateFunction but someone thought it would be really clever to be able to write things like:


runState stateIntString 1

See, all we’ve done there is used runState to take our function (fromStoAandS) out of the State wrapper; it is then applied it to it’s initial state (1). We would do this runState business after building up our composed function with (>>=), mapM, etc.

That leaves point 3 unanswered. Let’s start exploring the instance declaration for State.

The Instance Declaration

We’ll start with the first line:


instance Monad (State s) where

We create a Monad instance for (State s) not State. You can think of this as a partially-applied type, which is equivalent to a partially applied function:

(State) <==> (+)
(State s) <==> (1+)
(State s a) <== (1+2)

So (State s) is the m in our m a. This means the type of our state will remain the same as we compose our function with (>>=), whereas the intermediate values (the as) may well change type as they move through the chain.

Before we move on to the meat of the instance declaration, I'd like to get your mind calibrated to look at the definitions for return and (>>=):

Whenever you see m a, as in

return :: (Monad m) => a -> m a

...remember that m a is actually

State s a

...and when you remember (State s a), think

(s -> (s,a)).

So in your mind, m a becomes function :: s -> (a,s) everywhere you see it. Just forget about the silly State wrapper (the compiler does)!

The definition of return and Bind

Let's wet out feet with the definition for return:


    return a = State $ \-> (a, s)

All return does is take some value a and make a function that takes a state value and returns (value, state value). If we ignore the whole State wrapping business, then return is just (,) :: a -> b -> (a, b)

Now recall the definition of bind:


(>>=:: (Monad m) => m a -> (a -> m b) -> m b

Which in our case is:


(>>=::  State s a        -> 
          (a -> State s b) -> 
          State s b

And which is just a silly abstraction for the super special function composition that's going on, which looks like:


(>>=::  (s -> (a,s))       -> 
          (a -> s -> (a,s))  -> 
          (s -> (b,s))

So on the left hand side of (>>=) is a function that takes some initial state and produces a (value,new_state). On the right hand side is a function that takes that value and that new_state and generates it's own (new_value, newer_state). The job of bind is simply to combine those two functions into one bigger function from the initial state to (new_value,newer_state), just like the simple function composition operator (.) :: (b -> c) -> (a -> b) -> a -> c

At this point, we can show you bind's definition:


    m >>= k  = State $ \-> let
        (a, s') = runState m s
        in runState (k a) s'

You can work through that on your own, keeping in mind that we're doing function composition here. The main thing to remember is that the s at the top, right after State, won't actually be bound to a value until we unwrap the function with runState and pass it the initial state value, at which point we can evaluate the entire chain.

A Final Note About The State Monad with do Notation

State is often used like this:


stateFunction :: State [a] ()
stateFunction = do x <- pop
                   pop
                   push x

Remember that the functions above are desugaring to m >>= \a-> f... or if there is no left arrow on the previous line: m >>= \_-> f... That a in there is an intermediate value, the fst in the tuple. The push function might look like:


push :: State [a] ()
push a = State $ \as -> (() , a:as)

The function doesn't return any meaningful a value, so we don't bind it by using the <-. For more work with do notation and some fine pictures, see Bonus's post on something awful.

3 Comments

Cracking a Lock in Haskell with the De Bruijn sequence, pt. 2

29/09/2009

For this post I will rework the Prefer One algorithm from
the previous post
so that it is much more efficient. We will
add words to a Patricia Tree-like dictionary as we see them,
passing the tree along in the State monad; to check if a new
word has been seen we simply check in the tree, rather than
in the array.

First, a little boilerplate…


> module Main
>     where
>
> import Data.Array
> import Data.List(isInfixOf, tails)
>
> import Control.Monad.State
> import Control.Arrow

NEW IMPLEMENTATION:

———————————————————————-

In the previous implementation, to check if the word formed
by adding a one has been seen, we had to iterate through each
of the previous bits in the array, checking words.

For example for words of length 3, finding the 7th bit (?)
by checking if 111 has already been seen:

        /-----\  ==>  111
0 0 0 1 1 1 (1)...
\----/         000 == 111  No
  \----/       001 == 111  No
    \----/     011 == 111  No
      \----/   111 == 111  Yes, so this bit must be (0)

This is extremely inefficient. What we want is to be able to
store all the previous words that we’ve encountered in an easily-
searchable data structure.

In the example above, we would like the three words that we’ve
seen to be stored in what might be called a Trie, so that our
search instead looks like the following:

       /\
      0  1         1 - in tree, go right
     / \  \
    0   1  1       1 - in tree, go right
   / \   \  \
  0   1   1  1     1 - in tree, we've already seen 111,
                       so the last bit must be 0

Our new data structure will look like this:


> data Tree = Bs Tree Tree  -- Bs (zero_bit) (one_bit)
>           | X -- incomplete word
>           | B -- final bit of word
>           deriving Show

We’ll need to build a new tree from a list of bits, appending
a final bit (1, except for the initial tree):


> treeWithFinal1 = mkTree True
> treeWithFinal0 = mkTree False
>
>
> mkTree :: Bit -> [Bit] -> Tree
> mkTree p = foldr mkBranch (if p then Bs X B else Bs B X)  
>     where mkBranch b | b         = Bs X      --1
>                      | otherwise = flip Bs X --0


Finally, here is our new algorithm. The tree is passed in the
State monad, through the use of mapM. The state monad is a little
tricky sometimes:


> preferOneV2 :: Int -> [ Bit ]
> preferOneV2 n = 
>     let upB = 2^n
>         -- the whole bit sequence (one period):
>         bs =  take upB (replicate n False ++ bs')
>         (wp0:wordPrefixes) = [ take (n-1) w | w <- tails bs ]
>        
>         -- pass our Tree around in the State monad
>         state0 = treeWithFinal0 wp0
>        
>         -- thisBit is partially applied, after which we wrap the
>         -- function in a State constructor to make our :: m a
>         bsM'  = mapM (State . thisBit) wordPrefixes
>         (bs',tree) = runState bsM' state0
>
>       -- an infinite stream is returned... because I can:          
>    in cycle bs


With the following function, after we apply it to the word we’re searching
for, it becomes a function :: state -> (val,state), suitable for the
State monad:

Takes a list of the last n-1 Bits (Bools) and traverses a Tree which we’ve
been using to keep track of the words we’ve already seen. We fold the Bit
list into the tree. When we get to the endo of the list, we look for a One.
We return the new bit as well as the new Tree:


> thisBit :: [ Bit ] -> Tree -> (Bit, Tree)

We’re at a Zero bit,


> thisBit (False:bs) (Bs X o) = (True, Bs (treeWithFinal1 bs) o) -- last bit must be 1
> thisBit (False:bs) (Bs z o) = (id *** flip Bs o) (thisBit bs z)

…a One bit,


> thisBit (True:bs) (Bs z X) = (True, Bs z (treeWithFinal1 bs)) 
> thisBit (True:bs) (Bs z o) = (id *** Bs z) (thisBit bs o)

…or else propose a One for the last bit:


> thisBit [] (Bs _ o) = (b , (Bs z B)) 
>     -- we know that if the One bit has been seen (B) then we must
>     -- place a zero. we assume then that the Zero bit is (X):
>     where (b, z) = case o of 
>                         -- this bit = 1, Zero branch = nil
>                         X -> (True,  X) -- 1
>                         -- this bit = 0, Zero branch = last word bit
>                         _ -> (False, B) -- 0


TEST FUNCTIONS:

———————————————————————-

This code is copied from the previous post:

We use Bool for bits, where False ==> 0, True ==> 1:


> type Bit = Bool

Our garage-door lock model for testing the function:


> type Combo    = [ Bit ]
> type Receiver = Combo -> Bool

True means access granted:


> programReceiver :: Combo -> Receiver
> programReceiver = isInfixOf 

Test out our function:


> main =  let secretCode = [True,True,False,False,True,
>                           False,True,False,True,True]
>             receiver = programReceiver secretCode
>             crackingStream = preferOneV2 10
>
>          in if receiver crackingStream
>             then print "WE'RE IN!"
>             else print "...bugs"
>

Stay tuned for one more post on these algorithms.

2 Comments