Why is Haskell unable to resolve the number of arguments automatically? [duplicate] - haskell

This question already has answers here:
Defining a function by equations with different number of arguments
(3 answers)
Closed 7 years ago.
I'm new to Haskell and I got confused by the following behavior:
I have a function, called dealWithIt. It looks like this:
dealWithIt :: (Show a) => [a] -> String
dealWithIt = foldl f ""
where f memo x = memo ++ (show x)
All good, it's working as expected, it gets a list of showables and concatenates them into a single string.
As much as I understand, it doesn't matter if I explicitly specify the argument received as long as it can be passed to the underlying chain of functions. That means the following two definitions should be equivalent:
dealWithIt xs = foldl f "" xs
dealWithIt = foldl f ""
So far so good. Let's say I want to add now a special case scenario by pattern matching:
dealWithIt [] = "Empty list :("
This is where things get weird. If I don't explicitly specify the xs argument, I get the following error:
Equations for ‘dealWithIt’ have different numbers of arguments
I can live with it, but it's really interesting to me why is Haskell unable to detect what's going on and reports an error even when both variants take a single argument?

It's just a rule. A definition of a function by cases:
f p0 p1 = e0
f p2 p3 = e1
has to have the same number of patterns in the function arguments on the left-hand side for all equations.
It's partly to simplify the definition of the language; the Haskell standard defines that function definition in terms of a single case expression:
f x0 x1 = case (x0, x1) of
(p0, p1) -> e0
(p2, p3) -> e1
Now consider what would happen if you could say
f p0 p1 = e0
f p2 = e1 -- `e1` is a function
The language standard would have to handle that case specially, and define it as something like
f x0 x1 = case (x0, x1) of
(p0, p1) -> e0
(p2, _) -> e1 x1 -- Note that the argument to `e1` has to be supplied explicitly
That's an un-necessary complication for something that it's not normally sensible to do.
Furthermore, consider the definition of foldr:
foldr f z [] = z
foldr f z (x:xn) = f x (foldr f z xn)
Suppose you were typing it in and you forgot the f on the first equation:
foldr z [] = z
foldr f z (x:xn) = f x (foldr f z xn)
The current rule allows typos like this to be caught: the compiler can complain that you have a different number of arguments in different equations. Otherwise you would get some confusing type error, which would probably be difficult to debug. (Probably you would get an error because z in the first equation has to have the same type as f in the second equation, and z in the first equation has to have the same type as f x (foldr f z xn) in the second equation, so the first argument to foldr has to have an infinite type. Infinite type errors are typically not fun to debug.)

Related

Why is it not possible to define an infix operator via an equation on a section?

