Skip to content

Commit c64a95c

Browse files
committed
Unzip definitions
1 parent 7a9277d commit c64a95c

File tree

2 files changed

+100
-1
lines changed

2 files changed

+100
-1
lines changed

semialign/src/Data/Semialign.hs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,14 @@ module Data.Semialign (
1616
lpadZip, lpadZipWith,
1717
rpadZip, rpadZipWith,
1818
alignVectorWith,
19+
-- * Unzip definition helpers
20+
UnzipStrictSpineStrictPairs (..),
21+
UnzipStrictSpineLazyPairs (..),
22+
UnzipLazySpineLazyPairs (..),
23+
unzipWithStrictSpineStrictPairs,
24+
unzipWithStrictSpineLazyPairs,
25+
unzipStrictSpineLazyPairs,
26+
unzipWithLazySpineLazyPairs,
1927
) where
2028

2129
import Data.Semialign.Internal

semialign/src/Data/Semialign/Internal.hs

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
{-# LANGUAGE CPP #-}
22
{-# LANGUAGE DeriveFunctor #-}
3+
{-# LANGUAGE DeriveFoldable #-}
4+
{-# LANGUAGE DeriveTraversable #-}
35
{-# LANGUAGE FlexibleInstances #-}
46
{-# LANGUAGE FunctionalDependencies #-}
57
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
@@ -14,7 +16,7 @@ module Data.Semialign.Internal where
1416
import Prelude
1517
(Bool (..), Either (..), Eq (..), Functor (fmap), Int, Maybe (..),
1618
Monad (..), Ord (..), Ordering (..), String, error, flip, fst, id,
17-
maybe, snd, uncurry, ($), (++), (.))
19+
maybe, snd, uncurry, ($), (++), (.), Traversable, Foldable)
1820

1921
import qualified Prelude as Prelude
2022

@@ -590,6 +592,95 @@ instance Biapplicative SBPair where
590592
biliftA2 f g (SBPair (a, b)) (SBPair (c, d)) =
591593
SBPair (f a c, g b d)
592594

595+
-- A copy of (,) with a lazier biliftA2
596+
newtype LBPair a b = LBPair { unLBPair :: (a, b) }
597+
598+
instance Bifunctor LBPair where
599+
bimap f g (LBPair ab) = LBPair (f a, g b)
600+
where
601+
-- Is this enough? I'm not sure. The danger is if
602+
-- the call inlines and `ab = (p, q)` inlines, but for whatever
603+
-- reason we end up with something like
604+
--
605+
-- a = p
606+
-- b = case ab of (_, q) -> q
607+
--
608+
-- I've seen something vaguely like that before, in Data.List.transpose,
609+
-- but I don't remember the details. If necessary, we can use
610+
-- `GHC.Exts.noinline` on `ab` for `base >= 4.15`, or some kind of shim
611+
-- elsewhere, but then we'll also want a rewrite rule
612+
--
613+
-- bimap f g (LBPair a b) = LBPair (f a, g b)
614+
--
615+
-- for when we get lucky.
616+
{-# NOINLINE a #-}
617+
{-# NOINLINE b #-}
618+
(a, b) = ab
619+
620+
instance Biapplicative LBPair where
621+
bipure a b = LBPair (a, b)
622+
biliftA2 f g (LBPair ab) (LBPair cd) =
623+
LBPair (f a c, g b d)
624+
where
625+
{-# NOINLINE a #-}
626+
{-# NOINLINE b #-}
627+
{-# NOINLINE c #-}
628+
{-# NOINLINE d #-}
629+
(a, b) = ab
630+
(c, d) = cd
631+
632+
newtype UnzipStrictSpineStrictPairs t a =
633+
UnzipStrictSpineStrictPairs { getUnzipStrictSpineStrictPairs :: t a }
634+
deriving (Functor, Foldable, Traversable, Semialign, Align, Zip)
635+
636+
instance (Zip t, Traversable t) => Unzip (UnzipStrictSpineStrictPairs t) where
637+
unzipWith = unzipWithStrictSpineStrictPairs
638+
639+
newtype UnzipStrictSpineLazyPairs t a =
640+
UnzipStrictSpineLazyPairs { getUnzipStrictSpineLazyPairs :: t a }
641+
deriving (Functor, Foldable, Traversable, Semialign, Align, Zip)
642+
643+
instance (Zip t, Traversable t) => Unzip (UnzipStrictSpineLazyPairs t) where
644+
unzipWith = unzipWithStrictSpineLazyPairs
645+
unzip = unzipStrictSpineLazyPairs
646+
647+
newtype UnzipLazySpineLazyPairs t a =
648+
UnzipLazySpineLazyPairs { getUnzipLazySpineLazyPairs :: t a }
649+
deriving (Functor, Foldable, Traversable, Semialign, Align, Zip)
650+
651+
instance (Zip t, Traversable t) => Unzip (UnzipLazySpineLazyPairs t) where
652+
unzipWith = unzipWithLazySpineLazyPairs
653+
654+
unzipWithStrictSpineStrictPairs :: Traversable t
655+
=> (c -> (a, b)) -> t c -> (t a, t b)
656+
unzipWithStrictSpineStrictPairs f = unSBPair . traverseBia (SBPair . f)
657+
658+
unzipWithStrictSpineLazyPairs :: Traversable t
659+
=> (c -> (a, b)) -> t c -> (t a, t b)
660+
unzipWithStrictSpineLazyPairs f = unSBPair . traverseBia (SBPair . foo)
661+
where
662+
foo c = let
663+
{-# NOINLINE fc #-}
664+
{-# NOINLINE a #-}
665+
{-# NOINLINE b #-}
666+
fc = f c
667+
(a, b) = fc
668+
in (a, b)
669+
670+
unzipStrictSpineLazyPairs :: Traversable t
671+
=> t (a, b) -> (t a, t b)
672+
unzipStrictSpineLazyPairs = unSBPair . traverseBia (SBPair . foo)
673+
where
674+
foo ab = let
675+
{-# NOINLINE a #-}
676+
{-# NOINLINE b #-}
677+
(a, b) = ab
678+
in (a, b)
679+
680+
unzipWithLazySpineLazyPairs :: Traversable t
681+
=> (c -> (a, b)) -> t c -> (t a, t b)
682+
unzipWithLazySpineLazyPairs f = unLBPair . traverseBia (LBPair . f)
683+
593684
instance Ord k => Unzip (Map k) where unzip = unzipDefault
594685

595686
instance Ord k => Zip (Map k) where

0 commit comments

Comments
 (0)