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.
Related
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.
I am a Haskell newbie trying to wrap my head around type binding in functions and how Haskell enforces it. For example, even though the type for the fst function is fst :: (a, b) -> a, the compiler does not complain for the function fst'. But the compiler complains about type bindings for the function elem'.
fst' :: (a,a) -> a
fst' s = fst s
elem' :: (Eq a, Eq b) => a -> [b] -> Bool
elem' x xs = elem x xs
fst has as type fst :: (a, b) -> a so that means it is fine to define a function:
fst' :: (a, a) -> a
fst' = fst
Your fst' function is more restrictive than the fst function. Regardless with what you replace a in your fst' function that is fine for fst. If for example a ~ Bool holds, then you call fst with signature fst :: (Bool, Bool) -> Bool. But since fst can deal with all as and b, it is fine that both elements of the tuple are Bool, so given fst can handle tuples for all possible types for both the first and the second item of the 2-tuple, it is defintely ok if the two items have the same type.
The latter is not ok, here you define:
elem' :: (Eq a, Eq b) => a -> [b] -> Bool
elem' = elem
but elem has type elem :: Eq a => a -> [a] -> Bool. The signatures you can make with the elem' function are not a subset of the ones of the elem function, since you can set a ~ Int and b ~ Bool. In that case you expect elem :: Int -> [Bool] -> Bool, but evidently that does not hold, since the Int and Bool type are two different types, and in the elem signature, these are both as.
I just see an expression
fmap_List :: (a -> b) -> [] a -> [] b
-- "[] a" means "[a]", for types.
fmap_List f [] = []
fmap_List f (x:xs) = f x : fmap_List f xs
Since [] a means [a], why we don't put [a] directly instead? Are there some special cases we should use [] a?
It’s just avoiding the syntactic sugar [a] as a way of illustrating that the f type parameter of fmap :: Functor f => (a -> b) -> f a -> f b is being replaced with the type constructor [], just like any other type constructor.
That is, you might write the type [a] as [] a when you want to emphasise the relationship to a signature that’s polymorphic over some type constructor, like fmap:
fmap :: Functor f => (a -> b) -> f a -> f b
-- f = []
fmap_List :: (a -> b) -> [] a -> [] b
fmap_List = fmap
-- f = Maybe
fmap_Maybe :: (a -> b) -> Maybe a -> Maybe b
fmap_Maybe = fmap
Or join:
join :: Monad m => m ( m a) -> m a
join_List :: [] ([] a) -> [] a
This is exactly the same as [[a]] -> [a], just making it clearer that m = [].
[] a is the type constructor [] applied to the type variable a. [] a or [a] has the kind *, the kind of types that are inhabited by values, such as Int, Char, Maybe Int, or Either String Int. [] has kind * -> *, the kind of types that take a type argument and produce a type as a result, such as [], Maybe, Identity, or Either e.
You can see this for example in the definition of instance Monad []—we’re giving the constructor [] (of kind * -> *) as an argument to Monad (of kind (* -> *) -> Constraint), not a type (of kind *) made with that constructor such as instance Monad ([] a). This is just like using Maybe instead of Maybe a, Maybe Int, Maybe String, &c.
Using the TypeApplications pragma, you can explicitly apply polymorphic functions to type arguments, e.g. in GHCi:
> :set -XTypeApplications
> :type fmap #[]
fmap #[] :: (a -> b) -> [a] -> [b]
> :type fmap #Maybe
fmap #Maybe :: (a -> b) -> Maybe a -> Maybe b
> :type fmap #[] #Int #Char
fmap #[] #Int #Char :: (Int -> Char) -> [Int] -> [Char]
> :type fmap #[] #_ #Bool
fmap #[] #_ #Bool :: (a -> Bool) -> [a] -> [Bool]
This is very useful for figuring out how to use polymorphic functions, or documenting which container or monad you’re using such a function with, by specialising a type to a (more) concrete instance:
> :type traverse
traverse :: (Traversable t, Applicative f) => (a -> f b) -> t a -> f (t b)
> :type traverse #[] #IO
traverse #[] #IO :: (a -> IO b) -> [a] -> IO [b]
And you can also ask GHCi for the kind of a type to get a better understanding of kinds:
> :kind Either
Either :: * -> * -> *
> :kind Either String
Either String :: * -> *
> :kind Either String Int
Either String Int :: *
> :kind []
[] :: * -> *
> :kind [] Int
[] Int :: *
> :kind [Int]
[Int] :: *
> :kind Functor
Functor :: (* -> *) -> Constraint
> :kind Num
Num :: * -> Constraint
The notation [] is useful when it is not being applied but passed to another type constructor.
Fix [] -- recursion-schemes
Free [] a -- free
ReaderT r [] a -- transformers
Compose [] Maybe a -- base (Data.Functor.Compose)
Since [] a means [a], why we don't put [a] directly instead?
This is a funny question. Let me try to convince you that, arguably, the real question is:
Since [a] means [] a, why we don't put [] a directly instead?
Consider the following parametric types:
data Identity a = Identity a
data Maybe a = Nothing | Just a
data HPair a = HPair a a
data HTriple a = HTriple a a a
data Tree a = Empty | Branch (Tree a) a (Tree a)
data List a = Nil | Cons a (List a)
data [a] = [] | (a : [a])
Note that all of these have the form TypeConstructor a, except for [a]! Indeed, to make the world more coherent, we should actually write [] a instead of [a].
This also makes it clear that [] is a type constructor, exactly like Identity, Maybe, Tree, ....
The syntax [a] is convenient, and possibly easier to read, especially for a beginner. However, it makes understanding the real nature of [] harder. Maybe has no such issue, by comparison.
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.
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'