1
1
{-# LANGUAGE CPP #-}
2
+ {-# LANGUAGE DeriveFunctor #-}
2
3
{-# LANGUAGE FlexibleInstances #-}
3
4
{-# LANGUAGE FunctionalDependencies #-}
4
5
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
@@ -19,6 +20,7 @@ import qualified Prelude as Prelude
19
20
20
21
import Control.Applicative (ZipList (.. ), pure , (<$>) )
21
22
import Data.Bifunctor (Bifunctor (.. ))
23
+ import Data.Biapplicative (Biapplicative (.. ), traverseBia )
22
24
import Data.Functor.Compose (Compose (.. ))
23
25
import Data.Functor.Identity (Identity (.. ))
24
26
import Data.Functor.Product (Product (.. ))
@@ -577,7 +579,47 @@ instance (Ord k) => Align (Map k) where
577
579
instance Ord k => Unalign (Map k ) where
578
580
unalign xs = (Map. mapMaybe justHere xs, Map. mapMaybe justThere xs)
579
581
580
- instance Ord k => Unzip (Map k ) where unzip = unzipDefault
582
+ -- A copy of (,) with a stricter bimap.
583
+ newtype SBPair a b = SBPair { unSBPair :: (a , b ) }
584
+
585
+ instance Bifunctor SBPair where
586
+ bimap f g (SBPair (a, b)) = SBPair (f a, g b)
587
+
588
+ instance Biapplicative SBPair where
589
+ bipure a b = SBPair (a, b)
590
+ biliftA2 f g (SBPair (a, b)) (SBPair (c, d)) =
591
+ SBPair (f a c, g b d)
592
+
593
+ instance Ord k => Unzip (Map k ) where
594
+ -- Map has a strict spine, so we have to build a whole one at
595
+ -- once. The default instance would first build an entire
596
+ -- Map filled with thunks, each of which will produce a pair,
597
+ -- and then build two maps, each filled with thunks to extract
598
+ -- a value from the pair. We instead build both maps at once,
599
+ -- each of which will be filled with selector thunks, along
600
+ -- with thunks (not in any Map) holding the applications of
601
+ -- `f`.
602
+ unzipWith f xs = (l, r)
603
+ where
604
+ ~ (l, r) = unSBPair . traverseBia (SBPair . blah) $ xs
605
+ blah c = let
606
+ {-# NOINLINE fc #-} -- make sure the result of f c is shared,
607
+ -- and that nothing weird happens to
608
+ -- keep us from getting selector thunks.
609
+ {-# NOINLINE a #-} -- make sure we get selector thunks
610
+ {-# NOINLINE b #-}
611
+ fc = f c
612
+ ~ (a, b) = fc
613
+ in (a, b)
614
+
615
+ unzip xs = (l, r)
616
+ where
617
+ ~ (l, r) = unSBPair . traverseBia (SBPair . blah) $ xs
618
+ blah ab = let
619
+ {-# NOINLINE a #-} -- make sure we get selector thunks
620
+ {-# NOINLINE b #-}
621
+ ~ (a, b) = ab
622
+ in (a, b)
581
623
582
624
instance Ord k => Zip (Map k ) where
583
625
zipWith = Map. intersectionWith
@@ -601,7 +643,28 @@ instance Align IntMap where
601
643
instance Unalign IntMap where
602
644
unalign xs = (IntMap. mapMaybe justHere xs, IntMap. mapMaybe justThere xs)
603
645
604
- instance Unzip IntMap where unzip = unzipDefault
646
+ instance Unzip IntMap where
647
+ -- See notes at the Map instance
648
+ unzipWith f xs = (l, r)
649
+ where
650
+ ~ (l, r) = unSBPair . traverseBia (SBPair . blah) $ xs
651
+ blah c = let
652
+ {-# NOINLINE fc #-} -- make sure the result of f c is shared,
653
+ -- and that nothing weird happens to
654
+ -- keep us from getting selector thunks.
655
+ {-# NOINLINE a #-} -- make sure we get selector thunks
656
+ {-# NOINLINE b #-}
657
+ fc = f c
658
+ ~ (a, b) = fc
659
+ in (a, b)
660
+ unzip xs = (l, r)
661
+ where
662
+ ~ (l, r) = unSBPair . traverseBia (SBPair . blah) $ xs
663
+ blah ab = let
664
+ {-# NOINLINE a #-} -- make sure we get selector thunks
665
+ {-# NOINLINE b #-}
666
+ ~ (a, b) = ab
667
+ in (a, b)
605
668
606
669
instance Zip IntMap where
607
670
zipWith = IntMap. intersectionWith
0 commit comments