Proposal: Make intersect(By) lazier and faster

With the current implementation of intersectBy, the calculation of intersectBy _ xs [] takes O(length xs) time, hence doesn't finish on infinite lists and evaluates to _|_ for partial lists xs (... : _|_). The proposed new implementation, intersectBy :: (a -> a -> Bool) -> [a] -> [a] -> [a] intersectBy _ [] _ = [] intersectBy _ _ [] = [] intersectBy eq xs ys = [x | x <- xs, any (eq x) ys] makes this an O(1) operation, returning [] also for infinite or partial xs. The first equation retains the property intersectBy _ [] _|_ = [] Trac ticket: http://hackage.haskell.org/trac/ghc/ticket/4323 Period of discussion: Two weeks, until 30 Sep. 2010. Cheers, Daniel

On Thu, Sep 16, 2010 at 5:21 PM, Daniel Fischer
With the current implementation of intersectBy, the calculation of intersectBy _ xs [] takes O(length xs) time, hence doesn't finish on infinite lists and evaluates to _|_ for partial lists xs (... : _|_). The proposed new implementation,
intersectBy :: (a -> a -> Bool) -> [a] -> [a] -> [a] intersectBy _ [] _ = [] intersectBy _ _ [] = [] intersectBy eq xs ys = [x | x <- xs, any (eq x) ys]
makes this an O(1) operation, returning [] also for infinite or partial xs. The first equation retains the property
intersectBy _ [] _|_ = []
Trac ticket: http://hackage.haskell.org/trac/ghc/ticket/4323
Period of discussion: Two weeks, until 30 Sep. 2010.
Cheers, Daniel _______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
+1 However I like using a 'filter' more than using a list comprehension: intersectBy :: (a -> a -> Bool) -> [a] -> [a] -> [a] intersectBy _ [] _ = [] intersectBy _ _ [] = [] intersectBy eq xs ys = filter (\x -> any (eq x) ys) xs Hopefully this definition can even benefit from foldr/build fusion using the filter RULES in GHC.List: {-# NOINLINE [0] filterFB #-} filterFB :: (a -> b -> b) -> (a -> Bool) -> a -> b -> b filterFB c p x r | p x = x `c` r | otherwise = r {-# RULES "filter" [~1] forall p xs. filter p xs = build (\c n -> foldr (filterFB c p) n xs) "filterList" [1] forall p. foldr (filterFB (:) p) [] = filter p "filterFB" forall c p q. filterFB (filterFB c p) q = filterFB c (\x -> q x && p x) #-} Regards, Bas

On 16 September 2010 17:10, Bas van Dijk
However I like using a 'filter' more than using a list comprehension:
intersectBy :: (a -> a -> Bool) -> [a] -> [a] -> [a] intersectBy _ [] _ = [] intersectBy _ _ [] = [] intersectBy eq xs ys = filter (\x -> any (eq x) ys) xs
Hopefully this definition can even benefit from foldr/build fusion using the filter RULES in GHC.List:
It should not make any difference. List comprehensions can also be fused using foldr/build fusion because the list combrehension is desugared into uses of foldr and build. It is also unlikely to fuse anyway because the compiler would need to know at the call site that the two lists are non-empty. Duncan

On Thu, Sep 16, 2010 at 6:16 PM, Duncan Coutts
On 16 September 2010 17:10, Bas van Dijk
wrote: However I like using a 'filter' more than using a list comprehension:
intersectBy :: (a -> a -> Bool) -> [a] -> [a] -> [a] intersectBy _ [] _ = [] intersectBy _ _ [] = [] intersectBy eq xs ys = filter (\x -> any (eq x) ys) xs
Hopefully this definition can even benefit from foldr/build fusion using the filter RULES in GHC.List:
It should not make any difference. List comprehensions can also be fused using foldr/build fusion because the list combrehension is desugared into uses of foldr and build. It is also unlikely to fuse anyway because the compiler would need to know at the call site that the two lists are non-empty.
Agreed, but my reason for proposing using 'filter' instead of using a list comprehension is that I find it more "denotational". However, I think that's a matter of taste. Bas

On Thursday 16 September 2010 18:20:17, Bas van Dijk wrote:
On Thu, Sep 16, 2010 at 6:16 PM, Duncan Coutts
wrote: On 16 September 2010 17:10, Bas van Dijk
wrote: However I like using a 'filter' more than using a list comprehension:
intersectBy :: (a -> a -> Bool) -> [a] -> [a] -> [a] intersectBy _ [] _ = [] intersectBy _ _ [] = [] intersectBy eq xs ys = filter (\x -> any (eq x) ys) xs
Hopefully this definition can even benefit from foldr/build fusion using the filter RULES in GHC.List:
It should not make any difference. List comprehensions can also be fused using foldr/build fusion because the list combrehension is desugared into uses of foldr and build. It is also unlikely to fuse anyway because the compiler would need to know at the call site that the two lists are non-empty.
Agreed, but my reason for proposing using 'filter' instead of using a list comprehension is that I find it more "denotational". However, I think that's a matter of taste.
Bas
I don't care either way, I just inserted two equations to deal with empty lists before the current implementation. If a preference for using filter, the list comprehension or anything else emerges, that'll be fine with me.

+1 for proposal
On 16 September 2010 17:20, Bas van Dijk
Agreed, but my reason for proposing using 'filter' instead of using a list comprehension is that I find it more "denotational". However, I think that's a matter of taste.
Funny, I feel the opposite. ;) Also, list comprehensions are usually best if you want to increase the likely hood of fusion because the desugaring is under GHC's control.
participants (4)
-
Bas van Dijk
-
Daniel Fischer
-
Duncan Coutts
-
Thomas Schilling