Composition and type magic

Hi everyone, I defined a function for discrete convolution, i.e conv xs = sum . zipWith (*) xs . reverse And I was wondering, can it be done without explicitly passing in the xs (eta-reduction)? I've seen people play with (.).(.) and foldl foldl foldl and was thinking that maybe something similar might be used here. -- Regards Sumit Sahrawat

On 02/23/2015 10:11 PM, Sumit Sahrawat, Maths & Computing, IIT (BHU) wrote:
Hi everyone,
I defined a function for discrete convolution, i.e
conv xs = sum . zipWith (*) xs . reverse
And I was wondering, can it be done without explicitly passing in the xs (eta-reduction)?
Ehhhhhhhhhh this will work: conv = (sum .) . (. reverse) . zipWith (*) But it's so much easier to understand without all the boobies operators: conv xs ys = sum $ zipWith (*) xs (reverse ys)

Thanks.
You've given me a good exercise in equational reasoning.
I'm studying such things because I might start studying combinatory logic
(Smullyan's mockingbird book) soon.
It's a good exercise for the mind, and is very enjoyable with pencil &
paper.
Can you give me some more patterns like transducers (foldl foldl) and the
dot-dot-dot ( boobies, in your words :) ) example?
Thanks once again.
On 24 February 2015 at 08:57, Michael Orlitzky
On 02/23/2015 10:11 PM, Sumit Sahrawat, Maths & Computing, IIT (BHU) wrote:
Hi everyone,
I defined a function for discrete convolution, i.e
conv xs = sum . zipWith (*) xs . reverse
And I was wondering, can it be done without explicitly passing in the xs (eta-reduction)?
Ehhhhhhhhhh this will work:
conv = (sum .) . (. reverse) . zipWith (*)
But it's so much easier to understand without all the boobies operators:
conv xs ys = sum $ zipWith (*) xs (reverse ys)
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
-- Regards Sumit Sahrawat

On 24.02.2015 06:57, Sumit Sahrawat, Maths & Computing, IIT (BHU) wrote:
Thanks. You've given me a good exercise in equational reasoning.
I'm studying such things because I might start studying combinatory logic (Smullyan's mockingbird book) soon. It's a good exercise for the mind, and is very enjoyable with pencil & paper. Can you give me some more patterns like transducers (foldl foldl) and the dot-dot-dot ( boobies, in your words :) ) example?
Thanks once again.
On 24 February 2015 at 08:57, Michael Orlitzky
wrote: On 02/23/2015 10:11 PM, Sumit Sahrawat, Maths & Computing, IIT (BHU) wrote:
Hi everyone,
I defined a function for discrete convolution, i.e
conv xs = sum . zipWith (*) xs . reverse
And I was wondering, can it be done without explicitly passing in the xs (eta-reduction)?
Ehhhhhhhhhh this will work:
conv = (sum .) . (. reverse) . zipWith (*)
But it's so much easier to understand without all the boobies operators:
conv xs ys = sum $ zipWith (*) xs (reverse ys)
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
You might be interested in the pointfree [1] tool, which can convert lambda expressions to pointfree versions automatically. Allthough I also find the more complex ones, as in this case, rather obscure. I like you initial version best: conv xs = sum . zipWith (*) xs . reverse [1] http://hackage.haskell.org/package/pointfree

