The Russian Doll Pattern in Haskell [ 2010-05-12 05:56:18 UTC ]

The Russian Doll Pattern occurs when functions replace themselves. The example in that link uses javascript, but this technique should be applicable to any language with first-class functions and mutable containers.

nesting robots

Even haskell, with its static types and referential transparency, is capable of emulating this pattern. Here's an example:

-- RussianDoll.hs -- Russian Doll principle in haskell module Main where import Control.Concurrent.MVar import Control.Monad (join) main :: IO () main = do fn <- newEmptyMVar putMVar fn $ do putStrLn "First!" swapMVar fn (putStrLn "Again!") >> return () join $ readMVar fn join $ readMVar fn join $ readMVar fn

Which when executed prints:

First! Again! Again!

An empty MVar is created and bound to fn. MVars are especially convenient for this example since they have an empty state built-in. The first time fn is executed, "First!" is printed, but then the fn MVar is swapped for a new action that prints "Again!".

The inferred type for fn is MVar (IO ()), so join can be used to execute the IO () action inside the MVar.

ghci> :t join join :: (Monad m) => m (m a) -> m a

which means

:t join (readMVar (undefined :: (MVar (IO ())))) join (readMVar (undefined :: (MVar (IO ())))) :: IO ()

Neat!

It's usually a better idea in these cases to use the shared mutable state to delegate to functions instead of storing and swapping the functions themselves. I am however optimistic that this approach could be used in some code to build a more beautiful abstraction.


Maxwell Equations [ 2010-04-28 05:07:52 UTC ]

Maxwell Equations

James Clerk Maxwell was a pretty scruffy-looking guy. I imagine him panhandling in a dingy subway station deep underground.


Work [ 2010-04-20 13:44:02 UTC ]

I am at work. I don't remember deciding to come in today. I wonder how many choices I actually make. I wonder how a collection of cells can make choices at all. Perhaps the concept of personal continuity is just a convenient fiction. An evolutionary artifact devised by my selfish genes To further their own agenda. The evidence suggests that I am just a loose connection of divisible parts. Perhaps it is not so much that I think therefore I am, But that someone thinks. Or perhaps something. Can things think? Am I someone or something? Is there a difference? Perhaps I am just an emergent property of an indifferent universe Which is expanding into nothingness at an accelerating rate. Even universes die. I will die too. In a sense I have already died countless times. As the person I am gives way to an imperfect copy. I am an impostor in my own skin, Coasting in the wake of my previous self: The previous self who decided I should come to work today. But life is much shorter than I had supposed.
Haskell GD Bindings and the State Monad [ 2010-03-21 12:27:56 UTC ]

The haskell gd module provides bindings to a small but useful subset of libgd. It's a nice enough module and I am grateful that Björn Bringert took the time to put it together but it's just not... functional enough for my tastes. Consider setPixel.

setPixel :: Point -> Color -> Image -> IO ()

This function takes a point, a color, and an image, returning the unit type from the IO monad, which means that somewhere inside of Image there must lie a mutable reference. As good as GHC's garbage collection and algebraic trickery are for optimizing away many sorts of unused intermediate state, I can understand the appeal of these in-place updates, especially considering how much the underlying C library caters to this programming style.

Not all of the actions are performed in-place, however.

rotateImage :: Int -> Image -> IO Image

The rotateImage function creates and returns a new Image type which has been rotated some integer number of degrees. However, this return type is still wrapped up in the IO monad and threading this Image type around looks tedious. Luckily, there is a more functional way to handle both types of updates efficiently while providing a handy way to automatically thread the state at the same time.

-- State.hs module Graphics.GD.State where import Control.Monad.State.Lazy (State(..),modify,execState) import qualified Graphics.GD as GD data GDCmd = SetPixel GD.Point GD.Color data GD' = GD' { gdCmds :: [GDCmd] } type GD a = State GD' a

Here, the GD type lets us create State monads that operate on GD' data. The GD' type contains the image and a list of operations to perform on the image. For simplicity, only SetPixel is defined. With these types, we can write a helper function consCmd that adds a command to the gdCmds of the state and a function setPixel that registers a SetPixel action.

consCmd :: GDCmd -> GD () consCmd cmd = modify $ \gd -> gd { gdCmds = cmd : (gdCmds gd) } setPixel :: GD.Point -> GD.Color -> GD () setPixel = (consCmd .) . SetPixel

Finally, a newImage function is defined that takes a size and GD () action and executes the commands in the IO monad using runCmd.

newImage :: GD.Size -> GD () -> IO GD.Image newImage size f = do im <- GD.newImage size -- run each of the commands for the image mapM_ (flip runCmd $ im) $ gdCmds $ execState f $ GD' [] return im runCmd :: GDCmd -> GD.Image -> IO () runCmd (SetPixel pt c) = GD.setPixel pt c

