Sunday, 27 December 2009

F# examples on Rosetta Code

Rosetta Code is a wonderful community-driven wiki containing examples of dozens of programming tasks written in dozens of languages.

Naturally, we couldn't resist the challenge to solve many of these tasks in F# and we shall be publicizing our results here and even developing some into full-blown F#.NET Journal articles.

Perhaps the most surprising result is that the F# solutions are extremely concise even when compared with bleeding-edge research languages such as Haskell. For example, the Haskell solution to the Data Munging 2 problem is:

type Date = String
type Value = Double
type Flag = Int
type Record = (Date, [(Value,Flag)])
 
duplicatedDates :: [Record] -> [Date]
duplicatedDates [] = []
duplicatedDates [_] = []
duplicatedDates (a:b:tl)
    | sameDate a b = date a : duplicatedDates tl
    | otherwise    = duplicatedDates (b:tl)
    where sameDate a b = date a == date b
          date = fst
 
numGoodRecords :: [Record] -> Int
numGoodRecords = length . filter recordOk
    where recordOk :: Record -> Bool
          recordOk (_,record) = sumOk == 24
              where sumOk = length $ filter isOk record
                    isOk (_,v) = v >= 1
 
parseLine :: String -> Record
parseLine line = (date, records')
    where (date:records) = words line
          records' = mapRecords records
 
          mapRecords :: [String] -> [(Value,Flag)]
          mapRecords [] = []
          mapRecords [_] = error "invalid data"
          mapRecords (value:flag:tail) =
              (read value, read flag) : mapRecords tail
 
main :: IO ()
main = do
  contents <- readFile "readings.txt"
  let inputs = map parseLine $ lines contents
  putStrLn $ show (length inputs) ++ " total lines"
  putStrLn "duplicated dates:"
  mapM_ putStrLn $ duplicatedDates inputs
  putStrLn $ "number of good records: " ++ show (numGoodRecords inputs)

whereas our F# solution is simply:

let dates = HashSet(HashIdentity.Structural)
let mutable ok = 0
 
do
  for line in System.IO.File.ReadAllLines @"readings.txt" do
    match String.split [' '; '\t'] line with
    | [] -> ()
    | date::xys ->
        if dates.Contains date then
          printf "Date %s is duplicated\n" date
        else
          dates.Add date
        let f (b, t) h = not b, if b then int h::t else t
        let _, states = Seq.fold f (false, []) xys
        if Seq.forall (fun s -> s >= 1) states then
          ok <- ok + 1
  printf "%d records were ok\n" ok

This really highlights the dramatic step forward that F# represents, not only improving upon the previous generation of mainstream programming languages but even leaping beyond research.

1 comment:

Michael Mol said...
This comment has been removed by a blog administrator.