I'm making a stab at learning Haskell, a functional programming language, and as part of it I'm going through the section in Seven Languages in Seven Weeks, one of the exercises is to convert a string representation of a number to a real (floating point) number, so " $2,345,678.99" to 2345678.99.
Here's my first stab :
strToNum :: String -> Float
sToN :: (Float, Int, String) -> Float
sToN (acc, dec_place, ) = acc
sToN (acc, dec_place, xs)
| head xs == '$' = sToN (acc, dec_place, tail xs)
| head xs == ',' = sToN (acc, dec_place, tail xs)
| head xs == '.' = sToN (acc, 1, tail xs)
| dec_place > 0 =
let newacc = acc + (fromIntegral (digitToInt (head xs)) ) / (10.0 ^ dec_place)
in sToN (newacc, dec_place + 1, tail xs)
| otherwise =
let newacc = acc * 10.0 + (fromIntegral (digitToInt (head xs)) )
in sToN (newacc, dec_place, tail xs)
strToNum "" = 0.0
strToNum(xs) = sToN (0.0, 0, xs)
It's a bit brute force and ignorance, but it works. Just thought of a more elegant solution though. The point of this post is the use of 'let' rather than 'where' in the guard expression. The guards (| expressions) handle the various characters and states of the string, and in the two that alter the accumulator define the new value via a 'let'. Initially I tried using a 'where' for this, but it seems that you can only have one per pattern sequence, it would seem that this is because 'let' is a proper expression whilst 'where' is not.
BTW I also tried this with lambdas, but fell foul of the type system.
I quite like this pattern matching approach in general, and have used it in Perl a lot, as it is quite easy to see each 'case' and the logic that goes with it.