Why does this function work even though there is no argument?
I am trying to understand the following piece of code:
import Data.Char (ord)
encodeInteger :: String -> Integer
encodeInteger = read . concatMap ch
where ch c = show (ord c)
But I don't see how this can work when it encodeInteger
is defined as a function that takes a string, but in the second line, the function is implemented without that string argument.
Also concatMap
(according to hoogle) accepts a function and a list, but only a function is provided ch
.
Why does this code still work? Is the argument somehow magical? Is this something to do with currying?
edit: And why doesn't it work to change it like this:
encodeInteger :: String -> Integer
encodeInteger a = read . concatMap ch a
where ch c = show (ord c)
source to share
Basically function definition
f = g
matches function definition
f x = g x
In your specific case, you can use
encodeInteger a = (read . concatMap ch) a
to define your function. The parentheses are needed, otherwise they are parsed as
encodeInteger a = (read) . (concatMap ch a)
and is concatMap ch a
not a function and cannot be linked. At best, you can write
encodeInteger a = read (concatMap ch a)
-- or
encodeInteger a = read $ concatMap ch a
About "why concatMap ch
only takes one argument?" It is a partial application that is very common in Haskell. if you have
f x y z = x+y+z
you can call f
with fewer arguments and result in a function of the remaining arguments. For example, f 1 2
is a function that takes z
and returns 1+2+z
.
Specifically, thanks to Currying, there is no such thing as a function that takes two or more arguments. Each function always takes only one argument. When you have a function like
foo :: Int -> Bool -> String
then it foo
takes one argument, a Int
. It returns a function that takes Bool
and finally returns String
. You can visualize this by writing
foo :: Int -> (Bool -> String)
Anyway, if you look at currying and partial application you will find many examples.
source to share
encodeInteger :: String -> Integer
encodeInteger = read.concatMap (\char -> show $ ord char)
encodeInteger
on the left (LHS) "=" is the name; this refers to the function on the right hand side (RHS) "=". Both have the function type: String -> Integer
. Both take a list of characters and produce an integer. Haskell allows us to express such function equality without specifying formal arguments (a style known as point-free ).
Now let's look at RHS. Operator (.) Combines two functions. The folded function takes a string as its input from concatMap
and outputs an integer output from read
as the result of the compiled function.
concatMap
itself takes 2 inputs, but we need to leave the second one for the linked function, which requires a string as its input. We achieve this by partially applying concatMap
, including only his first argument.
source to share