On 02/24/2015 12:57 AM, Sumit Sahrawat, Maths & Computing, IIT (BHU) wrote:
Thanks. You've given me a good exercise in equational reasoning.
I'm studying such things because I might start studying combinatory logic (Smullyan's mockingbird book) soon. It's a good exercise for the mind, and is very enjoyable with pencil & paper. Can you give me some more patterns like transducers (foldl foldl) and the dot-dot-dot ( boobies, in your words :) ) example?
I cheated with the pointfree tool, but you can do it by hand, too. The only trick you need to know in this case is how to get the extra argument on the end. You start with, conv xs = sum . zipWith (*) xs . reverse and obviously, you want the 'xs' on the end. So you want to switch the 'zipWith (*) xs' and 'reverse' somehow. Well, you can always flip the composition operator! Unfortunately it's no longer infix at that point, so it has to be written like, conv xs = sum . (flip (.)) reverse (zipWith (*) xs) Now the secret is that putting an extra dot around the chain of functions takes it from a one-argument chain to a two-argument chain (where the first function in the chain eats the second argument). You can sort of see this in the type of 'sum' and '(sum .)': ghci> :t sum sum :: Num a => [a] -> a ghci> :t (sum .) (sum .) :: Num c => (a -> [c]) -> a -> c The second one essentially eats an argument by taking "something that will give me a list" instead of a list itself. You have to do the same thing with the '(flip (.)) reverse' part of the chain: conv = (sum .) . (((flip (.)) reverse) .) zipWith (*) Now, since you've got '((flip (.)) reverse' in parentheses anyway, you can change it from a normal function application to a "section," i.e. these two are the same: (flip (.)) reverse == (. reverse). So you wind up with, conv = (sum .) . (((. reverse) .) zipWith (*) Drop the useless parentheses, conv = (sum .) . (. reverse) . zipWith (*) and now all that's left to do is pray that you aren't hanged for witchcraft.

I didn't think of forcing xs to the end. I thought that I might be able to
convert the dot to something with type
(a -> b -> c) -> (b -> b) -> a -> b -> c
I tried flipping ((.).(.)) but got
(a -> b -> c) -> (c -> d) -> a -> b -> d
which is not what I wanted.
Thanks for the mini-tutorial. [?]
On 24 February 2015 at 18:58, Michael Orlitzky
On 02/24/2015 12:57 AM, Sumit Sahrawat, Maths & Computing, IIT (BHU) wrote:
Thanks. You've given me a good exercise in equational reasoning.
I'm studying such things because I might start studying combinatory logic (Smullyan's mockingbird book) soon. It's a good exercise for the mind, and is very enjoyable with pencil & paper. Can you give me some more patterns like transducers (foldl foldl) and the dot-dot-dot ( boobies, in your words :) ) example?
I cheated with the pointfree tool, but you can do it by hand, too. The only trick you need to know in this case is how to get the extra argument on the end. You start with,
conv xs = sum . zipWith (*) xs . reverse
and obviously, you want the 'xs' on the end. So you want to switch the 'zipWith (*) xs' and 'reverse' somehow. Well, you can always flip the composition operator! Unfortunately it's no longer infix at that point, so it has to be written like,
conv xs = sum . (flip (.)) reverse (zipWith (*) xs)
Now the secret is that putting an extra dot around the chain of functions takes it from a one-argument chain to a two-argument chain (where the first function in the chain eats the second argument). You can sort of see this in the type of 'sum' and '(sum .)':
ghci> :t sum sum :: Num a => [a] -> a
ghci> :t (sum .) (sum .) :: Num c => (a -> [c]) -> a -> c
The second one essentially eats an argument by taking "something that will give me a list" instead of a list itself. You have to do the same thing with the '(flip (.)) reverse' part of the chain:
conv = (sum .) . (((flip (.)) reverse) .) zipWith (*)
Now, since you've got '((flip (.)) reverse' in parentheses anyway, you can change it from a normal function application to a "section," i.e. these two are the same: (flip (.)) reverse == (. reverse). So you wind up with,
conv = (sum .) . (((. reverse) .) zipWith (*)
Drop the useless parentheses,
conv = (sum .) . (. reverse) . zipWith (*)
and now all that's left to do is pray that you aren't hanged for witchcraft.
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
-- Regards Sumit Sahrawat
participants (3)
-
Michael Orlitzky
-
Stere0id
-
Sumit Sahrawat, Maths & Computing, IIT (BHU)