With just these pieces, it's possible to build something useful! This program creates a file noise.png filled with random color values.

-- Main.hs module Main where import Graphics.GD.State import qualified Graphics.GD as GD import System.Random (newStdGen,randomRs) import Control.Monad (mapM_,liftM2) main = do g <- newStdGen let (w,h) = (400,300) (GD.savePngFile "noise.png" =<<) . newImage (w,h) $ mapM_ (uncurry setPixel) $ zip (liftM2 (,) [0..w-1] [0..h-1]) -- all the pixel coordinates $ map fromInteger $ randomRs (0,256^3-1) g -- random colors

The code here is just enough to demonstrate a use of the state monad to create a mini-domain specific language on top of another library. I forked dancor's haskell-gd to include a more complete version of this Graphics.GD.State module. You can check out the code here.

With the extended module, here's code that computes a gradient:

import Graphics.GD.State main = (savePngFile "gradient.png" =<<) . newImage (400,300) $ do (w,h) <- getSize eachPixel $ \(x,y) -> let r = ((128 * x) `div` w) + ((128 * y) `div` h) g = 127 + ((128 * x) `div` w) b = 127 in rgb r g b

And this one draws a circle and a line:

import Graphics.GD.State main = (savePngFile "circle.png" =<<) . newImage (400,300) $ do (w,h) <- getSize fill $ rgb 100 63 127 -- dark purple background drawArc (w `div` 2,h `div` 2) -- centered (180,180) -- (width,height) 0 360 -- a circle (rgb 255 255 255) -- white drawLine (0,0) (w-1,h-1) (rgb 127 255 127)

This might seem like a lot of effort for something that doesn't matter very much, but writing beautiful code is important. Clean, abstract interfaces save precious mental horsepower for the bigger, harder problems.

"Beauty is a consequential thing, a product of solving problems correctly." -- Joseph Esherick


Laptop Battery Hack [ 2010-02-20 10:11:39 UTC ]

My Thinkpad's battery life had gotten pathetic. When I first bought my R61i in April 2008, its 7 cells could endure 4 solid hours of continuous use before needing to be recharged. But after 22 months of heavy use, it could hold a charge for about 25 minutes. Lenovo sells replacement batteries for $143, but I found a seller on Amazon who was selling the same 9-cells listed on Lenovo's site for $45. My laptop's battery only has 7 cells, but I didn't process this before ordering.

The battery sat in the mailbox I never check for a week before I thought to check for it there. Sitting in a mailbox for a week in Fairbanks, Alaska in January probably wasn't great for the life of the battery, but thankfully lithium-ion electrolytes won't freeze above -40 C. After I got the battery, I finally noticed that it didn't fit in my Thinkpad R61i. Rather than return the battery, I decided it would be less hassle to figure out how to make this battery work than to return it.

Li-ion batteries are pretty dangerous, as it happens. Consumers should never open an Li-ion battery's protective case, but I did anyways. Note: this is very dangerous, and probably a bad idea. Knowing full well that Li-ion batteries can ignite or explode if mishandled or punctured, I very carefully opened the new battery I bought online with a pocket knife to see what was inside.

I first tried to make this new battery fit into my laptop's battery slot by trimming the plastic, but realized that the locking mechanism and dimensions couldn't be made to fit easily. Once I got the case apart, I was able to test that the new battery would work with my laptop by plugging in the short connector cord, fully expecting both the battery and my laptop to burst into a spectacular carmine blaze.

However, the new battery worked fine without so much as a beep or an entry in the system log. At this point I decided to replace my original laptop's innards with the guts of the new battery.

Getting the original 7-cell battery apart was much more difficult and time-consuming than the new 9-cell, but I finally succeeded and didn't break too much plastic in the process.

I was cautiously optimistic that I could just swap out the Li-ion cells directly, but the original battery had electronics around every cell. Probably these electronics are to keep the battery from exploding.

It was pretty obvious beforehand that not all the cells would fit in the original case. After removing the old cells, I removed excess plastic inside that was getting in the way and cut slots on the back so that 3 cells could just hang from the back of the case. Note: this is also probably a bad idea, since puncturing an Li-ion could cause it to ignite, and metal fires are serious business.

Those warnings aside, I covered everything in electrical tape, including some stripes to match the art on the back of my display, plugged in the frankensteinian battery, and it continues to work! At the time of this writing, it hasn't even exploded yet. I will update this post if/when it does ignite or explode, supposing I survive the incident. The TSA screeners will probably have some questions for me if I ever decide to board an airplane with this thing, but it probably looks just like any other laptop battery on an X-ray scanner.