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)

      

+3


source to share


2 answers


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.

+4


source


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.

+3


source







All Articles