Friday, January 18, 2008

Haskell Function calls and Parentheses

[1.] Function Calls in Haskell

As you may have noticed, passing input to a function in haskell is simple because of the statically type nature of the language. A function can have a complicated input and output return, but at least you are given the parameters of that particular function. In python you can pass anything to a function; you can pass a function, a integer constant, an instance of a class and yet the function really only expects an boolean.

[2.] Examples

putStrLn :: String -> IO ()

For example, putStrLn expects a string as an input and will return unit in the IO Monad.

>putStrLn "abc"

Will print abc to the console.

Prelude> putStrLn "abc" ++ "123"

Couldn't match expected type `[a]' against inferred type `IO ()'
In the first argument of `(++)', namely `putStrLn "abc"'
In the expression: putStrLn "abc" ++ "123"
In the definition of `it': it = putStrLn "abc" ++ "123"

The following example gave an error. Why? We gave putStrLn three arguments as opposed to the one. Here are the extra arguments, "++" and "123".

To fix the issue:

putStrLn ("abc" ++ "23")

Or even:

(putStrLn ("abc" ++ "23"))

[3.] Dollar Sign, syntatic sugar

We can also use the syntatic sugar, the dollar sign function to alleviate us from having to wrap the arguments in parentheses. Here is the type:

Prelude] :type ($)
($) :: (a -> b) -> a -> b

Pass ($) The infix function has a first input parameter (a -> b), a function and then the 'a' argument which will output b. The following code demonstrates three different calls to putStrLn, but the final output is the same.

Prelude] putStrLn "abc"
Prelude] putStrLn $ "abc"
Prelude] (putStrLn "abc")

Here is another working example:

putStrLn $ "abc: " ++ show(3) ++ show(4)

If we return to the ($) definition and putStrLn.
($) :: (a -> b) -> a -> b

putStrLn represents this part of the input (a -> b)
'a' represents the String input and b represents the output of putStrLn String which is the IO () monad.

For this aspect of the call, "abc: " ++ show(3) ++ show(4);

The (++) operator has the following type definition:

Prelude> :t (++)
(++) :: [a] -> [a] -> [a]

Where [a] can be represented by [Char].

Here are another set of working examples.

Prelude> putStrLn $ "abc: " ++ (show(3) ++ show(4))
abc: 34
Prelude> putStrLn $ ("abc: " ++ (show(3) ++ show(4)))
abc: 34
Prelude> (putStrLn $ ("abc: " ++ (show(3) ++ show(4))))
abc: 34
Prelude> (putStrLn $ ("abc: " ++ (show(3) ++ show(4))))
abc: 34
Prelude> (putStrLn ("abc: " ++ (show(3) ++ show(4))))
abc: 34

Those examples are a little confusing because the (++) operator calls are resulting to one "string" input. For example:

let z = "abc: " ++ show(3) ++ show(4)

Is of type String.

[4.] Function composition

The infix dot operator shown below takes one function, another function and an input and returns the output c.

Prelude] :t (.)
(.) :: (b -> c) -> (a -> b) -> a -> c

If we used the putStrLn function, and show function; what combinations could we come up with?

Note, show is defined by the following signature.

Prelude] :t show
show :: (Show a) => a -> String

Prelude] putStrLn . show $ 5

I will use the following notation to denote the operation invoked above:

### Function: **putStrLn** ||| Type: ( String -> IO () ) ###
infix dot-operator and then:
### Function: **show** ||| Type: ( a -> String ) ###
infix dollar sign operator and then the value of 5.

Prelude] putStrLn . show $ 5

The following calls also worked

Prelude> putStrLn $ show 5
Prelude> putStrLn (show $ 5)
Prelude> putStrLn $ (show $ 5)
Prelude> (putStrLn $ (show $ 5))

If you are given a list and need to print each element on its own line, you can use the following snippet.

mapM_ (\x -> (putStrLn ("Token: " ++ x ++ " Len: " ++ (show (length x))))) ["ab", "1231", "ddd"]

Do two things to make function composition look easier, think backwards and consider that putStrLn, show and ($) are operations with only one input and one output. As you can see, with haskell are many different ways to do something as simple as invoke a function.

edited: Apparently, I got so carried away, I didn't acknowledge that you can just call the function without any operators. E.g; [ putStrLn $ show 5 ] Sorry if that simple fact wasn't made clear.


Anonymous said...

Prelude> putStrLn "abc" ++ "123"

Actually, the issue is precedence, not of too many arguments (in fact, (++) can't be passed as an argument like that). Functions have higher precedence than operators, so that expression is evaluated as:

(putStrLn "abc") ++ "123"

And that's indeed exactly what the error message is saying, isn't it? : )

Anonymous said...

(putStrLn ("abc" ++ "23"))

Also, while there's nothing wrong with that, I think it's really unnecessary. I learned Lisp first, and I remember I would do the same thing too. But in Haskell, that would be equivalent to writing, say:

x = (1)

[But as you know, one situation where that's necessary is for negative numbers.]