Cute Haskell Code

May 9, 2007

For some recent supervision work on my Security lectures, I was given the task of decoding a string encrypted with a simple shift cipher. This cipher, given a key, simply moves each letter on in the alphabet by an amount given by the key, wrapping at the end. Being a good functional programmer, I decided to implement a brute force solver for this in Haskell, and I’m rather pleased by the terseness of the result, so I felt compelled to share it.

import List(elemIndex)
cipherText = “LUXDZNUAMNDODJUDTUZDGYQDLUXDGOJDCKDTKKJDOZ”

shift i x = (cycle ['A'..'Z'])!!(maybe (error “Bad character ” ++ (show x)) (+i) (elemIndex x ['A'..'Z']))
main = sequence_ (map (\i -> putStrLn $ map (shift i) cipherText) [0..25])

If you ignore the boilerplate, there’s only two lines of actual code there :-). I happen to think it’s rather understandable, though I’d be interested to get the opinion of someone who isn’t a Haskell hacker on the veracity of that statement. A hint you may need understanding it is that “cycle a_list” just returns the list which is “a_list” concatenated infinite times, and that “!!” is Haskells list indexing operator.

On this note, I saw an interesting blog post at retrospections the other day which compared the LOC count for a number of open source source control programs: Darcs (Haskell) and Mercurial (Python) were tied at 20KLOC, with the next best being Bazaar-NG (Python) at 47KLOC. Obviously this isn’t a strictly apples-to-apples comparison, though, so take it with a grain of salt!

About these ads

6 Responses to “Cute Haskell Code”

  1. Vineet Kumar Says:

    Maybe more readable?

    > import Char
    > shift i x = chr $ constrain $ ord x + i
    > where constrain n =
    > let a = ord ‘A’ in
    > (n – a) `mod` 26 + a

    Maybe not…


  2. Mmm, that’s a nice solution too. Though what I particularly liked about the ['A'..'Z'] style is that it never at any point did the ASCII conversion: it was just a literal encoding of how a human would think about the problem.

  3. Peter Says:

    I had to add a $ after error to get your program to compile. Now, here’s my attempt at being cute:

    shift i x = (dropWhile (/=x) $ ['A'..'Z']++['A'..'Z']) !! i

    This gives the error “index too large” from (!!) when x is not in ['A'..'Z'] or i is not in the proper range. (You’d want to check the arguments more carefully in a real program.)


  4. Ah, that’s very nice indeed :-). And yeah, about the compile error: mea culpa. In my code that was “undefined”, but I felt I should add some error handling to clean it up for the post :-).

  5. Morten Says:

    cipherText = “LUXDZNUAMNDODJUDTUZDGYQDLUXDGOJDCKDTKKJDOZ”

    main = print (sequence $ cipherText >>= (\x -> [lookup x (zip (‘Z':['A'..'Y']) ['A'..'Z'])]))

    This solution uses monad bindings.

  6. Morten Says:

    Sorry, I forgot the i

    import Monad

    cipherText = “LUXDZNUAMNDODJUDTUZDGYQDLUXDGOJDCKDTKKJDOZ”

    i = 20

    main = print (sequence $ cipherText >>= (\x -> [foldM (\y a -> lookup y (zip (‘Z':['A'..'Y']) ['A'..'Z'])) x [1..i]]))


Comments are closed.

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: