Showing posts with label haskell. Show all posts
Showing posts with label haskell. Show all posts

Wednesday, 7 September 2011

Haskell - 7 languages in 7 weeks, Day 2

Haskell Day 2 Exercises

Write a Haskell function to convert a string to a number. The string should be in the form of $2,345,678.99 and can possibly have leading zeros.

As I mentioned in the last post, there was a better way to solve this than tail recursion.


strToNum :: String -> Float
strToNum(str) = let num = [x|x <- str,  (x >= '0' && x <= '9') || x == '.']
       in read num :: Float

This function uses list comprehension to filter the string for valid characters and the uses read to convert the filtered string into a floating point number. As you can see it's very concise, and when you are used to the form very readable. This says num is all the valid (0-9 and .) characters from the string str. 

Write a function that takes an argument x and returns a lazy sequence that has every third number, starting with x. Then, write a function that includes every fifth number, beginning with y. Combine these functions through composition to return every eighth number, beginning with x + y.

stepList x n = take 5 [x,x+n..]

threeList x = stepList x 3
fiveList x = stepList x 5

eightList x y = zipWith (+) (threeList x) (fiveList y)


So, the lazy sequence is [x,x+n..] to stop things running off into infinity I've used take to perform the lazy eveluation. Again, Haskell can be very concise -look at zipWith in eightList.


Use a partially applied function to define a function that will return half of a number and another that will append \n to the end of any string.


half = (*) 0.5



This is quite cunning (of Haskell). Inside Hskell all functions are, I believe, curried -that is they take only one argument. As a bit of syntactic sugar Haskell support infix operators, but you can force them to their curried form but surrounding the operator in brackets.  Since the functions are curried they are quite happy to have a dangling second argument, in fact we have here a function that is 'multiply by 0.5'.


backAppend x y = y ++ x
append = backAppend "\n"



The same applies to the append function here, only we have had to define backAppend to get the arguments the way round we want.

I'm going to leave the second set for now, and maybe come back to them at the end.

Tuesday, 6 September 2011

Haskell, where vs let in guards

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 :

import Char

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.

linkedin