Haskell function type generalization - haskell

I am studying a Haskell course since I am total beginner. There is a task which I am not able to solve although I tried many times.
The task is to determine the most general type of following function:
f x _ False = x
f _ x y = maybe 42 (g y) x
providing we know that g :: a -> [a] -> b
Can anyone help me? Thank you
I tried to determine y :: Bool, g :: Bool -> [Bool] -> b(?)
But I am not sure what should be "x" 'cause from the first row we could say that it can be maybe 42 (g y) x but there is another "x" in the expression.
So maybe the type of the f is f :: [Bool] -> [Bool] -> Bool -> [Bool]?

Let us start with the most generic type possible: the function takes three parameters, and thus returns an item, so we assume first that f has type:
f :: a -> b -> c -> d
We see that the third parameter matches with False so that is a Bool, so c ~ Bool. The first clause also assigns the first parameter to x and returns x, so that means that the type a of the first parameter, and that of the return type d is the same, so a ~ d.
We know that maybe has type maybe :: f -> (e -> f) -> Maybe e -> f, and 42 is the first parameter so has type f. An integer literal can have any Num type, so we know Num f. Since the return type of maybe 42 (g y) x is also f and we know that this is also a, we know that f ~ a, so we can "specialize" maybe in this case to maybe :: Num a => a -> (e -> a) -> Maybe e -> a. The third parameter in maybe 42 (g y) x is x, this is the second parameter in the f call (not to be confused with the first clause), so we know that b ~ Maybe e.
We also see a call g y with g :: g -> [g] -> h. The type of g y should match that of the second parameter of the maybe call, so that means that e ~ [g] and a ~ h. y has type Bool in the g y call, so that means that g ~ Bool, and thus the g function has type g :: Bool -> [Bool] -> a.
Now we thus have gathered the following types and equivalences:
f :: a -> b -> c -> d
maybe :: f -> (e -> f) -> Maybe e -> f
g :: g -> [g] -> h
a ~ d
c ~ Bool
Num f
f ~ a
b ~ Maybe e
g ~ Bool
e ~ [g]
a ~ h
g ~ Bool
This thus means that f has type:
f :: a -> b -> c -> d
-> f :: a -> b -> c -> a
-> f :: a -> b -> Bool -> a
-> f :: Num f => f -> b -> Bool -> f
-> f :: Num f => f -> Maybe e -> Bool -> f
-> f :: Num f => f -> Maybe [g] -> Bool -> f
-> f :: Num f => f -> Maybe [Bool] -> Bool -> f
Hence the most generic type is f :: Num f => f -> Maybe [Bool] -> Bool -> f, or we can rename the parameters to f :: Num a => a -> Maybe [Bool] -> Bool -> a.
We can let ghci do the work, for example with:
ghci> import Data.Maybe
ghci> :{
ghci| g :: a -> [a] -> b
ghci| g = undefined
ghci| :}
ghci> :{
ghci| f x _ False = x
ghci| f _ x y = maybe 42 (g y) x
ghci| :}
ghci> :t f
f :: Num p => p -> Maybe [Bool] -> Bool -> p
This thus means that ghci confirms this type.

The first thing to realize is that, for any equation, any variables defined in that equation, are scoped only to that equation. In particular, this means that the x on the first line is not related at all to the x on the second line. These are two separate variables, they just happen to have the same name.
Now, you have already correctly determined that y :: Bool and g :: Bool -> [Bool] -> b for some as of yet unknown b. And therefore, g y :: [Bool] -> b
The next thing to observe is that, since maybe :: p -> (q -> p) -> Maybe q -> p, which means that q ~ [Bool] (coming from the type of g y) and p ~ Int (coming from the literal 42). And therefore, g :: Bool -> [Bool] -> Int and x :: Maybe [Bool] (since it's used as the third parameter of maybe).
Finally, from the second equation, we can see that the function's return type is whatever maybe returns, which is Int. And therefore, that's also the type of the first parameter, because it's being returned in the first equation.
Taking all of that together:
f :: Int -> Maybe [Bool] -> Bool -> Int
One final stroke: I actually lied a little. The literal 42 is not really Int. Such literal can be any type that has an instance of the Num class. To account for that, let's replace our Ints in the signature with a generic type and give that type a Num constraint:
f :: Num a => a -> Maybe [Bool] -> Bool -> a

Related

I don't understand the type declarations

I struggle to understand how type declarations work...
Like these ones for example:
t :: (a -> b) -> (b -> c) -> a -> c
s :: (a -> b -> c) -> (a -> b) -> a -> c
I know from just trying different things that the correct functions would look like this:
t :: (a -> b) -> (b -> c) -> a -> c
t f g x = g (f x)
s :: (a -> b -> c) -> (a -> b) -> a -> c
s f g x = f x (g x)
But how does this work? Why are the brackets at the end? Why is it not
t f g x = (f x) g
or
s f g x = (f x) g x
Im so lost
For the first example:
t :: (a -> b) -> (b -> c) -> a -> c
In a type declaration, the type1 -> type2 pattern indicates a function from type1 to type2. In type declarations, the -> operator is right-associative, so this is parsed as:
t :: (a -> b) -> ((b -> c) -> (a -> c))
This kind of construction is called "currying": providing the first argument (type a -> b) yields a function which accepts the second argument (type b -> c) which yields a function which accepts the third argument (type a).
The function declaration syntax is set up to do this automatically. The first two arguments are functions and the third is just a, so start with names that reflect that: f :: a -> b and g :: b -> c are functions, while x :: a is a fully generic type which could be anything.
t f g x = ...
Note that function application in Haskell is just concatenation: to apply function f to value x, just use f x. This syntax is left-associative, so t f g x is parsed as (((t f) g) x) to match the currying construction described above.
Anyway, given these types, you don't have much choice in how to put them together:
the only thing you know about the type a is that it's the type of x, and the argument type of f, so the only thing you can do with them is to apply the function to the value: f x.
the only thing you know about the type b is that it's the result type of f and the argument type of g, so the only thing you can do is apply g (f x).
the only thing you know about the type c is that it's the result type of g and of the overall function t, so the only thing t can return is g (f x).
The reason you can't do (f x) g is that the types don't match:
f :: a -> b
x :: a
(f x) :: b
g :: b -> c
So, you can apply g :: b -> c to (f x) :: b to get a result of type c. But not the other way around, because b might not even be a function type.

Defining a function that satisfies a type in Haskell

Considering the type
foo :: a -> ((b -> a) -> c) -> c
I want to create a function that satisfies this type...
I know foo x y = y (\z -> x) satisfies this type as confirmed with :type in GHCi, but how would I get to this final function manually, or step by step?
I also know foo2 f g = \x -> f (g x) would also satisfy foo2 :: (a -> b) -> (c -> a) -> c -> b but don't also know how to get to this function.
It's just a matter of fitting the matching pieces of a puzzle together. The same-named pieces match. The type of foo means it's a function with two parameters:
foo :: a -> ((b -> a) -> c) -> c
-- a f
foo a f = c
-- a :: a
-- f g :: c
-- g b :: a
where
c = f g -- produce a c-type value
g b = a -- define g to produce
-- the value a
f we're given, but g we must invent so that it returns a; fortunately, we're already given an a:
-- f :: ((b -> a) -> c)
-- g
-- g :: b -> a
a is given to us as a parameter of foo, and b is just an unused parameter of g.
Next we can substitute and simplify, using the fact that writing this:
p :: q -> r
p q = r...
is the same as writing this:
p :: q -> r
p = \q -> r...
where we use r... to indicate an expression whose type is r.
Also, s -> t -> r is the same as s -> (t -> r) because, similarly,
h :: s -> t -> r
h s t = r...
h s = (\t -> r...)
h = \s -> (\t -> r...)
all express the same thing.
Your second question can be addressed in the same manner.
x :: a means "the value x has type a"; a :: a means "the value a has type a". The same name a can be used in two different roles; when you're accustomed to it, it can actually be quite a helpful mnemonic.
See also.
An underscore _, or an undefined name beginning with an underscore such as _what, is treated by GHC as a “hole” that you want to fill in. You can use this to ask what type the compiler is expecting, and this can be helpful in figuring out how to iteratively fill in the program. Thankfully, this is a case where it’s very helpful, so I can easily go through it step by step in GHCi (with > indicating the prompt). We begin with a hole foo = _:
> foo :: a -> ((b -> a) -> c) -> c; foo = _
And we receive a message saying Found hole: _ :: a -> ((b -> a) -> c) -> c. GHC suggests foo :: a -> ((b -> a) -> c) -> c as a valid way of filling in the hole, and indeed foo = foo is legal, it’s just not the answer we’re looking for, since it represents an infinite loop.
Instead, we can look at the type and break it down into parts from the top down. We begin with a function type (->) whose input is a and whose output is ((b -> a) -> c) -> c. We can make a function value using a lambda expression, inventing a name for the a value, say x, and put another hole for the body:
> foo :: a -> ((b -> a) -> c) -> c; foo = \ x -> _
…
• Found hole: _ :: ((b -> a) -> c) -> c
…
It now mentions that we have x :: a available to work with, in addition to foo, but this isn’t quite enough, so next we can take apart ((b -> a) -> c) -> c into its input ((b -> a) -> c) and output c. (From now on, for brevity’s sake, I’ll also skip repeating the type signature of foo.)
> foo :: …; foo = \ x -> \ f -> _
…
• Found hole: _ :: c
…
We can’t take apart the type variable c any further, and we know we need to make a value of type c, so we can look at what we have available:
f :: (b -> a) -> c
x :: a
foo :: a -> ((b -> a) -> c) -> c
So our options are:
Recursively call foo
Call f
#1 would quickly put us back in the same situation we’re in, so #2 is all that’s left. f expects a value of type b -> a as an argument:
> foo :: …; foo = \ x -> \ f -> f _
…
• Found hole: _ :: b -> a
…
So again we can write a lambda:
> foo :: …; foo = \ x -> \ f -> f (\ y -> _)
…
• Found hole: _ :: a
…
The only way we can produce a value of the unknown type a is to use the value x :: a that we’ve been given, so the final result is this:
foo = \ x -> \ f -> f (\ y -> x)
And that can be written in exactly the same form as you put in your question, using a little syntactic sugar, and a couple different choices of variable names:
foo = \ x -> \ f -> f (\ y -> x)
foo x = \ f -> f (\ y -> x)
foo x f = f (\ y -> x)
foo x y = y (\ z -> x)
Question 1
foo :: a -> ((b -> a) -> c) -> c
says that foo has to take an a and a function with type (b -> a) -> c and somehow produce a c.
foo a function = c
where a::a and function::(b -> a) -> c
but where can we get the c from?
Good news: function makes cs for us.
Let's use that. function::(b->a) -> c so we can get a c if we give it a (b->a).
So we need to first make a helper function that takes bs and gives us as:
foo a function =
let helper b = a
That's fine! I already had an a so I could use that. We just need to hand function the helper we just made:
foo :: a -> ((b -> a) -> c) -> c
foo a function =
let helper b = a
in function helper
Now notice that helper ignores its input, so we could write
foo :: a -> ((b -> a) -> c) -> c
foo a function =
let helper _ = a
in function helper
And we can use lambda notation for helper:
foo :: a -> ((b -> a) -> c) -> c
foo a function =
let helper = \_ -> a
in function helper
But now we could just write (\_ -> a) instead of helper:
foo :: a -> ((b -> a) -> c) -> c
foo a function =
function (\_ -> a)
And finally, lets abbreviate function as f:
foo :: a -> ((b -> a) -> c) -> c
foo a f = f (\_ -> a)
Question 2
foo2 :: (a -> b) -> (c -> a) -> c -> b
OK, this time we need to make a b. We're given a c and a couple of functions for turning as into bs and cs into as:
foo2 :: (a -> b) -> (c -> a) -> c -> b
foo2
make_b_from_a
make_a_from_c
c
= b
Well, the only thing that can give us a b is make_b_from_a:
foo2 :: (a -> b) -> (c -> a) -> c -> b
foo2
make_b_from_a
make_a_from_c
c
= make_b_from_a a
but now we need an a, but we can use make_a_from_c for that, and we already have a c:
foo2 :: (a -> b) -> (c -> a) -> c -> b
foo2
make_b_from_a
make_a_from_c
c
= make_b_from_a (make_a_from_c c)
Let's shorten the names. I'm going to call the (c->a) one f because we use it before the other one, which I'll call g:
foo2 :: (a -> b) -> (c -> a) -> c -> b
foo2 g f c = g (f c)
We can take the last argument using a lambda:
foo2 :: (a -> b) -> (c -> a) -> c -> b
foo2 g f = \c -> g (f c)

Partially appplied function with (.) seems to take too few arguments

So, we have three functions:
A :: [([String], [String])] -> [String] -> [String]
A = B . C "*" f
B :: (a -> Maybe a) -> a -> a
C :: Eq a => a -> ([a] -> [a]) -> [([a], [a])] -> [a] -> Maybe [a]
The thing that confuses me about this is that A takes two arguments, and those arguments will then be the arguments to C when A is called. Then the result of C will be the argument(s) to B, but how is that possible since B is supposed to take two arguments, when C like every other function I've seen so far in Haskell will just return one value.
From what I can gather from the dot operator:
(.) f g = \x -> f (g x)
Using the dot in A allows it to be this "point free" style, and makes it more readable. But what it says is:
A x y = B (C "*" f x y)
But I'm obviously missing something, since if I write it like that then:
* Couldn't match expected type `a0 -> Maybe a0'
with actual type `Maybe [[Char]]'
And then I'm stumped.
Using the dot in A allows it to be this "point free" style, and makes it more readable. But what it says is:
A x y = B (C "*" f x y)
What it says is:
A x = B (C "*" f x)
since B has type B :: (a -> Maybe a) -> a -> a, it will return a function, and thus we can add an extra parameter:
A x y = B (C "*" f x) y
but these are different. Note that the (.) makes a chain for one parameter.
After all (.) is implemented like you say as:
(.) :: (b -> c) -> (a -> b) -> a -> c
(.) f g x = f (g x)
So here B is the left function, and (C "*" f) is the right function. So that means that (.) B (C "*" f) is equivalent to:
(.) B (C "*" f) x = B (C "*" f x)
If we analyze the types, we see:
(.) :: (b -> c ) -> ((a -> b) -> (a -> c))
B :: (d -> Maybe d) -> (d -> d)
--------------------------------------------------------------
b ~ (d -> Maybe d), c ~ (d -> d)
so that means the type of (.) B is (a -> (d -> Maybe d)) -> (a -> (d -> d)), or less verbose (a -> d -> Maybe d) -> a -> d -> d.
Now we can analyze the type of C "*" f:
C :: Eq a => a -> ([a] -> [a]) -> [([a], [a])] -> [a] -> Maybe [a]
"*" :: String
f :: ([a] -> [a])
--------------------------------------------------------------------
a ~ String
We do not know what f is here, but we will assume that it is a [String] -> [String] function, so the matching works.
This thus means that C "*" f has type [([String], [String])] -> [String] -> Maybe [String].
Now the types match, since:
(.) B :: ( a -> d -> Maybe d ) -> a -> d -> d
C "*" f :: [([String], [String])] -> [String] -> Maybe [String]
---------------------------------------------------------------------------------
a ~ [([String], [String])], d ~ [String]
So this means that (.) B (C "*" f) has type [([String], [String])] -> String -> String. This indeed holds if we determine this with ghci:
Prelude> :{
Prelude| b :: (a -> Maybe a) -> a -> a
Prelude| b = undefined
Prelude| :}
Prelude> :{
Prelude| c :: Eq a => a -> ([a] -> [a]) -> [([a], [a])] -> [a] -> Maybe [a]
Prelude| c = undefined
Prelude| :}
Prelude> :t b . c "*" undefined
b . c "*" undefined
:: [([[Char]], [[Char]])] -> [[Char]] -> [[Char]]

Type of "succ(zero)" differs from type of "one" in GHC

Asking the GHC to print the type of "one" and "succ zero" (lambda calculus way of encoding numerals), I get two different types!
Shouldn't they be the same?
Can you also show me how to derive its type manually?
zero = \ f x -> x
one = \ f x -> f x
succ = \ n f x -> f (n (f x))
:t one -- (t1 -> t2) -> t1 -> t2
:t succ zero -- ((t1 -> t1) -> t2) -> (t1 -> t1) -> t2
So as was said in the comments, the correct definition is
zero f x = x
succ n f x = f (n f x)
"do one more f after n applications of f, starting with x."
Thus
one f x = succ zero f x = f (zero f x) = f x
two f x = succ one f x = f (one f x) = f (f x)
The types which get derived are more general initially,
zero :: t -> t1 -> t1 -- most general
one :: (t1 -> t ) -> t1 -> t -- less general
succ one :: (t2 -> t2) -> t2 -> t2 -- most specific
but it doesn't matter, they all match (unify) between themselves, and starting from two = succ one the type settles down into the most specific (b -> b) -> (b -> b).
You could also define
church :: Int -> (b -> b) -> b -> b -- is derived so by GHCi
church n f x = foldr ($) x (replicate n f)
= foldr (.) id (replicate n f) x
{- church n = foldr (.) id . replicate n -- (^ n) for functions -}
and have all types be exactly the same, as
church 0 :: (b -> b) -> b -> b
church 1 :: (b -> b) -> b -> b
church 2 :: (b -> b) -> b -> b
It really doesn't matter.
As to the type derivations, it comes down to just using the modus ponens / application rule,
f :: a -> b
x :: a
-------------
f x :: b
Just need to be careful renaming each type consistently so there's no type variable capture introduced at any step:
succ n f x = f (n f x)
x :: a
f :: t , t ~ ...
n :: t -> a -> b
f :: b -> c , t ~ b -> c
succ n f x :: c
succ :: (t -> a -> b) -> (b -> c) -> a -> c
:: ((b -> c) -> a -> b) -> (b -> c) -> a -> c
(because final result type produced by succ is the same as the final result type produced by f -- i.e. c), or as GHCi puts it,
succ :: ((t1 -> t) -> t2 -> t1) -> (t1 -> t) -> t2 -> t
-- b c a b b c a c
Firstly, you want zero to be same type as one. In your equation for zero, you don't use f on rhs of ->. So the compiler doesn't know what type to infer. In your equation for one, you want f x (its result) to be same type as x (the result from zero). But you're not getting that either. It's easiest to give signatures, but failing that use asTypeOf.
In the equation for succ, you want its result to be same type as f x, same type as x.
Can you also show me how to derive its type manually?
OK let's achieve the above using asTypeOf. Then you can use :t to find the types ...
zero = \ f x -> (x `asTypeOf` f x)
one = \ f x -> (f x `asTypeOf` x)
succ = \ n f x -> (f (n f x)
`asTypeOf` f x `asTypeOf` x)
(I've used the correct definition for succ, per #LambdaFairy.)
Note that Church numerals are framed in the untyped lambda calculus -- that's what wikipedia is showing. As you get into more exotic functions over them (like addition or predecessor), you'll find that Haskell is a typed lambda calculus, and GHC will barf/you'll hit the dreaded monomorphism restriction. Then asTypeOf can't help you; you must resort to type signatures (of higher-rank).

What is the meaning of parentheses in Haskell type signatures?

Take the type signature of fmap (the Functor method) as an example:
(a -> b) -> f a -> f b
How is that different from the following type signature?
a -> b -> f a -> f b
Is there even a difference between those two type signatures?
Yes, there is a difference, because the -> type constructor is right-associative. In other words,
a -> b -> f a -> f b
is equivalent to
a -> (b -> (f a -> f b))
This type signature denotes a function that takes a parameter of type a and returns a function, which itself takes a parameter of type b and returns a function, which itself takes a parameter of type f a and returns a value of type f b.
On the other hand,
(a -> b) -> f a -> f b
denotes a function that takes a parameter of type a -> b (i.e. a function that takes a parameter of type a and returns a value of type b) and returns a function, which itself takes a parameter of type f a and returns a value of type f b.
Here is a contrived example that illustrates the difference between the two type signatures:
f :: (Int -> Bool) -> [Int] -> [Bool]
f = map
g :: Int -> Bool -> [Int] -> [Bool]
g n b = map (\n' -> (n' == n) == b)
λ> let ns = [42, 13, 42, 17]
λ> f (== 42) ns
[True,False,True,False]
λ> g 42 True ns
[True,False,True,False]
λ> g 42 False ns
[False,True,False,True]
Yes,
(a -> b) -> ...
means "given a function which takes a to b ...". While, this
a -> b -> ...
means "given some a and some b..."
Yes, the (a -> b) means one argument which is a function with signature a -> b, whereas a -> b -> ... means two arguments.

Resources