
I have a new proposal to add swap and swap' to Data.Tuple http://hackage.haskell.org/trac/ghc/ticket/3298 -- Russell O'Connor http://r6.ca/ ``All talk about `theft,''' the general counsel of the American Graphophone Company wrote, ``is the merest claptrap, for there exists no property in ideas musical, literary or artistic, except as defined by statute.''

What is the need for swap' ? Things like foldl' solve space leaks,
what does swap' solve? I fully agree on the addition of swap.
Thanks, Neil
On Fri, Jun 12, 2009 at 10:10 PM,
I have a new proposal to add swap and swap' to Data.Tuple
http://hackage.haskell.org/trac/ghc/ticket/3298
-- Russell O'Connor http://r6.ca/ ``All talk about `theft,''' the general counsel of the American Graphophone Company wrote, ``is the merest claptrap, for there exists no property in ideas musical, literary or artistic, except as defined by statute.'' _______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

On Tue, 16 Jun 2009, Neil Mitchell wrote:
What is the need for swap' ? Things like foldl' solve space leaks, what does swap' solve? I fully agree on the addition of swap.
I'm not sure what swap' solves. I just think it has a pretty symmetry to it. I presume one of these pro-strict-swap people can come up with an example of where swap' solves a problem. -- Russell O'Connor http://r6.ca/ ``All talk about `theft,''' the general counsel of the American Graphophone Company wrote, ``is the merest claptrap, for there exists no property in ideas musical, literary or artistic, except as defined by statute.''

roconnor@theorem.ca wrote:
On Tue, 16 Jun 2009, Neil Mitchell wrote:
What is the need for swap' ? Things like foldl' solve space leaks, what does swap' solve? I fully agree on the addition of swap.
I'm not sure what swap' solves. I just think it has a pretty symmetry to it. I presume one of these pro-strict-swap people can come up with an example of where swap' solves a problem.
Sure. f (x, y) z = let !t = x+z in (t, y) bar1 xs = foldl' ((swap' .) . f) (0, 0) xs bar2 xs = foldl' ((swap .) . f) (0, 0) xs Prelude Swap> bar1 [0..1000000] (250000000000,250000500000) Prelude Swap> bar2 [0..1000000] (*** Exception: stack overflow Actually, "swap" works fairly well most of the time, because in addition to its laziness, ghc's garbage collector does short-cut evaluation of record selectors. So if the code just builds up a chain of swaps, GC will compress that chain very nicely. But I still prefer the strict version. Bertram P.S. I'd problably write your example as foo x [] = (x, 0) foo x [y] = (0, x + y) foo x (y:z:xs) = let !t = x + y + z in foo t xs or, if I wanted to do something fancy, foo x xs = r where (c, d, r) = go x xs (c, d) go x [] r = (x, 0, r) go x (y:ys) r = let !z = x + y; !r' = swap' r in go z ys r' Compiled, both versions end up about 2 times faster than foo x [] = (x, 0) foo x (y:xs) = let !z = x + y in swap (foo z xs) on foo 0 [0..1000000].

How about this: swap should be lazy because that is how H98 defines uncurry: uncurry :: (a -> b -> c) -> ((a, b) -> c) uncurry f p = f (fst p) (snd p) -- Russell O'Connor http://r6.ca/ ``All talk about `theft,''' the general counsel of the American Graphophone Company wrote, ``is the merest claptrap, for there exists no property in ideas musical, literary or artistic, except as defined by statute.''

