2

What I don't get is how it is possible to use foldl in this way in haskell. I do not understand how the argument ( in this case list) is carried over implicitly:

addAll :: [Int] -> Int
addAll =  foldl (+) 0

-- This is how I could write foldl to simplify addAll where xs is clearly defined

addAll :: [Int] -> Int
addAll xs = foldl (+) 0 xs

or

addAll :: [Int] -> Int
addAll = \ xs -> foldl (+) 0 xs

But I don't really understand the first example. So basically I wonder how it is possible for something to be evaluated like that in haskell?

Nilo
  • 41
  • 4
  • 2
    `foldl (+) 0` produces a function that maps a list to the sum. – Willem Van Onsem Oct 12 '20 at 17:50
  • 1
    Technically, because of currying, all the functions in Haskell take exactly _one_ argument. `foldl` takes one argument, which is `(+)` in your code. It happens that the result of `foldl (+)` is a function, so that can take something as its argument -- `0`, in your code. It also happens that the new result is also a function, so it can take `xs` as argument. Summing up, `foldl`, `foldl (+)`, `foldl (+) 0`, `foldl (+) 0 xs` are all valid expressions. – chi Oct 12 '20 at 20:08

2 Answers2

4

Remember that all functions in Haskell are curried. foldl is no exception; it has type Foldable t => (b -> a -> b) -> b -> t a -> b, which means it takes an argument of type (b -> a -> b) and returns a function of type Foldable t => b -> t a -> b.

That function is also curried. foldl (+) takes an argument of type Int b => b and returns a function of type (Foldable t, Num b) => t b -> b.

Thus, foldl (+) 0 has type (Foldable t, Num b) => t b -> b, and your type annotation makes the restrictions t ~ [] and b ~ Int.

Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
chepner
  • 497,756
  • 71
  • 530
  • 681
4

But I don't really understand the first example. So basically I wonder how it is possible for something to be evaluated like that in haskell?

The foldl (+) 0 produces a function. A function of type (Foldable f, Num a) => f a -> a, so why would you need an extra parameter? The addAll is a function as well.

In functional programming, functions are "first class citizens". This means that you can pass functions as parameters, and that the result can be a function. In Haskell every function takes exactly one parameter. Indeed:

foldl :: Foldable t => (b -> a -> b) ->  b ->  t a -> b

is short for:

foldl :: Foldable t => (b -> a -> b) -> (b -> (t a -> b))

foldl is thus a function that takes as parameter a function of type (b -> a -> b), and produces a function of type b -> t a -> b. This thus means that foldl (+) has type:

foldl (+) :: (Foldable f, Num b) => b -> (f b -> b)

again a function that in this case takes a parameter the base case for foldl, and returns then a function that maps a (Foldable f, Num a) => f a -> f a. If you write foldl (+) 0, this is thus short for (fold (+)) 0.

Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
  • 1
    I just tried it out with max to check what number is bigger, 10 or the other and it works, how cool is that. – Nilo Oct 12 '20 at 18:22
  • ```Haskell-- max :: (Ord a) => a -> (a -> a) max10 :: Int -> Int max10 = max 10``` – Nilo Oct 12 '20 at 18:22
  • @DN: yes. All functions take one parameter, so you can make functions that calculate the maximum compared to 10 as you did :) – Willem Van Onsem Oct 12 '20 at 18:24
  • Yeah, I noticed it when I read about Curried functions just now. Thanks a lot, understanding curried functions was the key and especially that "Every function in Haskell officially only takes one parameter.". – Nilo Oct 12 '20 at 18:27