Hutton's "Programming in Haskell", first edition, says that the concatenation operator ++ could be defined as:
(++ ys) = foldr (:) ys
This makes logical sense.
I had never seen an operator being defined by an equation on one of its sections (in this case (++ ys)), so I tried it myself:
(##) :: [a] -> [a] -> [a]
(## ys) = foldr (:) ys
However this doesn't compile, higlighting a syntax error in (## ys).
Has this never been a feature, or has it been removed at some point? If so, why?
I know I could write the above as:
xs ## ys = foldr (:) ys xs
But I find the point-free style more elegant.
This would result in some subtle inconsistencies. Although we tend to think of curried and flipped and uncurried functions as just different ways of writing the same thing, that is not quite true when it comes to the actual evaluation strategy. Consider
(#>) :: Integer -> Integer -> Integer
(#>) n = let p = {- the `n`-th prime number -} `mod` 74
in (p+)
Indexing prime numbers is costly. If you write something like
map ((2^43) #>) [100 .. 150]
then the 243-th prime number needs to be computed only once. By contrast, if I define
(<#) :: Integer -> Integer -> Integer
(<#) = flip foo
then writing map (<# (2^43)) [100 .. 150] would compute the prime number over and over again, because Haskell doesn't support partially applying functions on the second argument.
With the flip foo definition this isn't too surprising, but if I could have defined the flipped form directly as
(<#n) = let p = {- the `n`-th prime number -} `mod` 74
in (p+)
then one could reasonably expect that map (<# (2^43)) does share the prime computation, but to support that Haskell's partial evaluation semantics would need to track more information than they currently do, and if we want this to work reliably then it would probably incur some other disadvantages.
I think there's a simpler explanation to do with how complex already are the allowed syntactic forms on lhs of an = binding.
Please always post the error message you're getting, don't just say "higlighting a syntax error". The message might not mean a lot to you, but in this case it gives a strong hint:
(## ys) = ...
===> error: Parse error in pattern: ##ys
(xs ##) = ...
===> error: Expression syntax in pattern: xs ##
"in pattern" aha! That is, the lhs is potentially a syntactic pattern. Furthermore there might not be a signature decl for whatever you're introducing; even if there is, the compiler has to check your equation against the signature, so it can't assume anything about the arity of what you're introducing. Consider these valid equations
z = 42 -- z counts as a pattern
Just z = {- long and complex expr returning a Maybe, binds z at module-wide scope -}
(Just z) = {- same same, binds z at module-wide scope -}
foo x = ... -- foo gets module-wide scope but not x
(foo x) = ... -- same
bar x y = ... -- bar gets module-wide scope but not x, y
(bar x) y = ... -- same
(x ## y) z = ... -- accepted, introduces triadic operator ##
x ## y z = -- rejected error: Parse error in pattern: y
(x ##) y = -- rejected error: Expression syntax in pattern: x ##
(## y) z = -- rejected error: Parse error in pattern: ##y
The Language Report (section 4.4.3 Function and Pattern Bindings) has
decl -> (funlhs | pat) rhs
funlhs -> var apat { apat }
| pat varop pat
| ( funlhs ) apat { apat }
So the lhs is not a place where expression syntax (incl operator sections) can appear. See also the ugly detail at the end of section 4.4.3.1 to do with using lhs operator syntax in combo with a infix data constructor ugh!
The last sentence here also confirms you can't use operator sections on lhs.

Different fold in Haskell and SML/NJ

In foldl definition possible wrong in SML/NJ 110.75, I found that the relation foldl (op -) 2 [1] = foldr (op -) 2 [1] holds. But when I tried the above in Haskell I found that the above relation rewritten in Haskell as foldl (-) 2 [1] == foldr (-) 2 [1] doesn't hold. Why is this? Does Haskell have different definition for fold than SML/NJ?
Thanks
In ML, both folds have the same type signature:
val foldl : ('a * 'b -> 'b) -> 'b -> 'a list -> 'b
val foldr : ('a * 'b -> 'b) -> 'b -> 'a list -> 'b
whereas in Haskell they're different:
foldl :: (a -> b -> a) -> a -> [b] -> a
foldr :: (a -> b -> b) -> b -> [a] -> b
so Haskell's foldl is necessarily doing something different with the operation it's been given.
Similarities
The two languages agree on both the type and the value computed by foldr - a list folded into a value by moving righwards along the list, bracketed from the right hand end:
foldr f init [x1, x2, ..., xn]
==> f(x1, f(x2, ..., f(xn, init)...))
Differences
First, ML has
foldl f init [x1, x2, ..., xn]
==> f(xn,...,f(x2, f(x1, init))...)
So ML's foldl is a left fold in the sense that it folds the list leftwards instead of rightwards.
whereas in Haskell, you have
foldl f init [x1,x2,.....,xn]
==> f(f(...f(f(init,x1),x2),.....),xn)
In haskell, foldl is a left fold in the sense that it puts the initial value at the left and brackets the list from the left, but retains its order.
Your example
With a list with just a single element, ML does f(x1,init) which gives you x1 - init which happens to be the same as foldr's xn - init because the first and last elements are the same.
Conversely, Haskell does f(init,x1) which gives you init - x1. That's why you get the opposite answer.
Slightly longer example
ML's foldl:
foldl (op -) 100 [1,2,3,4]
==> 4 - (3 - (2 - (1 - 100)))
==> 102
ML/Haskell's foldr:
foldr (-) 100 [1,2,3,4] or foldr (op -) 100 [1,2,3,4]
==> 1 - (2 - (3 - (4 - 100)))
==> 98
Haskell's foldl:
foldl (-) 100 [1,]
==> (((100 - 1) - 2) - 3) - 4
==> 90
Conclusion
Yes the two definitions are different for foldl. ML's left means opposite order of elements, whereas Haskell's left means opposite order of bracketing.
This isn't a big problem as long as you remember which one you're using. (If the types of init and x1 are different, the type checker will tell you when you get it wrong.)
Does this help?
mlFoldl :: (a -> b -> b) -> b -> [a] -> b
mlFoldl f = foldl (flip f)
Long story short, they are essentially the same, with one minor difference: the order of the arguments passed to the operator (the combining function you pass to fold) are flipped. And since subtraction is not commutative, it will produce different results.
In Haskell (as well as OCaml, C++, Clojure, Common Lisp, Erlang, F#, JavaScript, PHP, Python, Ruby, Scala, and many others), for foldl, the supplied function's first argument is the initial value, or the "folded value so far", while the second argument is an element from the list.
However, in Standard ML, the supplied function's first argument is the element from the list, and the second argument is the initial value, or the "folded value so far".
Neither is "correct" or "incorrect". The order of arguments is purely a design decision. The way Haskell does it is more commonly used today across languages. And in a certain "graphical" way of looking at folding, it makes more sense. Why did SML define theirs the way they did? I am not sure. Perhaps so that the signatures of foldl and foldr will be the same.
Expanding on Some Other Guy's answer:
From the Haskell Wiki:
-- if the list is empty, the result is the initial value z; else
-- apply f to the first element and the result of folding the rest
foldr f z [] = z
foldr f z (x:xs) = f x (foldr f z xs)
-- if the list is empty, the result is the initial value; else
-- we recurse immediately, making the new initial value the result
-- of combining the old initial value with the first element.
foldl f z [] = z
foldl f z (x:xs) = foldl f (f z x) xs
so foldl (-) 2 [1] is (2 - 1) and foldr (-) 2 [1] is (1 - 2)
From the SML Basis Library
foldl f init [x1, x2, ..., xn]
returns
f(xn,...,f(x2, f(x1, init))...)
or init if the list is empty.
foldr f init [x1, x2, ..., xn]
returns
f(x1, f(x2, ..., f(xn, init)...))
or init if the list is empty.
so foldl (op -) 2 [1] is fxn - init or 1 - 2, and foldr (op -) 2 [1] is fx1 - init. It is still 1 - 2, but only by coincidence. The answers diverge with a longer list, but not as much as the answers between Haskell and SML.

Error while declaring a lambda function: declare an instance first

I am trying to understand lambda functions (i.e. anonymous functions) in Haskell by writing a few simple functions that use them.
In the following example, I am simply trying to take in 3 parameters and add two of the three using an anonymous function and adding the third parameter after that.
I am getting an error saying that I must declare an instance first.
specialAdd x y z = (\x y -> x + y) + z
I appreciate any explanation of why my example is not working and/or any explanation that would help me better understand lambda functions.
specialAdd x y z = (\x y -> x + y) + z
In this example, what you are trying to do is add a function to a number, which is not going to work. Look at (\x y -> x + y) + z: it has the form a + b. In order for such an expression to work, the a part and the b part must be numbers of the same type.
Haskell is a bit of an unusual language, so its error messages are rarely of the form "you can't do that". So what's going on here is that Haskell sees that (\x y -> x + y) is a function, and since in an expression like a + b, b must be the same type as a, it concludes that b must also be a function. Haskell also allows you to define your own rules for adding non-built-in types; so it can't just give you an error saying "you can't add two functions," but instead the error is "you have not defined a rule that allows me to add two functions."
The following would do what you want:
specialAdd x y z = ((\x y -> x + y) x y) + z
Here you are applying the function (\x y -> x + y) to arguments x and y, then adding the result to z.
A good way to practice anonymous function is to use them with high order function as fold or map.
Using map as an entry point,
Basic definition of map,
map f [] = []
map f (x:xs) = f x : f xs
Built up an example,
>>> let list = [0..4]
>>> let f x = x + 1
Applying map we obtain,
>>> map f list
[1,2,3,4,5]
Now, we can omit the declaration of f and replace it using anonymous function,
>>> map (\x->x+1) list
[1,2,3,4,5]
then we deduce, map f list == map (\x->x+1) list, thus
f = \x-> x + 1 --- The same as f x = x + 1, but this is the equivalent lambda notation.
then starting with a simple function we see how to translate it into an anonymous function and then how an anonymous function can be rely to a lambda abstraction.
As an exercise try to translate f x = 2*x.
Now more complex, an anonymous function which take two arguments,
Again an working example,
>>> let add x y = x + y
>>> foldl' add 0 [0..4]
10
Can be rewrite using anonymous function as,
>>> foldl' (\x y -> x + y) 0 [0..4]
Again using equality we deduce that add = \x y -> x + y
Moreover as in hakell all function are function of one argument, and we can partial apply it, we can rewrite our previous anonymous function as, add = \x -> (\y -> x + y).
Then where is the trick ?? Because, I just show the use of anonymous function into high order one, and starting from that, showing how this can be exploited to rewrite function using lambda notation. I mean how can it help you to learn how to write down anonymous function ?
Simply cause I've give you (show you) an existing framework using high order function.
This framework is a huge opportunity to accommodate you with this notation.
Starting from that an infinity range of exercise can be deduce, for example try to do the following.
A - Find the corresponding anonymous function ?
1 - let f (x,y) = x + y in map f [(0,1),(2,3),(-1,1)]
2 - let f x y = x * y in foldl' f 1 [1..5]
B - Rewrite all of them using lambda notation into a declarative form (f = \x-> (\y-> ...)
And so on ....
To summarize,
A function as
(F0) f x1 x2 ... xn = {BODY of f}
can always be rewrite as,
(F1) f = \x1 x2 ... xn -> {BODY of f}
where
(F2) (\x1 x2 ... xn -> {BODY of f})
F2 form are just anonymous function, a pure translation of the function into lambda calculus form. F1 is a declarative lambda notation (because we declare f, as we define it, binding it to the anonymous F2). F0 being the usual notation of Haskeller.
A last note focusing on the fact we can put parenthesis between the argument, this create a closure. Doing that mean that a subset of the function's code can be fully evaluated using a subset of the function's argument, (mean converting to a form where no more free variable occurs), but that's another story.
Here is correct form:
specialAdd a b c = ((\x y -> x + y) a b) + c
Example from Learn You a Haskell...:
zipWith (\a b -> (a * 30 + 3) / b) [5,4,3,2,1] [1,2,3,4,5]
Great explanation:
http://learnyouahaskell.com/higher-order-functions#lambdas
From what I understand Labmbda/Anonymous functions help you declare a function "inline" without the need to give it a name. The "\" (ASCII for the Greek, λ) precedes the variable names for the expression that follows the "->". For example,
(\x y -> x + y)
is an anonymous (lambda) function similar to (+). It takes two parameters of type Num and returns their sum:
Prelude> :type (+)
(+) :: Num a => a -> a -> a
Prelude> :type (\x y -> x + y)
(\x y -> x + y) :: Num a => a -> a -> a
Your example is not working because, as others have pointed out, the right hand side of it is using a lambda function, (\x y -> x + y), as a parameter for the (+) operator, which is defined by default only for parameters of type Num. Some of the beauty of the lambda function can be in its "anonymous" use. Vladimir showed how you can use the lambda function in your declaration by passing it the variables from the left side. A more "anonymous" use could be simply calling it, with variables, without giving the function a name (hence anonymous). For example,
Prelude> (\x y z -> x + y + z) 1 2 3
6
and if you like writing parentheses:
Prelude> (((+).) . (+)) 1 2 3
6
Or in a longer expression (as in your example declaration), e.g.,
Prelude> filter (\x -> length x < 3) [[1],[1,2],[1,2,3]]
[[1],[1,2]]
You are trying to use (+) as something like (Num a) => (a -> a -> a) -> a -> ?? which is not correct.
(+) is defined in the class Num and (a -> a -> a) is not an instance of this class.
What exactly are you trying to achieve ?

Composing a chain of 2-argument functions

So I have a list of a functions of two arguments of the type [a -> a -> a]
I want to write a function which will take the list and compose them into a chain of functions which takes length+1 arguments composed on the left. For example if I have [f,g,h] all of types [a -> a -> a] I need to write a function which gives:
chain [f,g,h] = \a b c d -> f ( g ( h a b ) c ) d
Also if it helps, the functions are commutative in their arguments ( i.e. f x y = f y x for all x y ).
I can do this inside of a list comprehension given that I know the the number of functions in question, it would be almost exactly like the definition. It's the stretch from a fixed number of functions to a dynamic number that has me stumped.
This is what I have so far:
f xs = f' xs
where
f' [] = id
f' (x:xs) = \z -> x (f' xs) z
I think the logic is along the right path, it just doesn't type-check.
Thanks in advance!
The comment from n.m. is correct--this can't be done in any conventional way, because the result's type depends on the length of the input list. You need a much fancier type system to make that work. You could compromise in Haskell by using a list that encodes its length in the type, but that's painful and awkward.
Instead, since your arguments are all of the same type, you'd be much better served by creating a function that takes a list of values instead of multiple arguments. So the type you want is something like this: chain :: [a -> a -> a] -> [a] -> a
There are several ways to write such a function. Conceptually you want to start from the front of the argument list and the end of the function list, then apply the first function to the first argument to get something of type a -> a. From there, apply that function to the next argument, then apply the next function to the result, removing one element from each list and giving you a new function of type a -> a.
You'll need to handle the case where the list lengths don't match up correctly, as well. There's no way around that, other than the aforementioned type-encoded-lengths and the hassle associate with such.
I wonder, whether your "have a list of a functions" requirement is a real requirement or a workaround? I was faced with the same problem, but in my case set of functions was small and known at compile time. To be more precise, my task was to zip 4 lists with xor. And all I wanted is a compact notation to compose 3 binary functions. What I used is a small helper:
-- Binary Function Chain
bfc :: (c -> d) -> (a -> b -> c) -> a -> b -> d
bfc f g = \a b -> f (g a b)
For example:
ghci> ((+) `bfc` (*)) 5 3 2 -- (5 * 3) + 2
17
ghci> ((+) `bfc` (*) `bfc` (-)) 5 3 2 1 -- ((5 - 3) * 2) + 1
5
ghci> zipWith3 ((+) `bfc` (+)) [1,2] [3,4] [5,6]
[9,12]
ghci> getZipList $ (xor `bfc` xor `bfc` xor) <$> ZipList [1,2] <*> ZipList [3,4] <*> ZipList [5,6] <*> ZipList [7,8]
[0,8]
That doesn't answers the original question as it is, but hope still can be helpful since it covers pretty much what question subject line is about.

Confusion about function composition in Haskell

Consider following function definition in ghci.
let myF = sin . cos . sum
where, . stands for composition of two function (right associative). This I can call
myF [3.14, 3.14]
and it gives me desired result. Apparently, it passes list [3.14, 3.14] to function 'sum' and its 'result' is passed to cos and so on and on. However, if I do this in interpreter
let myF y = sin . cos . sum y
or
let myF y = sin . cos (sum y)
then I run into troubles. Modifying this into following gives me desired result.
let myF y = sin . cos $ sum y
or
let myF y = sin . cos . sum $ y
The type of (.) suggests that there should not be a problem with following form since 'sum y' is also a function (isn't it? After-all everything is a function in Haskell?)
let myF y = sin . cos . sum y -- this should work?
What is more interesting that I can make it work with two (or many) arguments (think of passing list [3.14, 3.14] as two arguments x and y), I have to write the following
let (myF x) y = (sin . cos . (+ x)) y
myF 3.14 3.14 -- it works!
let myF = sin . cos . (+)
myF 3.14 3.14 -- -- Doesn't work!
There is some discussion on HaskellWiki regarding this form which they call 'PointFree' form http://www.haskell.org/haskellwiki/Pointfree . By reading this article, I am suspecting that this form is different from composition of two lambda expressions. I am getting confused when I try to draw a line separating both of these styles.
Let's look at the types. For sin and cos we have:
cos, sin :: Floating a => a -> a
For sum:
sum :: Num a => [a] -> a
Now, sum y turns that into a
sum y :: Num a => a
which is a value, not a function (you could name it a function with no arguments but this is very tricky and you also need to name () -> a functions - there was a discussion somewhere about this but I cannot find the link now - Conal spoke about it).
Anyway, trying cos . sum y won't work because . expects both sides to have types a -> b and b -> c (signature is (b -> c) -> (a -> b) -> (a -> c)) and sum y cannot be written in this style. That's why you need to include parentheses or $.
As for point-free style, the simples translation recipe is this:
take you function and move the last argument of function to the end of the expression separated by a function application. For example, in case of mysum x y = x + y we have y at the end but we cannot remove it right now. Instead, rewriting as mysum x y = (x +) y it works.
remove said argument. In our case mysum x = (x +)
repeat until you have no more arguments. Here mysum = (+)
(I chose a simple example, for more convoluted cases you'll have to use flip and others)
No, sum y is not a function. It's a number, just like sum [1, 2, 3] is. It therefore makes complete sense that you cannot use the function composition operator (.) with it.
Not everything in Haskell are functions.
The obligatory cryptic answer is this: (space) binds more tightly than .
Most whitespace in Haskell can be thought of as a very high-fixity $ (the "apply" function). w x . y z is basically the same as (w $ x) . (y $ z)
When you are first learning about $ and . you should also make sure you learn about (space) as well, and make sure you understand how the language semantics implicitly parenthesize things in ways that may not (at first blush) appear intuitive.

Resources