Qwertie
Qwertie

Reputation: 6573

How do "invisible" function parameters in Haskell work?

An example of what I am talking about is takeWhile

takeWhile :: (a -> Bool) -> [a] -> [a] 

Example usage

takeWhile (< 3) [1,2,3,4,1,2,3,4] == [1,2]

From what I can tell (< 3) becomes (a < 3) where a is the current item in the list being checked.

How is this done in Haskell and how would I be able to move where a goes so I could do something like

takeWhile ((length a) < 4) ["aaa", "aaaaa"]

Upvotes: 4

Views: 348

Answers (3)

n. m. could be an AI
n. m. could be an AI

Reputation: 120021

(< 3) is called a "section" and works only with infix operators. It's a syntactic sugar to write abbreviated functions. (< 3) is equivalent to \x -> x < 3 and (3 <) is equivalent to \x -> 3 < x.

Thus, (< 3) is a function of one argument that returns a Bool. Which is exactly what takeWhile expects.

With length, you have to write a function in full:

takeWhile (\x -> length x < 4) ["aaa", "aaaaa"]

or define your own function you can curry:

shorterThan n x = length x < n

takeWhile (shorterThan 4) ["aaa", "aaaaa"]

If you are feeling adventurous, you can write

takeWhile ((< 4) . length) ["aaa", "aaaaa"]

or perhaps in a more readable fashion

(??) = flip (.)

takeWhile (length ?? (< 4)) ["aaa", "aaaaa"]

Upvotes: 9

developer_hatch
developer_hatch

Reputation: 16224

There go nowhere, you have to remember that every function in Haskell is currified, so, think in the (+) function, you can do the next, think in the type first:

(+) :: Num a => a -> a -> a

now I can do my custom plusOne, plusTwo, etc, so fast thanks to the curryfication, because

(+) :: Num a => a -> a -> a

has "implicit paranthesis" and really looks like:

(+) :: Num a => a -> (a -> a)

meaning give me a number a give you a function back, so:

plusOne :: Num a => a -> a
plusOne = (+1)

plusTwo :: Num a => a -> a
plusTwo = (+2)

Can you see? you transform the (+) in a new function by giving to it just one of the two parameters, same happens with < and > functions, you can create the function greaterThanTen like this:

greaterThanTen :: (Num a, Ord a) => a -> a
greaterThanTen = (>10)

So in your example of takeWhile (< 3) your (< 3) is the function "less than 3", and if you "read" all the function would be "take while n is less than 3"

you can play around with it in the console by asking the types with :t command

  :t (< 3)
(< 3) :: (Num a, Ord a) => a -> Bool

Upvotes: 3

Karim
Karim

Reputation: 361

The first argument to takeWhile is a predicate; this is your unary function (< 3), which is true, when the argument has numeric semantics and is less than 3. This option is applied to each list member, making up a new list and terminating, when the predicate is not true the first time. The elements, which have passed, make up the result list.

Your example is almost correct, you must only convert it into predicate form, i.e. create an unary function, which is true, when the parameter (a string) has a length less than 4. This can for example done by

(\a -> (length a) < 4)

then

takeWhile (\a -> (length a) < 4) ["aaa", "aaaaa"]

should do what you expect.

Upvotes: 3

Related Questions