Sunday, December 24, 2006

ROT13 in F#, revisited

So after seeing the Haskell version I thought, lookup is actually assoc, in F# included in the module List. So how about trying a F# version similar to the Haskell one? Well, the problem is, as I mentioned, that F# doesn't have zip, take and drop, and there is no way to map over a string. So we have to define all these functions, and then define rot13 as in the Haskell version. I defined zipWith from the Haskell prelude as well, and then used it to define zip (as it is in Haskell).

#light

let strmap f (s : string) =
let sb = new System.Text.StringBuilder(s)
let rec aux i =
if i = sb.Length then () else
(sb.Chars(i) <- f (sb.Chars(i)) ; aux (i + 1))
( aux 0; sb.ToString() )

let rec drop n l =
match (l, n) with
([], _) -> []
| (l, 0) -> l
| (_ :: rl, n) -> drop (n - 1) rl

let rec take n l =
match (l, n) with
([], _) -> []
| (l, 0) -> []
| (x :: rl, n) -> x :: (take (n - 1) rl)

let rec zipWith f l1 l2 =
match (l1, l2) with
([], _) -> []
| (_, []) -> []
| (x1 :: rl1, x2 :: rl2) -> (f x1 x2) :: (zipWith f rl1 rl2)

let zip l1 l2 =
zipWith (fun a b -> (a, b)) l1 l2

// and now for something completely different
let rot13 s =
let letters = ['a' .. 'z']
let transp = zip letters ((drop 13 letters) @ (take 13 letters))
let rotchar c = List.assoc c transp
strmap rotchar s

Works as expected, but we ended with code that is still longer than the first version, only because it was necessary to define some general-use functions. I guess I will create a Prelude module to use with F#, containing the Haskell functions I use most.

No comments: