I came across this function
iter p f x = if (p x) then x else (iter p f (f x))
and I thought I'd give a go at defining the polymorphic types myself to understand the concept.
My thought was the following:
The function takes 3 parameters, so we have t1 -> t2 -> t3 -> T
p is being used inside the if condition so it must return a bool, therefore t1 = a -> Bool
f is also the same type as p because it is passed as an argument in the else block, therefore t2 = a -> Bool
x is being used inside the if condition so it must return a bool, therefore t1 = a -> Bool
But when i checked the type in the ghci, the type they gave me was
iter :: (t -> Bool) -> (t -> t) -> t -> t
Can someone please explain the reasoning behind this.
Thanks
The function takes 3 parameters, so we have t1 -> t2 -> t3 -> T
This is correct as a starting point.
p is being used inside the if condition so it must return a bool, therefore t1 = a -> Bool
Correct.
f is also the same type as p because it is passed as an argument in the else block, therefore t2 = a -> Bool
Incorrect. f is never used in the same way as p. In the else block f is being applied to x and the result passed as the last argument to iter. From that we know f x must be the same type as x so f :: a -> a.
x is being used inside the if condition so it must return a bool, therefore t1 = a -> Bool
Incorrect. In the if condition x is being used only as an argument to p. You established above p :: a -> Bool. Therefore x :: a.
But when i checked the type in the ghci, the type they gave me was
iter :: (t -> Bool) -> (t -> t) -> t -> t
Correct. You could also write this replacing t with a to be consistent in the notation - we used a above:
iter :: (a -> Bool) -> (a -> a) -> a -> a
Let's evaluate it again:
iter p f x = if (p x) then x else (iter p f (f x))
iter takes three parameters (well technically speaking every function takes one parameter, but let's skip the details). So it has indeed a type t1 -> t2 -> t3 -> t.
Now in the if-then-else statement, we see (p x) this means that p x has to evaluate to a boolean. So that means that:
t1 ~ t3 -> Bool
Next we see x in the then statement. This may strike as non-important, but it is: it means that the output type t is the same as that of t3, so:
t3 ~ t
Now that means we already derived that iter has the type:
iter :: (t3 -> Bool) -> t2 -> t3 -> t3
Now we see in the else statement the call:
iter p f (f x)
So that means that f is a function f :: t4 -> t5. Since it takes x as input, its input type should be t3, and since the result of (f x) is passed to an iter function (that is not per se the same "grounded" iter function). So we have to inspect the call:
iter :: (u3 -> Bool) -> u2 -> u3 -> u3 -- call
Now since we call it with iter p f (f x) we definitely know that u3 ~ t3: because p has type t3 -> Bool. So it grounds further to:
iter :: (t3 -> Bool) -> u2 -> t3 -> t3 -- call
Sine (f x) is used as third argument, we know that the type of the result of f x should be t3 as well. So f has type f :: t3 -> t3. So we conclude that iter has the type:
iter :: (t3 -> Bool) -> (t3 -> t3) -> t3 -> t3
Related
I have the following two type signatures in Haskell:
foo :: (a -> (a,b)) -> a -> [b]
bar :: (a -> b) -> (a -> b -> c) -> a -> c
I want to write a concrete implementation of these two functions but I'm really struggling to understand where to start.
I understand that foo takes a function (a -> (a,b)) and returns a and a list containing b.
And bar takes a function (b -> c) which returns a function (a -> b -> c) which finally returns a and c.
Can anyone show me an example of a concrete implementation?
How do I know where to start with something like this and what goes on the left side of the definition?
You have some misunderstandings there:
I understand that foo takes a function (a -> (a,b)) and returns a and a list containing b.
No, it doesn't return a. It expects it as another argument, in addition to that function.
And bar takes a function (b -> c) which returns a function (a -> b -> c) which finally returns a and c.
Same here. Given g :: a -> b, bar returns a function bar g :: (a -> b -> c) -> a -> c. This function, in turn, given a function h :: (a -> b -> c), returns a function of type a -> c. And so it goes.
It's just like playing with pieces of a puzzle:
foo :: (a -> (a,b)) -> a -> [b]
-- g :: a -> (a,b)
-- x :: a
-- g x :: (a,b)
foo g x = [b] where
(a,b) = g x
bar :: (a -> b) -> (a -> b -> c) -> a -> c
-- g :: a -> b
-- x :: a
-- g x :: b
-- h :: a -> b -> c
-- h x :: b -> c
-- h x (g x) :: c
bar g h x = c where
c = ....
There's not much free choice for us here. Although, there are more ways to get more values of type b, for foo. Instead of ignoring that a in (a,b) = g x, we can use it in more applications of g, so there actually are many more possibilities there, like
foo2 :: (a -> (a,b)) -> a -> [b]
foo2 g x = [b1,b2] where
(a1,b1) = g x
(a2,b2) = g a1
and many more. Still, the types guide the possible implementations. foo can even make use of foo in its implementation, according to the types:
foo3 :: (a -> (a,b)) -> a -> [b]
foo3 g x = b : bs where
(a,b) = g x
bs = ...
So now, with this implementation, the previous two become its special cases: foo g x === take 1 (foo3 g x) and foo2 g x === take 2 (foo3 g x). Having the most general definition is probably best.
In addition to #will-nes's answer, it will be useful to treat (->) as a right-associative infix operator. So something like f: a -> b -> c is the same as f: a -> (b -> c). So this is saying f is a function that takes a value of type a and returns you a value of type b -> c, which is, another function, one that takes a value of type b and returns you a value of type c.
So the types in your example can be re-written as follows
foo :: (a -> (a,b)) -> (a -> [b])
bar :: (a -> b) -> ((a -> (b -> c)) -> (a -> c))
Similarly, you can think of arguments to a function in pieces as well, as being left-associative (like + and -), though there's no explicit operator in this case. foo a b c d e is the same as ((((foo a) b) c) d) e. For example, let's say we have a function f: Int -> Int -> Int (which is the same as f: Int -> (Int -> Int)). You don't have to provide both arguments at once. So you can write g = f 1, which has the type (Int -> Int). And then you can provide an argument to g, like g 2, which has the type Int. f 1 2 and let g = f 1 in g 2 are more or less the same. Here's a more concrete example of how this works:
Prelude> f = (+)
Prelude> g = f 1
Prelude> g 2
3
Prelude> :t f
f :: Num a => a -> a -> a
Prelude> :t g
g :: Num a => a -> a
Prelude> :t g 2
g 2 :: Num a => a
In #will-nes's sample implementation examples, he defines the functions with all of the arguments up front, but you don't have to think of them that way. Just think of f: a -> b -> c as taking a value of type a and returning another function. While most of the methods you encounter will use all of their arguments up-front, there might be cases in which you don't want to do that. Here's an example:
veryExpensive :: A -> B
unstagedFun :: A -> (B -> C) -> C
unstagedFun a f = f (veryExpensive a)
stagedFun :: A -> (B -> C) -> C
stagedFun a = let b = veryExpensive a in \f -> f b
(You can also rewrite the latter as let b = veryExpensive a in ($ b))
Of course, with compiler optimizations, I wouldn't be surprised if the unstaged version staged automatically, but hopefully this offers some motivation for thinking of functions as not having multiple arguments, but rather, as a single argument, but they may return other functions that may themselves return functions (but also only take a single argument).
Im trying to define the polymorphic type of the following function:
flip f x y = f y x
My thought was the following:
1st parameter of flip, f takes two arguments so (t1 -> t2 -> t3)
2nd parameter of flip, x is of type t1 because of the parameter t1 inside f function.
3rd parameter of flip, y which is of type t3 because of the parameter t3 inside f function.
I don't know the polymorphic type of the overall return.
But when I checked the type in the ghci, I get:
flip :: (t2 -> t1 -> t) -> t1 -> t2 -> t
Can someone please help go through this example was to whats happening here?
Thanks
Your second assumption is wrong:
2nd parameter of flip, x is of type t1 because of the parameter t1 inside f function.
Let us first analyze the function:
flip f x y = f y x
We see that flip has three arguments in the head. So we first make the type:
flip :: a -> (b -> (c -> d))
We will of course now aim to fill in the types. With:
f :: a
x :: b
y :: c
flip f x y :: d
We see on the right hand side:
(f y) x
So that means that f is a function that takes as input y. So that means that a is the same type as c -> e (or shorter a ~ c -> e).
So now:
flip :: (c -> e) -> (b -> (c -> d))
f :: (c -> e)
x :: b
y :: c
Furthermore we see that:
(f x) y
So the result of (f x) is another function, with as input y. So that means that e ~ b -> f. Thus:
flip :: (c -> (b -> f)) -> (b -> (c -> d))
f :: c -> (b -> f)
x :: b
y :: c
Finally we see that (f y) x is the result of flip f x y. So that means that the type of the result of (f y) x is the same type as d. So that means that f ~ d. Which thus means that:
flip :: (c -> (b -> d)) -> (b -> (c -> d))
Or if we drop some redundant brackets:
flip :: (c -> b -> d) -> b -> c -> d
This is just a matter of solving a system of equations. First, assign unknown types:
f : a1
x : a2
y : a3
Next, f is applied to y. So, f must be a function type with argument of the same type as y, that is
f : a1 = a3 -> a4
f y : a4
Similarily, f y is applied to x, so
f y : a4 = a2 -> a5
f y x : a5
Substituting this back, we get
f : a3 -> a2 -> a5
x : a2
y : a3
We can rename these types
t2 = a3
t1 = a2
t = a5
and get
f : t2 -> t1 -> t
x : t1
y : t2
The function body is f y x, which has type t = a5.
I start to learn Haskell. While studying a tutorial I have found the following example that enables the usage of functions in arithmetic expressions:
module FunNat where
instance Num a => Num (t -> a) where
(+) = fun2 (+)
(*) = fun2 (*)
(-) = fun2 (-)
abs = fun1 abs
signum = fun1 signum
fromInteger = const . fromInteger
fun1 :: (a -> b) -> ((t -> a) -> (t -> b))
fun1 = (.)
fun2 :: (a -> b -> c) -> ((t -> a) -> (t -> b) -> (t -> c))
fun2 op a b = \t -> a t `op` b t
The example works. But I can not understand how the (+) function is transformed into the function of two arguments. As I can understand each (+) is substituted with fun2 (+). And fun2 is equivalent to the function of one argument \t -> a t 'op' b t, but we should have a function of two arguments (something like (\t1 t2 -> (\x -> x ) t1 + (\x -> x) t2) ). I think that here some basic concepts of Haskell typing should be applied but I do not know what they are.
EDIT 1
I understand that fun2 is a function of three arguments. I can't understand internal expression transformation. I'm reasoning in the following way: (+) 3 4 = (+) (\x->3) (\x->4) = fun2 (+) (\x->3) (\x->4) = \t -> (\x->3) t + (\x->4) t
What is this t? Or where am I wrong in my reasoning? May be it is necessary to think another way?
EDIT 2
I think that I have reached some understanding of the issue (thanks you all!). So:
When we write (+) 3 4 - in this case a simple operation from Num is used, no special features from FunNat. To use (+) from FunNat it is necessary to write fun2 (+) 3 4 or fun2 (+) (\x -> 3) (\x -> 4). But these expressions expect any third parameter to be evaluated;
To demonstrate specific features from FunNat we may use the following example ((*)-(+)) (taken from tutorial) or in other form - (-) (*) (+). Both expressions take two arguments. In this case we have: ((*)-(+)) = fun2 (-) (*) (+) = \t -> (*) t - (+) t = \t -> (\t1 t2 -> t1 * t2) t - (\t1 t2 -> t1 + t2) t = (\t t2 -> t * t2) - (\t t2 -> t + t2) = \t t2 -> (t * t2) - (t + t2). The final expression expects just Num. I hope that all these are correct
As it was explained in tutorial, but I can't understand what for, the possibility to use (*) and (+) as parameters for fun2 that expects (t->a) is based on the following (taken from tutorial): t1 -> t2 -> a = t1->a' where a' = t2 -> a. Here curring is used.
So all necessary facts were on the surface but I do not take into consideration the non-trivial mechanism of type inference.
The type of (+) is Num a => a -> a -> a. Since you're creating an instance of Num for the type Num a => t -> a, consider the explicit signature
(+) :: Num a => (t -> a) -> (t -> a) -> (t -> a) (1)
or equivalently (by currying)
(+) :: Num a => (t -> a) -> (t -> a) -> t -> a (2)
What this says is: "If you give me 2 strategies for producing a Num a => a from a t, I can create a new strategy for producing a Num a => a from a t by using the Num.(+) instance of the a's"
I think the part that has you confused is that this specific (+) can be viewed as a function of 2 arguments which returns a function (1), or a function of 3 arguments which returns a value (2). Since functions in Haskell are curried, these are really the same thing.
In type signatures parentheses associate to the right, so:
f :: a -> (b -> c -> d)
is the same as:
f :: a -> b -> c -> d
So the parens indicated below are redundant:
fun2 :: (a -> b -> c) -> ((t -> a) -> (t -> b) -> (t -> c))
^ ^
and removing them leaves:
fun2 :: (a -> b -> c) -> (t -> a) -> (t -> b) -> (t -> c)
arg1 arg2 arg3
I have the following structure:
Terra [['0','1','0','1'],['0','1','0','1'],['1','0','G','1']]
and de function:
esTerra:: Taulell -> (Int,Int) -> Bool
esTerra t (u,d) =
case t!!!u!!!d of
Left e -> False
Right p -> True
(!!!) :: [a] -> Int -> Either Bool a
xs !!! n | n < 0 = Left False -- error Exception: Prelude.!!:...
[] !!! _ = Left False -- error Exception: Prelude.!!:...
(x:_) !!! 0 = Right x
(_:xs) !!! n = xs!!!(n-1)
the function !!! is equal the operation !! but when you have to return an error message returns False
but return error:
Couldn't match expected type ‘[a0]’
with actual type ‘Either Bool [Char]’
In the first argument of ‘(!!!)’, namely ‘t !!! u’
In the expression: t !!! u !!! d
In the expression:
case t !!! u !!! d of {
Left e -> False
Right p -> True }
Because?
Thank's
I don't know what Taulell is, let's guess Taulell = [[a]] for some a.
We have
t :: [[a]] -- Taulell
u :: Int
d :: Int
hence
t !!! u :: Either Bool [a]
Then we write
(t !!! u) !!! d
but here the leftmost argument is not a list, it's an Either Bool [a]. Hence a type error arises.
Instead, we could try, e.g.
case t !!! u of
Left b -> ...
Right l -> case l !!! d of
Left c -> ...
Rigth w -> ...
!!! needs a list as its left argument, but for a nested list it does not give a simple list as the result. It gives an Either Bool [a] as the result.
You can't use that again as the argument to !!!, but you can easily enough apply !!! to the Either-contained list:
esTerra:: Taulell -> (Int,Int) -> Bool
esTerra t (u,d) =
case t!!!u >>= (!!!d) of
Left e -> False
Right p -> True
Here, I've used the monadic bind operator >>= to combine two possibly-failing lookups into one, which will succeed only if both lookups do. This is equivalent to twice explicitly unwrapping the Either structure with a case construct, as shown by chi.
Im trying to understand Haskell and I have a question: What is the type of this function and how do you call it.
two f(a,b) = f a b
If we take, for example, arguments of type Int, then the type of two is like this:
two :: (Int -> Int -> Int) -> (Int, Int) -> Int
two f (a,b) = f a b
example:
two (*) (3,4)
12
Explanation:
You are taking a function that takes 2 arguments (Int -> Int -> Int)and a tuple (Int, Int) and applying that function to a and b.
The actual type, when not constrained, is actually like this:
:t two
two :: (t1 -> t2 -> t) -> (t1, t2) -> t
So for example other things are possible:
two (++) ("he","llo")
"hello"
(etc etc.)