Laziness and fizzbuzz in Haskell

Paul Brown @ 2007-01-25T03:26:00Z

After peeking at Reg's solution, I can't resist posting a fizzbuzz implementation in Haskell (because Reg's looks stylistically like it should be written in an FP language of some flavor). It's also an example of the surprising effectiveness of being lazy. Some Haskell:

module Main(main) where

import List

f :: Int -> String
f x | (x `mod` 15 == 0) = " fizzbuzz"
    | (x `mod` 5 == 0) = " buzz"
    | (x `mod` 3 == 0) = " fizz"
f 1 = "1"
f x = ' ':(show x)

main :: IO ()
main = (putStr.concat) (map f [1..100])

Here's a slightly different version of the main function:

main' :: IO ()
main' = mapM_ putStr (map f [1..100])

So, which one is better? Interestingly, if you crank up the 100 to 10000000 (108), either one of those two versions runs in well under a minute, in <2MB of (resident) memory, and presents roughly the same heap profile:


main


main'

The main' version might naively appear to be faster than the main version, but this is laziness in action: a String is [Char], i.e., a list of characters. The list of characters passed to putStr in the main version is generated lazily, as are the IO actions in the main' version. (In fact, the main version is faster at under 7 seconds to roughly 20 seconds for the main' version.) As you would expect based on laziness, both programs begin producing output immediately upon execution. Meanwhile, without laziness, the ruby version chews up gobs of memory and takes a long time. (I got tired of waiting for it after about 30 minutes, at which point it was using 35M of resident memory without producing any output.) The simplest possible ruby solution (for loop, if...elsif...else) runs in around 45 seconds and consumes <2M of resident memory.

As an aside, reproducing the precise flavor of Reg's solution would mean composing a list of functions, which is simply expressed in Haskell terms and wouldn't impact laziness. If l is of type [Int -> Int] (a list of functions that map integers to integers), then:

foldr (.) id l

is the Int -> Int that applies the composition of the elements of l on the left, i.e., last l is the first function applied. Nonetheless, precisely the same solution (repeatedly applying a function parameterized by a modulus and a substitution) isn't as simply expressed because String and Int are distinct types.

Update: There is a thread going on reddit that has some terse Haskell versions, along with versions for a bunch of other languages.

(comment bubbles) 1 comment

Useful grep Flag

Paul Brown @ 2007-01-17T02:50:04Z

GNU grep supports a -A flag (or --after-context if you're a long options kind of person) that includes lines of context:

-A NUM, --after-context=NUM
       Print  NUM  lines  of  trailing  context  after  matching lines.
       Places  a  line  containing  --  between  contiguous  groups  of
       matches.

which is very handy for sifting through log files where you want grep to match the "ERROR" but the useful information is in the following couple of lines.

(comment bubbles) 0 comments

Masking Tape Brio/Thomas Track Hack

Paul Brown @ 2007-01-11T04:08:28Z

The kid's not old enough yet if you believe what the boxes say, but we've gone ahead and gotten her some Brio trains to play with. (For what it's worth, we went with Brio over Thomas as an extension of our "no Disney" rule — in a nutshell, anthropomorphized things derived from TV shows or movies are bad. The kid loves the trains (although she does wonder why some have eyes and hers don't) and runs them around and around whatever track we have set up on her play table yelling "choo choo". (I'll wait until she's older to tell her that "choo choo" is a bit of an anachronism, e.g., when she's old enough to know what anachronism means.)

Anyway, when we first set up the train set, the kid was rough enough that any elevated track tended to fall down. Gluing the tracks together or nailing them down didn't make sense, but the wife came up with the idea of using masking tape on the underside of the joints in the track. It works like a charm; the track stays together when the kid is using it, but it's easy to take the tape off and lay out a new configuration. Now we just have to get down off of our anthropomorphism horse to figure out how to get a dispenser with eyes, and we can market Rufus, the Very Useful Track Tape™...

(comment bubbles) 0 comments

Bring It On

Paul Brown @ 2007-01-11T03:37:07Z

Reg Braithwaite has lots of smart things to say, and I agree about asking potentially challenging questions in an interview, albeit for different reasons. When hiring someone who represents themselves as "senior", the ultimate answer is simpler: I have 60-90 minutes to figure out who you are and what "senior" means; you have 60-90 minutes to help me, so get cracking. Whining about the question during or after completely misses the point.

(comment bubbles) 1 comment

The Kid, The Office, and Perception

Paul Brown @ 2007-01-10T02:59:14Z

The kid has been demonstrating pretty much full comprehension of verbal instructions and basic predicates ("if", "before", "after", etc.) from me and/or the wife, which is very, very nice: "If you want more crackers, take your snack trap and ask your mother." Her ability to express herself isn't as far along, but she is picking up a couple of new words each day. The most interesting thing that she did recently was to randomly interject words while I was humming the theme for a DVD that she'd watched. So I hummed it again. Same words. It took me a minute, but I figured out that she was describing the scenes that went along with the intro music, more or less at the right point. Note to self to be very careful about what I say around her and what she sees. Nonetheless, it's easy for me to slip and forget how the kid might see situations.

Today, we were looking at the iPhone pages at Apple.com together, and we watched the video clip of The Office. The basic plot synopsis was that Guy A was playing jokes on Guy B by sending Guy B faxes ostensibly from himself in the future, and the current fax was a warning that the coffee was poisoned. In possession of this information, Guy B saw Guy C about to drink some coffee, ran over screaming "Noooooooo", and slapped the coffee out of Guy C's hand. I had a good laugh. The kid was scared out of her wits and didn't stop hugging me until we went to see the wife... Oops.

(comment bubbles) 0 comments

Gestures and a Better Mouse

Paul Brown @ 2007-01-10T00:53:14Z

In spite of it being relatively expensive, I might just get an iPhone, and it's the gesture-based UI that has me interested rather than any of the other gee-whiz stuff, which I view as incremental. (I don't have time or interest to watch video at home, and the last thing I want is to clutter my head with more noise when I have moments of inactivity.)

When I got a fingertip smashed by a faulty window way back when we moved into a new condo in Chicago (fully recovered), Bob gifted me me with a FingerWorks keyboard that he'd been playing with. It was a bit of a white elephant in that it reduced my typing to a crawl and some common IDE key combinations (e.g., CTRL-[SPACE]) were difficult), but the gestures were the first interesting user experience that I've had since I first tried a mouse. Different numbers of fingers were used for clicking, selecting, dragging, scrolling; closing the current window was like screwing the lid on a jar with three fingers, and opening a file was like unscrewing it. Ultimately, the novelty of the gestures didn't outweigh input speed, and the keyboard now sits in my closet. (Not for sale; the only thing I'd do with it would be to reluctantly give it back to Bob if he asked.)

I didn't have the foresight to pick up the standalone gesture pad, and even somewhat broken ones are going for almost $100. (I haven't seen a non-broken one recently.) Hopefully the iPhone will be successful and someone will provide a gesture-based input device for the desktop, and I'll gladly be a customer — build a better mouse, and I'll beat a path to your website.

(comment bubbles) 1 comment

OpenID for Me

Paul Brown @ 2007-01-06T01:23:58Z

Thanks to Sam's post on a short path to getting a personal install of OpenID working, I got things working and gave them a quick whirl with both the OpenID Enabled checker and a WordPress scratchpad. All-in-all it was almost too easy; the most troublesome thing in the whole process was switching Apache2's execution module so that I could apt-get the PHP module (which depends on thread safety).

My only objection is that the identification URI is supposed to return specific content in response to a GET with no parameters:

If it's a GET request with no arguments, the Identity Provider SHALL show a 200 text/html error saying "This is an OpenID server endpoint. For more information, see http://openid.net/".

Specifically because the URI represents my identity, I'd like to have control over the human-facing response that the URI generates when requested. The openid.delegate parameter works around this issue by allowing me to delegate from http://mult.ifario.us/id/ to http://mult.ifario.us, but I'm not sure what the above restriction buys in terms of either security or utility.

(comment bubbles) 1 comment

All Posts contains 399 items in 57 pages of 7 items each:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57