If we look at swap from the standpoint of the laws/RULES it should support,
viewing Hask over (,) as a symmetric monoidal category you get something
like:
{-# RULES"swap . swap = id" forall x. swap (swap x) = x
"fst . swap = snd" forall x. fst (swap x) = snd x
"snd . swap = fst" forall x. snd (swap x) = fst x
#-}
That seems to argue for the lazy definition being the default to avoid the
strict pattern match in swap breaking the latter very pleasing equalities.
-Edward Kmett
On Wed, Jun 17, 2009 at 8:52 PM,
How about this: swap should be lazy because that is how H98 defines uncurry:
uncurry :: (a -> b -> c) -> ((a, b) -> c) uncurry f p = f (fst p) (snd p)
-- Russell O'Connor http://r6.ca/ ``All talk about `theft,''' the general counsel of the American Graphophone Company wrote, ``is the merest claptrap, for there exists no property in ideas musical, literary or artistic, except as defined by statute.'' _______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

On Thu, 2009-06-18 at 01:24 -0400, Edward Kmett wrote:
If we look at swap from the standpoint of the laws/RULES it should support, viewing Hask over (,) as a symmetric monoidal category you get something like:
{-# RULES "swap . swap = id" forall x. swap (swap x) = x "fst . swap = snd" forall x. fst (swap x) = snd x "snd . swap = fst" forall x. snd (swap x) = fst x #-}
That seems to argue for the lazy definition being the default to avoid the strict pattern match in swap breaking the latter very pleasing equalities.
Lazy swap fails the swap . swap rule: swap (swap undefined) = swap (snd undefined, fst undefined) = swap (undefined, undefined) = (undefined, undefined) which is distinct from undefined because Haskell tuples are lifted. jcc

Good point. This brings us back to Russell's original suggestion of swap and
swap' to cover both cases. That module has all of ~4 methods in it right
now. -- I'm evaluating that lazily -- so its not exactly like adding both
will break the complexity budget of a self-contained module designed to deal
with tuples. ;)
-Edward Kmett
On Thu, Jun 18, 2009 at 1:27 AM, Jonathan Cast
On Thu, 2009-06-18 at 01:24 -0400, Edward Kmett wrote:
If we look at swap from the standpoint of the laws/RULES it should support, viewing Hask over (,) as a symmetric monoidal category you get something like:
{-# RULES "swap . swap = id" forall x. swap (swap x) = x "fst . swap = snd" forall x. fst (swap x) = snd x "snd . swap = fst" forall x. snd (swap x) = fst x #-}
That seems to argue for the lazy definition being the default to avoid the strict pattern match in swap breaking the latter very pleasing equalities.
Lazy swap fails the swap . swap rule:
swap (swap undefined) = swap (snd undefined, fst undefined) = swap (undefined, undefined) = (undefined, undefined)
which is distinct from undefined because Haskell tuples are lifted.
jcc

Reopening discussion. I believe that swap should be lazy by default in order to be consistent with how uncurry works. -- Russell O'Connor http://r6.ca/ ``All talk about `theft,''' the general counsel of the American Graphophone Company wrote, ``is the merest claptrap, for there exists no property in ideas musical, literary or artistic, except as defined by statute.''

roconnor@theorem.ca wrote:
I have a new proposal to add swap and swap' to Data.Tuple
I'd ask the opposite of Neil's question - what is a good use case for the extra laziness that swap provides over swap'? It seems to fill a rather small niche to me. To provide the extra laziness, my favourite haskell compiler will have to create and later evaluate two thunks in addition to allocating a new pair. In other words, I'd rather add only one function, swap (a, b) = (b, a) regards, Bertram

Russell O'Connor wrote:
I have a new proposal to add swap and swap' to Data.Tuple swap ~(a,b) = (b,a) swap' (a,b) = (b,a)
Bertram Felgenhauer wrote:
I'd ask the opposite of Neil's question - what is a good use case for the extra laziness that swap provides over swap'? It seems to fill a rather small niche to me.
Well, another natural way of writing it would be swap = uncurry $ flip (,) which supports the lazy version as default. But Bertram is right, in practice we know that there will never be an advantage to pushing off until later the "hard work" of swapping the order of the tuple. So we should make it strict by default. Let's not fall into the trap of "sum" and "product", where the default is idiotically lazy, and now we have to fight to get it fixed. Regards, Yitz

On Wed, 17 Jun 2009, Bertram Felgenhauer wrote:
roconnor@theorem.ca wrote:
I have a new proposal to add swap and swap' to Data.Tuple
I'd ask the opposite of Neil's question - what is a good use case for the extra laziness that swap provides over swap'? It seems to fill a rather small niche to me.
let foo x [] = (x,0); foo x (y:xs) = let !z = x + y in swap (foo z xs) in foo 0 [0..1000000] The above runs fine while let foo x [] = (x,0); foo x (y:xs) = let !z = x + y in swap' (foo z xs) in foo 0 [0..1000000] causes a stack overflow in GHC.
To provide the extra laziness, my favourite haskell compiler will have to create and later evaluate two thunks in addition to allocating a new pair.
I think we should be as lazy as possible in general, because lazier code supports more (data) fixpoint definitions than strict code. Adding strictness is generally used as an optimization, and adding it as default would be prematurely optimize *everyone's* code.
In other words, I'd rather add only one function,
swap (a, b) = (b, a)
-- Russell O'Connor http://r6.ca/ ``All talk about `theft,''' the general counsel of the American Graphophone Company wrote, ``is the merest claptrap, for there exists no property in ideas musical, literary or artistic, except as defined by statute.''
participants (6)
-
Bertram Felgenhauer
-
Edward Kmett
-
Jonathan Cast
-
Neil Mitchell
-
roconnor@theorem.ca
-
Yitzchak Gale