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?
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.
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.
Related
On my GHCi foldr and foldl have this signature:
Prelude> :t foldr
foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b
Prelude> :t foldl
foldl :: Foldable t => (b -> a -> b) -> b -> t a -> b
What is the difference between the alternative type signature of fold, specifically t a part?
fr :: (a -> b -> b) -> b -> [a] -> b
fl :: (b -> a -> b) -> b -> [a] -> b
The type class Foldable defines a number of functions in addition to foldl.
class Foldable t where
foldMap :: Monoid m => t m -> m
foldr :: (a -> b -> b) -> b -> t a -> b
foldl :: (b -> a -> b) -> b -> t a -> b
-- ...
We can define an instance of Foldable for a type constructor t by defining at least foldMap or foldr for the type. (foldl has a default definition in terms of some of the others, so you get it for "free" as long as you supply the minimum definition).
instance Foldable [] where
foldr f b [] = b
foldr f b (x:xs) = f x : foldr f b xs
instance Foldable Maybe where
foldr f b Nothing = b
foldr f b (Just a) = f b a
The t in the type signature just means that as long as a type constructor has a Foldable instance for it defined, you can use foldl with a value of the appropriate type. For example:
Prelude> foldl (+) 0 [1,2,3]
6
Prelude> foldl (+) 0 []
0
Prelude> foldl (+) 0 Nothing
0
Prelude> foldl (+) 0 (Just 3)
3
In the first two cases, we use the [] instance because the arguments corresponding to t a are lists, meaning t is unified with [], written t ~ []. In the second two, we use the Maybe instance because the arguments corresponding to t a are Maybe values, so t ~ Maybe.
A function is polymorphic if it works for several different types - and thus, a function is monomorphic if it works only for one type. (wiki.haskell)
As an example, map is polymorphic.
map :: (a -> b) -> [a] -> [b]
However, the function (foo) has a monomorphic type. It will only accept lists of Int:
foo :: (Int -> Int) -> [Int] -> [Int]
foo = map
foldr in Haskell:
foldr f z [] = z
foldr f z (x:xs) = f x (foldr f z xs)
Is Fold polymorphic function too?
You could ask Haskell itself, via GHCi:
Prelude> :t foldr
foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b
As you can see, it's defined entirely from parametrically polymorphic types (a, b, and t, where t is Foldable).
Generally speaking, fold is a pattern that allows to traverse the elements of different collections. In the case of foldr, it's applied to lists of any type:
foldr :: (a -> b -> b) -> b -> [a] -> b
So in this sense, it's a polymorphic function.
For example, I can't do
f = ((*2).(+)) 3
which is alright since I can always do
f = (*2).(+3)
but this is slightly inconvenient when I want to create a list of functions, e.g.
map ((*2).(+)) [1, 2, 3]
whereas
map (+) [1, 2, 3]
would be alright.
Of course, I can always use lambda notation to implement currying:
map (\x y -> 2*(x + y)) [1, 2, 3]
As far as I can tell, GHC doesn't like composing partially applied functions because it doesn't know how to feed function types to operations like (*2).
(+) 2 :: Num a => a -> a
(*2) :: Num a => a -> a
But I've always thought it should be a rather natural thing: the type of the output of (+) is Num a => a, so (*2) should be able to 'eat' that.
My question is: is this implemented in some way? Or, does someone have any idea why such a straightforward thing isn't implemented in Haskell?
Haskell support composition of partial functions but you have type mismatch. Composition is function
(.) :: (b -> c) -> (a -> b) -> a -> c
In your case you have two function
(*2) :: Num a => a -> a
(+) :: Num a => a -> a -> a
and when you compose this functions type of result will be
((*2).(+)) :: (Num (a -> a), Num a) => a -> a -> a
that not what you want. You can rewrite your function f such as (.) (*2) . (+) but I think that lambda is more readable.
And you confuse partial function and partial application. Partial function is function that defined not for the entire domain and partial application is the process of fixing a number of arguments to a function, producing function of smaller arity.
When going to point-free it might get confusing. If we go through the type signatures;
(.) is (b -> c) -> (a -> b) -> a -> c
(+) is Num a => a -> a -> a
(2*) is Num a => a -> a
Now if we do (2*) . (+) being the second parameter of (.) which is (+), has to have a type (a -> b) which is in fact true when we rewrite (+)s type as Num a => a -> (a -> a). So our b type happens to be Num a => a -> a. Now remember that (.) takes (b -> c) as first parameter. We have a little problem here because in our expression (2*) . (+) (2*) waits for a b type like Num a => a while we have our b type like Num a => a -> a. You can't multiply a function by 2..! We must transform (2*) into such a function that would take a function of our type which is Num a => a -> a, run it and feed it's result to (2*). No need to look this is no more than (.). In this case if we write again like ((2*) . ) we can safely feed our Num a => a -> a type function (remember this is partially applied (+)). Let us wrap it up...
Our point free equivalent of \x y -> 2*(x + y) is ((2*) . ) . (+)
Prelude> (((2*) . ) . (+)) 3 5
16
We may use applicative functors of ((->) r) type to express ourselves more easily in these situations. I will try to add it once i have more time.
One thing that got me stuck early when learning Haskell was the difference between foldl + and foldl (+).
Prelude> :t foldl + 0 [1,2,3]
:: (Num t1, Num ((b -> a -> b) -> b -> t a -> b),
Num ([t1] -> (b -> a -> b) -> b -> t a -> b), Foldable t) =>
(b -> a -> b) -> b -> t a -> b
vs
Prelude> :t foldl (+) 0 [1,2,3]
foldl (+) 0 [1,2,3] :: Num b => b
How does Haskell / GHC derive the type of foldl + 0 [1,2,3]? How can I understand why it expands to this giant type?
Because + is an infix operator and there are no parentheses overriding things,
foldl + 0 [1,2,3]
parses as
(foldl) + (0 [1,2,3])
The easiest starting point is the type of foldl, which is well known (and if you don't know it, you can just ask GHCI with :t foldl).
foldl :: Foldable f => (a -> b -> a) -> a -> f b -> a
Next, the other side of the addition. Because 0 is being applied as a function with [1,2,3] as an argument, there must be a Num instance for a function type which takes a list of some numeric type as input, and produces as output...well, we'll get to that.
0 [1,2,3] :: (Num t, Num ([t] -> s)) => s
Because + is being applied to these two expressions, they must have the same type. Therefore, we must unify
foldl :: Foldable f => (a -> b -> a) -> a -> f b -> a
with
0 [1,2,3] :: (Num t, Num ([t] -> s)) => s
The most general way to do that is to let s be the exact same type as foldl (combining their constraints), giving us
0 [1,2,3] :: (Foldable f,
Num t,
Num ([t] -> (a -> b -> a) -> a -> f b -> a))
=> (a -> b -> a) -> a -> f b -> a
And remember that of course foldl must have precisely the same type:
foldl :: (Foldable f,
Num t,
Num ([t] -> (a -> b -> a) -> a -> f b -> a))
=> (a -> b -> a) -> a -> f b -> a
And since + is from the Num typeclass, the type that they share must be Num as well.
foldl + 0 [1,2,3] :: (Foldable f,
Num t,
Num ([t] -> (a -> b -> a) -> a -> f b -> a),
Num ((a -> b -> a) -> a -> f b -> a))
=> (a -> b -> a) -> a -> f b -> a
Which as you can see is, modulo some renaming of types, just what GHC told you.
But of course, this is a rather silly type. It's possible someone would write all these outrageous Num instances, so GHC dutifully infers this as a valid type. But nobody actually has written these instances, so you will have a great deal of trouble actually using this expression. Really what you should do is fix your parentheses.
foldl + 0 [1,2,3] is parsed as the sum of foldl and 0 [1,2,3], which is 0 applied to the list [1,2,3].
In Haskell parentheses are not only used to set precedence of expression evaluation. The two statements are actually quite different.
The sign + is an operator, so it's supposed to work like a + b = c. That is, one function argument to the left and the other to the right. You say the operator is used in infix notation when it is like that.
You can covert any operator to a normal function being in the prefix notation by having parentheses. (+) a b = c.
Because of this, your two provided expressions are quite different. It's natural they have different type signatures.
I'm working through "Haskell Programming From First Principles". In the chapter on Folding Lists, exercise 5f,
when I evaluate
foldr const 'a' [1..5]
I get
No instance for (Num Char) arising from the literal ‘1’
However, with
foldl const 'a' [1..5]
I get 'a'.
I get that the folds are lazy, foldr doesn't traverse the spine and foldl does. But even looking at the definitions of foldr and foldl,
foldr f z [] = z
foldr f z (x:xs) = f x (foldr f z xs)
foldl f z [] = z
foldl f z (x:xs) = foldl f (f z x) xs
I can't figure out why it would have this type error. I'm guessing that the compiler is inferring type of x (Num) based on the type of z (Char), but I can't see where it draws the connection, since const or f doesn't require its two arguments to be the same type.
Any thoughts?
ok look at the type of foldr :: (a -> b -> b) -> b -> [a] -> b
Starting from the right you obviously must have a be some instance of Num and Enum (because you use [1..5])
Next you pass in 'a' so you have b ~ Char
Finally you have const for the function - and const is const :: a -> b -> a - note how you now must have a ~ b because you unify
a -> b -> b
a -> b -> a
^^^^^
but this of course would mean that 'a' must be a value of an instance of Num which Char is not ... there is your error (it's complaining about the 1 because starting left instead it's the point where the the problem becomes obvious)
foldl on the other side has foldl :: (b -> a -> b) -> b -> [a] -> b
so now you have again a some instance of Num, b must again be Char but now const just fits in (just switch b and a in the type of const)
foldl and foldr invoke f with a different order of arguments. That is foldr calls const x 'a', but foldl calls const 'a' x. The result of the latter is 'a', which is fine, but the result of the latter is x, which is wrong because x is an Int and the result is supposed to have the same type as the accumulator (Char).
This is a typing problem. The type of foldl is
foldl :: Foldable t => (b -> a -> b) -> b -> t a -> b
and foldr type is:
foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b
When you apply foldr to const you get:
foldr const :: Foldable t => b -> t b -> b
Next, you supply 'a' argument, you get
(foldr const 'a') :: Foldable t => t Char -> Char
So, when you pass [1..5] as an argument it will try to unify t Char with (Enum a, Num a) => [a]. Type Char is an instance of Enum class but not Num and it is the reason why you get this error message.
As others have said, the order of arguments in a foldl and foldr are different. Use flip const instead:
> foldr (flip const) 'a' [1..5]
'a'