
Chaddaï Fouché wrote:
2007/9/25, Andrew Coppin
: I just found it rather surprising. Every time *I* try to compose with functions of more than 1 argument, the type checker complains.
There is no function that takes more than one argument in Haskell. ;-) map _could_ be seen as a function with 2 arguments, but in this case it's more useful to think of it as a function that take one argument f, a function that turn 'a into 'b and turn it into a new function that turn a list of 'a into a list of 'b.
This is why I found it so surprising - and annoying - that you can't use a 2-argument function in a point-free expression. For example, "zipWith (*)" expects two arguments, and yet sum . zipWith (*) fails to type-check. You just instead write \xs ys -> sum $ zipWith(*) xs ys which works as expected. I can't figure out why map . map works, but sum . zipWith (*) doesn't work. As I say, the only reason I can see is that the type checker hates me and wants to force me to write everything the long way round...

Andrew Coppin writes:
...I found it so surprising - and annoying - that you can't use a 2-argument function in a point-free expression. For example, "zipWith (*)" expects two arguments, and yet
sum . zipWith (*) fails to type-check. You just instead write
\xs ys -> sum $ zipWith(*) xs ys
which works as expected.
I can't figure out why map . map works, but sum . zipWith (*) doesn't work. As I say, the only reason I can see is that the type checker hates me and wants to force me to write everything the long way round...
I suspect that it is you who hates the Haskell type-checker, forcing it to work on expressions which go against the rules: precedence, and normal order. The transformation to combinators is doable, but one has to be careful. Let's see: res p q = sum (zipWith (*) p q) = (sum . (zipWith (*) p)) q res p = (sum .) (zipWith (*) p) = ((sum .) . (zipWith (*)) p res = (sum .) . (zipWith (*)) Certainly it is a kind of madness, since is hardly readable, but it is correct. Jerzy Karczmarczuk

This is why I found it so surprising - and annoying - that you can't use a 2-argument function in a point-free expression.
For example, "zipWith (*)" expects two arguments, and yet
sum . zipWith (*)
fails to type-check. You just instead write
\xs ys -> sum $ zipWith(*) xs ys
which works as expected.
Prelude> :t \xs ys->sum $ zipWith (*) xs ys \xs ys->sum $ zipWith (*) xs ys :: (Num a) => [a] -> [a] -> a Prelude> :t \xs->sum . zipWith (*) xs \xs->sum . zipWith (*) xs :: (Num a) => [a] -> [a] -> a Prelude> :t (sum .) . zipWith (*) (sum .) . zipWith (*) :: (Num a) => [a] -> [a] -> a Prelude> :t (\g->sum . g) . zipWith (*) (\g->sum . g) . zipWith (*) :: (Num a) => [a] -> [a] -> a (.) composes single-parameter functions, so in (f . g) x y, g only gets the first parameter, x. but by adding further levels of composition to f, we can let g consume more parameters. claus

On Sep 25, 2007, at 6:55 , Andrew Coppin wrote:
This is why I found it so surprising - and annoying - that you can't use a 2-argument function in a point-free expression.
You can, it just requires more juggling. Play around with lambdabot's @pl for a bit. -- brandon s. allbery [solaris,freebsd,perl,pugs,haskell] allbery@kf8nh.com system administrator [openafs,heimdal,too many hats] allbery@ece.cmu.edu electrical and computer engineering, carnegie mellon university KF8NH

On 9/25/07, Andrew Coppin
This is why I found it so surprising - and annoying - that you can't use a 2-argument function in a point-free expression. [...] I can't figure out why map . map works, but sum . zipWith (*) doesn't work. As I say, the only reason I can see is that the type checker hates me and wants to force me to write everything the long way round...
I suspect you're getting confused by the way Haskell treats
multi-parameter functions. Specifically, as far as function
composition is concerned, all Haskell functions have one parameter.
It may help to fully parenthesize function applications.
For example,
\xs ys -> sum (zipWith f xs ys)
is
\xs ys -> sum (((zipWith f) xs) ys)
The rule is that you can replace "f (g x)" with "(f . g) x". If you
apply that above, you get
\xs ys -> (sum . ((zipWith f) xs)) ys
or
\xs -> sum . zipWith f xs
Removing 'xs' takes a little more work, because it's nested more
deeply. We can rewrite the above as,
\xs -> ((.) sum) ((zipWith f) xs)
Applying the rule f (g x) = (f . g) x gets us,
\xs -> (((.) sum) . (zipWith f)) xs
or
((.) sum) . zipWith f
or
(sum .) . zipWith f
The reason "map . map" is acceptible is that you can write "map (map f)".
--
Dave Menendez
participants (5)
-
Andrew Coppin
-
Brandon S. Allbery KF8NH
-
Claus Reinke
-
David Menendez
-
jerzy.karczmarczuk@info.unicaen.fr