Assume
f x y z = x*y*z
Then I expect to return the application of f three times with each member of the list
foldl ($) f [1,2,3]
Something like (((f 1) 2) 3) = 1*2*3 = 6
The function f would be the accumulator and each iteration of the fold would apply one argument and return a partially applied function as the next accumulator.
Why doesn't this work? Is it because f changes type while iterating?
As an aside: is there any other way to accomplish this type of function application?
The types look like
foldl :: (a -> b -> a) -> a -> [b] -> a
($) :: (x -> y) -> x -> y
To apply foldl to ($) requires matching (technically, unifying) the type of the first argument to foldl with the type of ($). That is, solving the equation
a -> b -> a = (x -> y) -> x -> y
This leads immediately to
a = x -> y
b = x
a = y
Substituting the second and third equations into the first:
a = b -> a
The problem is that Haskell has no type that solves this equation. In particular, it is impossible to write down a solution with a finite number of symbols! It expands first to
a = b -> b -> a
then
a = b -> b -> b -> a
and on forever. So there is no way to choose types for the type variables to make them match, and GHC will complain loudly.
In general, you can't do what you're trying to do because the type system distinguishes between functions with different numbers of arguments. What you're trying to do, essentially, is convert a list of values into a list of arguments for a function, which doesn't make sense in context.
However, the instance you're pointing at is literally just foldl (*). If you're performing the same operation on all of the variables in a function, you can just use this (well, you should be using either foldl' or foldr, but you get the idea).
Related
Let's say we have these 2 functions
f1 :: Int -> [Int] -> Int -> [Int]
f1 _ [] _ = []
f1 x (h:t) y = (x * h + y):(f1 x t y)
f2 :: [Int] -> Int
f2 (h:t) = h
Why does (f2 . f1 1 [1..10]) 1 work, but (f2 . f1 1) [1..10] 1 doesn't work?
All functions in Haskell take exactly one argument and return one value. The argument and/or the return type could be another function.
f1 has an argument type of Int and a return type of [Int] -> Int -> [Int]. The right associativity of (->) means we don't have to explicitly write this as
f1 :: Int -> ([Int] -> (Int -> [Int]))
but can instead drop the parentheses.
(Yes, (->) is an operator. You can use :k in GHCi to see the kind, but unfortunately what you get back is more complicated than we want to explain here:
> :k (->)
(->) :: TYPE q -> TYPE r -> *
Don't worry about what TYPE q and TYPE r stand for. Suffice it to say that (->) takes two types and returns a new type, and we can assume a simpler kind like
(->) :: * -> * -> *
The kind * is the kind of an ordinary type, more frequently written as Type these days.
)
In order to compose two functions, the return type of one must match the argument type of the other. We can see this from the type of (.) itself:
(.) :: (b -> c) -> (a -> b) -> a -> c
^ ^
That's not the case with f1 and f2:
-- vvvvvvvvvvvvvvvvvvvvv
f1 :: Int -> ([Int] -> Int -> [Int])
f2 :: [Int] -> Int
-- ^^^^^
-- [Int] -> Int -> [Int] and [Int] are different types
nor with f1 1 and f2
-- vvvvvvvvvvvv
f1 1 :: [Int] -> (Int -> [Int])
f2 :: [Int] -> Int
-- ^^^^^
-- Int -> [Int] and [Int] are different types
but it is true of f1 1 [1..10] and f2:
-- vvvvv
f1 1 [1..10] :: Int -> [Int]
f2 :: [Int] -> Int
-- ^^^^^
-- [Int] and [Int] are the same type
While (->) is right-associative, function application is left-associative, which is why we can write
((f1 1) [1..10]) 1
as f1 1 [1..10] 1 instead, leading to the appearance of f1 as taking 3 arguments, rather than an expression involving 3 separate function calls. You can see the three calls more clearly if you use a let expression to name each intermediate function explicitly:
let t1 = f1 1
t2 = t1 [1..10]
t3 = t2 1
in t3
As a complement to chepner's excellent answer, here's a less formal way of looking at it (which might be more intuitive if you haven't assimilated the formalities yet).
You seem to be thinking of (f . g) arg as a special syntactic form that will pass the argument to g and then call f on the result1. In fact this isn't what happens (or at best it's a shorthand for what happens).
Remember that functions are first class in Haskell. Frequently when that is brought up it means that we are passing functions as values to other functions, or storing them in data structures. But here what we need to remember is that first-class values can be computed as the result of expressions. f . g is an expression that computes a new function, in precisely the same manner that 7 + 9 is an expression that computes a new integer.
So (f . g) arg is not passing arg to g. It's passing arg to the function that is computed by the expression f . g. And if we had multiple arguments where arg is written, as in (f . g) x y z they would all be passed to the whole function f . g. There is no way for any of them to be passed to g directly.
The . operator builds a new function out of f and g by producing a function that behaves as follows: it takes a single argument x, passes it to g and then passes the result of that to f. In Haskell syntax that is basically (f . g) x = f (g x)2. So if we try to pass multiple arguments, as in (f . g) x y z, we end up with this:
(f . g) x y z = (f (g x)) y z
You can see this doesn't end up passing more arguments to g before g's result is fed to f; rather y and z end up being passed to the final result after x has been fed all the way through g and f (this is only going to work if f itself returns a function after being applied to one argument3). A simple way to think of it is that the first argument to the composed function "flows through the composition pipeline"; any other arguments will be passed to the result, after x has "flowed through". If we wanted the extra arguments to be passed to g, we should write it this way:
(f . g x y) z = f (g x y z)
Note that this reframes the "flow"; now it's z that is feeding through the composed functions. x and y have moved to being part of the definition of one of the two composed functions (g x y is every bit as much of an "expression that computes a function" as f . g is). If you really want the emphasis to be on x "flowing through" the composition pipeline, you'll need to change the way you defined g so that it takes arguments in a different order. This is a big part of why Haskellers frequently write functions to take the "main thing being operated on" as their last argument.
With all that in mind, your question should be pretty clear now.
In (f2 . f1 1 [1..10]) 1 the outermost 1 will "flow through the pipeline"; the first stage of the pipeline is f1 1 [1..10] (so the 1 will end up as a third argument to f1).
Whereas in (f2 . f1 1) [1..10] 1, the [1..10] will "flow through the pipeline", and the outer 1 will only be passed to the final result of the whole pipeline, not to the first stage of the pipeline. And the final result of the composition pipeline is the result of f2, which is a simple Int and cannot be applied to more arguments.
1 Haskell does have syntax for "pass multiple arguments to one function, then call another function on the result of that". However it's much more pedestrian. Just write f (g x y z). If this looks simpler to you than trying to twist it into a chain of function compositions, then just write it directly.
2 (f . g) x = f (g x) is almost the literal definition of the . operator. The real definition is f . g = \x -> f (g x). This definition is equivalent in the sense that it always produces exactly the same result, but it is usually a bit more efficient.
3 And your f2 example does not return a function after being applied to one argument (it just returns an Int), so we can see that (f2 . _anything_) arg1 arg2 is definitely going to be a type error with no further analysis, no matter what other function you're composing or what the two arguments are.
substitute':: (Eq a)=> a -> a -> [a] -> [a]
substitute' x y = map substituteOne
where
substituteOne x' | x == x' = y
| otherwise = x'
So, the point of this function is, that it takes two inputs of type a and a list of type a and substitutes all elements in list [a] that are from the "first" a with the "second" a. At least that is what the task description says.
I already implemented a recursive version, but a function with a where clause is also needed.
So THAT is the solution for it. Somehow I have questions:
how can substituteOne in the second line work without any parameters?
where do we give a list as input? or where do we state WHAT we do with that list? I mean compiling and eecuting it works, but somehow I don't see it
what is x' ? it is never defined anywhere, we just start working with it somehow (maybe refers also to question 1)
map needs a function and a list, so that it works. here we have map function _. refers maybe to 2., but what would be the output of substituteOne x' ?
If needed, result looks like this:
substitute' 5 10 [1, 5, 2, 5, 3, 5]
[1,10,2,10,3,10]
(1) how can substituteOne in the second line work without any parameters?
(2) where do we give a list as input? or where do we state what we do with that list? I mean compiling and executing it works, but somehow I don’t see it
The parameters are still there; this is currying at work. Consider the section of an infix operator (+1), which is a special case of partial application. Given a number, it produces a number that is one greater. Witness:
λ> :t (+1)
(+1) :: Num a => a -> a
We could define a function to increment all elements of a list by naming the list
λ> :t \l -> map (+1) l
\l -> map (+1) l :: Num b => [b] -> [b]
but that turns out to be unnecessary because of currying.
λ> :t map (+1)
map (+1) :: Num b => [b] -> [b]
This is functional programming, after all. With Haskell, we manipulate functions as easily as other languages manipulate strings.
(3) what is x'? it is never defined anywhere, we just start working with it somehow (maybe refers also to question 1)
But you do define x' as a parameter of substituteOne!
Consider the type of map:
λ> :t map
map :: (a -> b) -> [a] -> [b]
Its first argument is a function of one parameter. For your program to typecheck, the types have to line up. We can emphasize this for substituteOne by adding an optional type annotation — but have to work a bit harder (by enabling the scoped type variables extension) because substituteOne is an inner function with references to the outer scope,
substitute':: forall a. Eq a => a -> a -> [a] -> [a]
substitute' x y = map substituteOne
where
substituteOne :: a -> a
substituteOne x' | x == x' = y
| otherwise = x'
(4) map needs a function and a list, so that it works. here we have map function _. refers maybe to 2., but what would be the output of substituteOne x'?
Using unnamed arguments at the point of application as your code does with map substituteOne is known as pointfree style. In your case, there are two invisible “points” or variable names: the argument to substituteOne and the list argument to map.
You could be explicit about everything, as in
substitute'' :: Eq a => a -> a -> [a] -> [a]
substitute'' x y l = map (\x' -> if x == x' then y else x') l
but that is much more cluttered in comparison.
The values produced by substituteOne are collected in the list that results from map.
substitute has type a -> a -> [a] -> [a], which means it takes one argument and returns a function of type a -> [a] -> [a]. This is because (->) is right-associative, and the above type is equivalent to a -> (a -> [a] -> [a]).
Since function application is left-associative, a call like substitute x y is equivalent to (substitute x) y; y is the argument to the function returned by substitute x.
When one writes
substitute x y = ...
that is syntactic sugar for
substitute = \x -> \y -> ...
Further, since map substituteOne' has type [a] -> [a], that makes it a suitable value for substitute x y to return.
substitute1 takes a parameter x'. The bits between the | and = characters are guard conditions. Since this particular function has only one condition you could rewrite it like this:
substitute1 x' = if x == x' then y else x'
Because it is in the where clause substitute1 also has access to the parameters x and y of the main function.
Haskell newb here
I'm working on this problem in haskell:
(**) Eliminate consecutive duplicates of list elements.
If a list contains repeated elements they should be replaced with a single copy of the element. The order of the elements should not be changed.
Example:
* (compress '(a a a a b c c a a d e e e e))
(A B C A D E)
The solution (which I had to look up) uses foldr:
compress' :: (Eq a) => [a] -> [a]
compress' xs = foldr (\x acc -> if x == (head acc) then acc else x:acc) [last xs] xs
This foldr, according to the solution, takes two parameters, x and acc. It would seem like all foldr's take these parameters; is there any exception to this? Like a foldr that takes 3 or more? If not, is this convention redundant and can the formula be written with less code?
foldr takes a function of 2 arguments, but this doesn't prevent it from taking a function of 3 arguments provided that function has the right type signature.
If we had a function
g :: x -> y -> z -> w
With
foldr :: (a -> b -> b) -> b -> [a] -> b
Where we want to pass g to foldr, then (a -> b -> b) ~ (x -> y -> z -> w) (where ~ is type equality). Since -> is right associative, this means we can write g's signature as
x -> y -> (z -> w)
and its meaning is the same. Now we've produced a function of two parameters that returns a function of one parameter. In order to unify this with the type a -> b -> b, we just need to line up the arguments:
a -> | x ->
b -> | y ->
b | (z -> w)
This means that b ~ z -> w, so y ~ b ~ z -> w and a ~ x so g's type really has to be
g :: x -> (z -> w) -> (z -> w)
implying
foldr g :: (z -> w) -> [x] -> (z -> w)
This is certainly not impossible, although more unlikely. Our accumulator is a function instead, and to me this begs to be demonstrated with DiffLists:
type DiffList a = [a] -> [a]
append :: a -> DiffList a -> DiffList a
append x dl = \xs -> dl xs ++ [x]
reverse' :: [a] -> [a]
reverse' xs = foldr append (const []) xs $ []
Note that foldr append (const []) xs returns a function which we apply to [] to reverse a list. In this case we've given an alias to functions of the type [a] -> [a] called DiffList, but it's really no different than having written
append :: a -> ([a] -> [a]) -> [a] -> [a]
which is a function of 3 arguments.
As with all things in haskell have a look at the types of things to guide your way you can do this for any function in ghci.
Looking at this for foldr we see:
Prelude> :t foldr
foldr :: (a -> b -> b) -> b -> [a] -> b
This slightly abstract string can be written in english as:
foldr is a function that takes
1 ) a function with two parameters one of type a and one of type b and returns something of type b
2 ) A value of type b
3 ) A list of values of type a
And returns a value of type b
Where a and b are type variables (see here for a good tutorial on them) which can be filled in with any type you like.
It turns out that you can solve your compress problem using a foldr with a three-argument function.
compress :: Eq a => [a] -> [a]
compress [] = []
compress (z:zs) = z : foldr f (const []) zs z
where f x k w | x==w = k x
| otherwise = x : k x
Let's dissect that. First, we can improve readability by changing the last two lines to
where f x k = \w -> if x==w then k x else x : k x
This makes it evident that a ternary function is nothing but a binary function returning a unary function. The advantage of looking at it in this way is that foldr is best understood when passed a binary function. Indeed, we are passing a binary function, which just happens to return a function.
Let's focus on types now:
f :: a -> (a -> [a]) -> (a -> [a])
f x k
So, x::a is the element of the list we are folding on. Function k is the result of the fold on the list tail. The result of f x k is something having the same type as k.
\w -> if .... :: (a -> [a])
The overall idea behind this anonymous function is as follows. The parameter k plays the same role as acc in the OP code, except it is a function expecting the previous element w in the list before producing the accumulated compressed list.
Concretely, we use now k x when we used acc, passing on the current element to the next step, since by that time x will become the previous element w. At the top-level, we pass z to the function which is returned by foldr f (const []).
This compress variant is lazy, unlike the posted solution. In fact, the posted solution needs to scan the whole list before starting producing something: this is due to (\x acc -> ...) being strict in acc, and to the use of last xs. Instead, the above compress outputs list elements in a "streaming" fashion. Indeed, it works with infinite lists as well:
> take 10 $ compress [1..]
[1,2,3,4,5,6,7,8,9,10]
That being said, I think using a foldr here feels a bit weird: the code above is arguably less readable than the explicit recursion.
I am new to haskell and trying out some exercises
I dont understand whats the error generated and why it is generated
split = foldr
(\x y -> y:x)
[[]]
the error on the interpretator is as below
Occurs check: cannot construct the infinite type: a0 = [a0]
In the first argument of `(:)', namely `y'
In the expression: y : x
In the first argument of `foldr', namely `(\ x y -> y : x)'
Failed, modules loaded: none.
anyone can help? Thanks in advance
Type of foldr is
foldr :: (a -> b -> b) -> b -> [a] -> b
so in split
split = foldr (\x y -> y:x) [[]]
y and y:x has to be of same type, which is not possible for any x and y as y:x will always be one step deeper in the list than y.
I think you wanted to do x:y?
Recall the type of foldr: (a -> b -> b) -> b -> [a] -> b. This says that foldr expects a function that combines an element of the list with a value of the final result type, producing a new value of the result type.
For the first argument, you've given foldr the function \x y -> y:x, where x will be the list elements and y the result of the next step to the right; and the result of applying this lambda should have the same type as y.
But the type of (:) is a -> [a] -> [a]--that is, it appends a single element to the head of a list. In the expression y:x, you're taking something of the "result" type and using it as an element of a list used as the result.
Because of that, GHC attempts to infer that the result type b is the same as the type [b], which is then of course the same as the type [[b]], and [[[b]]]... and so on. Thus it complains about an "infinite type".
The posts before me answer your question, but after your comment i can see that you want a function that splits your list by a predicate.
You can use groupWith::Ord b => (a -> b) -> [a] -> [[a]] from the module GHC.Exts and supply it with a function of type (a -> Bool) in your example:
groupWith even [1,2,3,4,5,6] yields [[1,3,5],[2,4,6]]
Also, something ugly but that achieves the type of "outing" you want is:
split::Eq a => (a -> Bool) -> [a] -> [[a]]
split f ls = (ls \\ rl):rl:[]
where rl = filter f ls
But this will always split the supplied list in just two lists because of the binary function you supply.
Why is the type of this function (a -> a) -> a?
Prelude> let y f = f (y f)
Prelude> :t y
y :: (t -> t) -> t
Shouldn't it be an infinite/recursive type?
I was going to try and put into words what I think it's type should be, but I just can't do it for some reason.
y :: (t -> t) -> ?WTFIsGoingOnOnTheRHS?
I don't get how f (y f) resolves to a value. The following makes a little more sense to me:
Prelude> let y f x = f (y f) x
Prelude> :t y
y :: ((a -> b) -> a -> b) -> a -> b
But it's still ridiculously confusing. What's going on?
Well, y has to be of type (a -> b) -> c, for some a, b and c we don't know yet; after all, it takes a function, f, and applies it to an argument, so it must be a function taking a function.
Since y f = f x (again, for some x), we know that the return type of y must be the return type of f itself. So, we can refine the type of y a bit: it must be (a -> b) -> b for some a and b we don't know yet.
To figure out what a is, we just have to look at the type of the value passed to f. It's y f, which is the expression we're trying to figure out the type of right now. We're saying that the type of y is (a -> b) -> b (for some a, b, etc.), so we can say that this application of y f must be of type b itself.
So, the type of the argument to f is b. Put it all back together, and we get (b -> b) -> b — which is, of course, the same thing as (a -> a) -> a.
Here's a more intuitive, but less precise view of things: we're saying that y f = f (y f), which we can expand to the equivalent y f = f (f (y f)), y f = f (f (f (y f))), and so on. So, we know that we can always apply another f around the whole thing, and since the "whole thing" in question is the result of applying f to an argument, f has to have the type a -> a; and since we just concluded that the whole thing is the result of applying f to an argument, the return type of y must be that of f itself — coming together, again, as (a -> a) -> a.
Just two points to add to other people's answers.
The function you're defining is usually called fix, and it is a fixed-point combinator: a function that computes the fixed point of another function. In mathematics, the fixed point of a function f is an argument x such that f x = x. This already allows you to infer that the type of fix has to be (a -> a) -> a; "function that takes a function from a to a, and returns an a."
You've called your function y, which seems to be after the Y combinator, but this is an inaccurate name: the Y combinator is one specific fixed point combinator, but not the same as the one you've defined here.
I don't get how f (y f) resolves to a value.
Well, the trick is that Haskell is a non-strict (a.k.a. "lazy") language. The calculation of f (y f) can terminate if f doesn't need to evaluate its y f argument in all cases. So, if you're defining factorial (as John L illustrates), fac (y fac) 1 evaluates to 1 without evaluating y fac.
Strict languages can't do this, so in those languages you cannot define a fixed-point combinator in this way. In those languages, the textbook fixed-point combinator is the Y combinator proper.
#ehird's done a good job of explaining the type, so I'd like to show how it can resolve to a value with some examples.
f1 :: Int -> Int
f1 _ = 5
-- expansion of y applied to f1
y f1
f1 (y f1) -- definition of y
5 -- definition of f1 (the argument is ignored)
-- here's an example that uses the argument, a factorial function
fac :: (Int -> Int) -> (Int -> Int)
fac next 1 = 1
fac next n = n * next (n-1)
y fac :: Int -> Int
fac (y fac) -- def. of y
-- at this point, further evaluation requires the next argument
-- so let's try 3
fac (y fac) 3 :: Int
3 * (y fac) 2 -- def. of fac
3 * (fac (y fac) 2) -- def. of y
3 * (2 * (y fac) 1) -- def. of fac
3 * (2 * (fac (y fac) 1) -- def. of y
3 * (2 * 1) -- def. of fac
You can follow the same steps with any function you like to see what will happen. Both of these examples converge to values, but that doesn't always happen.
Let me tell about a combinator. It's called the "fixpoint combinator" and it has the following property:
The Property: the "fixpoint combinator" takes a function f :: (a -> a) and discovers a "fixed point" x :: a of that function such that f x == x. Some implementations of the fixpoint combinator might be better or worse at "discovering", but assuming it terminates, it will produce a fixed point of the input function. Any function that satisfies The Property can be called a "fixpoint combinator".
Call this "fixpoint combinator" y. Based on what we just said, the following are true:
-- as we said, y's input is f :: a -> a, and its output is x :: a, therefore
y :: (a -> a) -> a
-- let x be the fixed point discovered by applying f to y
y f == x -- because y discovers x, a fixed point of f, per The Property
f x == x -- the behavior of a fixed point, per The Property
-- now, per substitution of "x" with "f x" in "y f == x"
y f == f x
-- again, per substitution of "x" with "y f" in the previous line
y f == f (y f)
So there you go. You have defined y in terms of the essential property of the fixpoint combinator:
y f == f (y f). Instead of assuming that y f discovers x, you can assume that x represents a divergent computation, and still come to the same conclusion (iinm).
Since your function satisfies The Property, we can conclude that it is a fixpoint combinator, and that the other properties we have stated, including the type, are applicable to your function.
This isn't exactly a solid proof, but I hope it provides additional insight.