diff --git a/vec/src/Data/Vec/DataFamily/SpineStrict.hs b/vec/src/Data/Vec/DataFamily/SpineStrict.hs index 22e4b70..bd018ab 100644 --- a/vec/src/Data/Vec/DataFamily/SpineStrict.hs +++ b/vec/src/Data/Vec/DataFamily/SpineStrict.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE BangPatterns #-} {-# LANGUAGE CPP #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleInstances #-} @@ -91,6 +92,13 @@ module Data.Vec.DataFamily.SpineStrict ( ifoldMap1, foldr, ifoldr, + -- * Scans + scanr, + scanl, + scanl', + scanr1, + scanl1, + scanl1', -- * Special folds length, null, @@ -582,10 +590,10 @@ last :: forall n a. N.SNatI n => Vec ('S n) a -> a last xs = getLast (N.induction1 start step) xs where start :: Last 'Z a start = Last $ \(x:::VNil) -> x - + step :: Last m a -> Last ('S m) a step (Last rec) = Last $ \(_ ::: ys) -> rec ys - + newtype Last n a = Last { getLast :: Vec ('S n) a -> a } @@ -596,7 +604,7 @@ init :: forall n a. N.SNatI n => Vec ('S n) a -> Vec n a init xs = getInit (N.induction1 start step) xs where start :: Init 'Z a start = Init (const VNil) - + step :: Init m a -> Init ('S m) a step (Init rec) = Init $ \(y ::: ys) -> y ::: rec ys @@ -845,6 +853,62 @@ ifoldr = getIFoldr $ N.induction1 start step where newtype IFoldr a n b = IFoldr { getIFoldr :: (Fin n -> a -> b -> b) -> b -> Vec n a -> b } +-- | Right-to-left scan. +scanr :: forall a b n. N.SNatI n => (a -> b -> b) -> b -> Vec n a -> Vec ('S n) b +scanr f z = getScanr $ N.induction1 start step where + start :: Scanr a 'Z b + start = Scanr $ \_ -> singleton z + + step :: Scanr a m b -> Scanr a ('S m) b + step (Scanr go) = Scanr $ \(x ::: xs) -> let ys@(y ::: _) = go xs in f x y ::: ys + +newtype Scanr a n b = Scanr { getScanr :: Vec n a -> Vec ('S n) b } + +-- | Left-to-right scan. +scanl :: forall a b n. N.SNatI n => (b -> a -> b) -> b -> Vec n a -> Vec ('S n) b +scanl f = getScanl $ N.induction1 start step where + start :: Scanl a 'Z b + start = Scanl $ \z VNil -> singleton z + + step :: Scanl a m b -> Scanl a ('S m) b + step (Scanl go) = Scanl $ \acc (x ::: xs) -> acc ::: go (f acc x) xs + +-- | Left-to-right scan with strict accumulator. +scanl' :: forall a b n. N.SNatI n => (b -> a -> b) -> b -> Vec n a -> Vec ('S n) b +scanl' f = getScanl $ N.induction1 start step where + start :: Scanl a 'Z b + start = Scanl $ \z VNil -> singleton z + + step :: Scanl a m b -> Scanl a ('S m) b + step (Scanl go) = Scanl $ \(!acc) (x ::: xs) -> acc ::: go (f acc x) xs + +newtype Scanl a n b = Scanl { getScanl :: b -> Vec n a -> Vec ('S n) b } + +-- | Right-to-left scan with no starting value. +scanr1 :: forall a n. N.SNatI n => (a -> a -> a) -> Vec n a -> Vec n a +scanr1 f = getScanr1 $ N.induction1 start step where + start :: Scanr1 'Z a + start = Scanr1 $ \_ -> VNil + + step :: forall m. N.SNatI m => Scanr1 m a -> Scanr1 ('S m) a + step (Scanr1 go) = Scanr1 $ \(x ::: xs) -> case N.snat :: N.SNat m of + N.SZ -> x ::: VNil + N.SS -> let ys@(y ::: _) = go xs in f x y ::: ys + +newtype Scanr1 n a = Scanr1 { getScanr1 :: Vec n a -> Vec n a } + +-- | Left-to-right scan with no starting value. +scanl1 :: forall a n. N.SNatI n => (a -> a -> a) -> Vec n a -> Vec n a +scanl1 f xs = case N.snat :: N.SNat n of + N.SZ -> VNil + N.SS -> let (y ::: ys) = xs in scanl f y ys + +-- | Left-to-right scan with no starting value, and with strict accumulator. +scanl1' :: forall a n. N.SNatI n => (a -> a -> a) -> Vec n a -> Vec n a +scanl1' f xs = case N.snat :: N.SNat n of + N.SZ -> VNil + N.SS -> let (y ::: ys) = xs in scanl' f y ys + -- | Yield the length of a 'Vec'. /O(n)/ length :: forall n a. N.SNatI n => Vec n a -> Int length _ = getLength l where diff --git a/vec/src/Data/Vec/Lazy.hs b/vec/src/Data/Vec/Lazy.hs index 94f638d..5821636 100644 --- a/vec/src/Data/Vec/Lazy.hs +++ b/vec/src/Data/Vec/Lazy.hs @@ -55,6 +55,13 @@ module Data.Vec.Lazy ( foldr, ifoldr, foldl', + -- * Scans + scanr, + scanl, + scanl', + scanr1, + scanl1, + scanl1', -- * Special folds length, null, @@ -691,6 +698,45 @@ foldl' f z = go z where go !acc VNil = acc go !acc (x ::: xs) = go (f acc x) xs +-- | Right-to-left scan. +scanr :: forall a b n. (a -> b -> b) -> b -> Vec n a -> Vec ('S n) b +scanr f z = go where + go :: Vec m a -> Vec ('S m) b + go VNil = singleton z + go (x ::: xs) = case go xs of ys@(y ::: _) -> f x y ::: ys + +-- | Left-to-right scan. +scanl :: forall a b n. (b -> a -> b) -> b -> Vec n a -> Vec ('S n) b +scanl f = go where + go :: b -> Vec m a -> Vec ('S m) b + go acc VNil = acc ::: VNil + go acc (x ::: xs) = acc ::: go (f acc x) xs + +-- | Left-to-right scan with strict accumulator. +scanl' :: forall a b n. (b -> a -> b) -> b -> Vec n a -> Vec ('S n) b +scanl' f = go where + go :: b -> Vec m a -> Vec ('S m) b + go !acc VNil = acc ::: VNil + go !acc (x ::: xs) = acc ::: go (f acc x) xs + +-- | Right-to-left scan with no starting value. +scanr1 :: forall a n. (a -> a -> a) -> Vec n a -> Vec n a +scanr1 f = go where + go :: Vec m a -> Vec m a + go VNil = VNil + go (x ::: VNil) = x ::: VNil + go (x ::: xs@(_ ::: _)) = case go xs of ys@(y ::: _) -> f x y ::: ys + +-- | Left-to-right scan with no starting value. +scanl1 :: forall a n. (a -> a -> a) -> Vec n a -> Vec n a +scanl1 _ VNil = VNil +scanl1 f (x ::: xs) = scanl f x xs + +-- | Left-to-right scan with no starting value, and with strict accumulator. +scanl1' :: forall a n. (a -> a -> a) -> Vec n a -> Vec n a +scanl1' _ VNil = VNil +scanl1' f (x ::: xs) = scanl' f x xs + -- | Yield the length of a 'Vec'. /O(n)/ length :: Vec n a -> Int length = go 0 where diff --git a/vec/src/Data/Vec/Lazy/Inline.hs b/vec/src/Data/Vec/Lazy/Inline.hs index 74250d7..73910a1 100644 --- a/vec/src/Data/Vec/Lazy/Inline.hs +++ b/vec/src/Data/Vec/Lazy/Inline.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE BangPatterns #-} {-# LANGUAGE CPP #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleInstances #-} @@ -51,6 +52,13 @@ module Data.Vec.Lazy.Inline ( ifoldMap1, foldr, ifoldr, + -- * Scans + scanr, + scanl, + scanl', + scanr1, + scanl1, + scanl1', -- * Special folds length, null, @@ -260,10 +268,10 @@ last :: forall n a. N.SNatI n => Vec ('S n) a -> a last xs = getLast (N.induction1 start step) xs where start :: Last 'Z a start = Last $ \(x:::VNil) -> x - + step :: Last m a -> Last ('S m) a step (Last rec) = Last $ \(_ ::: ys) -> rec ys - + newtype Last n a = Last { getLast :: Vec ('S n) a -> a } @@ -274,7 +282,7 @@ init :: forall n a. N.SNatI n => Vec ('S n) a -> Vec n a init xs = getInit (N.induction1 start step) xs where start :: Init 'Z a start = Init (const VNil) - + step :: Init m a -> Init ('S m) a step (Init rec) = Init $ \(y ::: ys) -> y ::: rec ys @@ -520,6 +528,63 @@ ifoldr = getIFoldr $ N.induction1 start step where newtype IFoldr a n b = IFoldr { getIFoldr :: (Fin n -> a -> b -> b) -> b -> Vec n a -> b } +-- | Right-to-left scan. +scanr :: forall a b n. N.SNatI n => (a -> b -> b) -> b -> Vec n a -> Vec ('S n) b +scanr f z = getScanr $ N.induction1 start step where + start :: Scanr a 'Z b + start = Scanr $ \_ -> singleton z + + step :: Scanr a m b -> Scanr a ('S m) b + step (Scanr go) = Scanr $ \(x ::: xs) -> case go xs of + ys@(y ::: _) -> f x y ::: ys + +newtype Scanr a n b = Scanr { getScanr :: Vec n a -> Vec ('S n) b } + +-- | Left-to-right scan. +scanl :: forall a b n. N.SNatI n => (b -> a -> b) -> b -> Vec n a -> Vec ('S n) b +scanl f = getScanl $ N.induction1 start step where + start :: Scanl a 'Z b + start = Scanl $ \z VNil -> singleton z + + step :: Scanl a m b -> Scanl a ('S m) b + step (Scanl go) = Scanl $ \acc (x ::: xs) -> acc ::: go (f acc x) xs + +-- | Left-to-right scan with strict accumulator. +scanl' :: forall a b n. N.SNatI n => (b -> a -> b) -> b -> Vec n a -> Vec ('S n) b +scanl' f = getScanl $ N.induction1 start step where + start :: Scanl a 'Z b + start = Scanl $ \z VNil -> singleton z + + step :: Scanl a m b -> Scanl a ('S m) b + step (Scanl go) = Scanl $ \(!acc) (x ::: xs) -> acc ::: go (f acc x) xs + +newtype Scanl a n b = Scanl { getScanl :: b -> Vec n a -> Vec ('S n) b } + +-- | Right-to-left scan with no starting value. +scanr1 :: forall a n. N.SNatI n => (a -> a -> a) -> Vec n a -> Vec n a +scanr1 f = getScanr1 $ N.induction1 start step where + start :: Scanr1 'Z a + start = Scanr1 $ \_ -> VNil + + step :: forall m. N.SNatI m => Scanr1 m a -> Scanr1 ('S m) a + step (Scanr1 go) = Scanr1 $ \(x ::: xs) -> case N.snat :: N.SNat m of + N.SZ -> x ::: VNil + N.SS -> case go xs of ys@(y ::: _) -> f x y ::: ys + +newtype Scanr1 n a = Scanr1 { getScanr1 :: Vec n a -> Vec n a } + +-- | Left-to-right scan with no starting value. +scanl1 :: forall a n. N.SNatI n => (a -> a -> a) -> Vec n a -> Vec n a +scanl1 f xs = case N.snat :: N.SNat n of + N.SZ -> VNil + N.SS -> case xs of y ::: ys -> scanl f y ys + +-- | Left-to-right scan with no starting value, and with strict accumulator. +scanl1' :: forall a n. N.SNatI n => (a -> a -> a) -> Vec n a -> Vec n a +scanl1' f xs = case N.snat :: N.SNat n of + N.SZ -> VNil + N.SS -> case xs of y ::: ys -> scanl' f y ys + -- | Yield the length of a 'Vec'. /O(n)/ length :: forall n a. N.SNatI n => Vec n a -> Int length _ = getLength l where diff --git a/vec/src/Data/Vec/Pull.hs b/vec/src/Data/Vec/Pull.hs index a4b08ba..30d63a8 100644 --- a/vec/src/Data/Vec/Pull.hs +++ b/vec/src/Data/Vec/Pull.hs @@ -12,7 +12,7 @@ -- -- The module tries to have same API as "Data.Vec.Lazy", missing bits: -- @withDict@, @toPull@, @fromPull@, @traverse@ (and variants), --- @(++)@, @concat@ and @split@. +-- @scanr@ (and variants), @(++)@, @concat@ and @split@. module Data.Vec.Pull ( Vec (..), -- * Construction diff --git a/vec/test/Inspection.hs b/vec/test/Inspection.hs index 900d588..9ee1166 100644 --- a/vec/test/Inspection.hs +++ b/vec/test/Inspection.hs @@ -131,7 +131,7 @@ lhsLast = I.last $ 'a' ::: 'b' ::: 'c' ::: VNil lhsLast' :: Char lhsLast' = L.last $ 'a' ::: 'b' ::: 'c' :::VNil -rhsLast :: Char +rhsLast :: Char rhsLast = 'c' inspect $ 'lhsLast === 'rhsLast @@ -167,4 +167,100 @@ rhsToNonEmpty :: NonEmpty Char rhsToNonEmpty = 'a' :| ['b', 'c'] inspect $ 'lhsToNonEmpty === 'rhsToNonEmpty -inspect $ 'lhsToNonEmpty' =/= 'rhsToNonEmpty \ No newline at end of file +inspect $ 'lhsToNonEmpty' =/= 'rhsToNonEmpty + +------------------------------------------------------------------------------- +-- scanr +------------------------------------------------------------------------------- + +lhsScanr :: Vec N.Nat5 Int +lhsScanr = I.scanr (-) 0 $ 1 ::: 2 ::: 3 ::: 4 ::: VNil + +lhsScanr' :: Vec N.Nat5 Int +lhsScanr' = L.scanr (-) 0 $ 1 ::: 2 ::: 3 ::: 4 ::: VNil + +rhsScanr :: Vec N.Nat5 Int +rhsScanr = (-2) ::: 3 ::: (-1) ::: 4 ::: 0 ::: VNil + +inspect $ 'lhsScanr === 'rhsScanr +inspect $ 'lhsScanr' =/= 'rhsScanr + +------------------------------------------------------------------------------- +-- scanl +------------------------------------------------------------------------------- + +lhsScanl :: Vec N.Nat5 Int +lhsScanl = I.scanl (-) 0 $ 1 ::: 2 ::: 3 ::: 4 ::: VNil + +lhsScanl0 :: Vec N.Nat5 Int +lhsScanl0 = L.scanl (-) 0 $ 1 ::: 2 ::: 3 ::: 4 ::: VNil + +rhsScanl :: Vec N.Nat5 Int +rhsScanl = 0 ::: (-1) ::: (-3) ::: (-6) ::: (-10) ::: VNil + +inspect $ 'lhsScanl === 'rhsScanl +inspect $ 'lhsScanl0 =/= 'rhsScanl + +------------------------------------------------------------------------------- +-- scanl' +------------------------------------------------------------------------------- + +lhsScanl' :: Vec N.Nat5 Int +lhsScanl' = I.scanl' (-) 0 $ 1 ::: 2 ::: 3 ::: 4 ::: VNil + +lhsScanl'0 :: Vec N.Nat5 Int +lhsScanl'0 = L.scanl' (-) 0 $ 1 ::: 2 ::: 3 ::: 4 ::: VNil + +rhsScanl' :: Vec N.Nat5 Int +rhsScanl' = 0 ::: (-1) ::: (-3) ::: (-6) ::: (-10) ::: VNil + +inspect $ 'lhsScanl' === 'rhsScanl' +inspect $ 'lhsScanl'0 =/= 'rhsScanl' + +------------------------------------------------------------------------------- +-- scanr1 +------------------------------------------------------------------------------- + +lhsScanr1 :: Vec N.Nat4 Int +lhsScanr1 = I.scanr1 (-) $ 1 ::: 2 ::: 3 ::: 4 ::: VNil + +lhsScanr1' :: Vec N.Nat4 Int +lhsScanr1' = L.scanr1 (-) $ 1 ::: 2 ::: 3 ::: 4 ::: VNil + +rhsScanr1 :: Vec N.Nat4 Int +rhsScanr1 = (-2) ::: 3 ::: (-1) ::: 4 ::: VNil + +inspect $ 'lhsScanr1 === 'rhsScanr1 +inspect $ 'lhsScanr1' =/= 'rhsScanr1 + +------------------------------------------------------------------------------- +-- scanl1 +------------------------------------------------------------------------------- + +lhsScanl1 :: Vec N.Nat4 Int +lhsScanl1 = I.scanl1 (-) $ 1 ::: 2 ::: 3 ::: 4 ::: VNil + +lhsScanl10 :: Vec N.Nat4 Int +lhsScanl10 = L.scanl1 (-) $ 1 ::: 2 ::: 3 ::: 4 ::: VNil + +rhsScanl1 :: Vec N.Nat4 Int +rhsScanl1 = 1 ::: (-1) ::: (-4) ::: (-8) ::: VNil + +inspect $ 'lhsScanl1 === 'rhsScanl1 +inspect $ 'lhsScanl10 =/= 'rhsScanl1 + +------------------------------------------------------------------------------- +-- scanl1' +------------------------------------------------------------------------------- + +lhsScanl1' :: Vec N.Nat4 Int +lhsScanl1' = I.scanl1' (-) $ 1 ::: 2 ::: 3 ::: 4 ::: VNil + +lhsScanl1'0 :: Vec N.Nat4 Int +lhsScanl1'0 = L.scanl1' (-) $ 1 ::: 2 ::: 3 ::: 4 ::: VNil + +rhsScanl1' :: Vec N.Nat4 Int +rhsScanl1' = 1 ::: (-1) ::: (-4) ::: (-8) ::: VNil + +inspect $ 'lhsScanl1' === 'rhsScanl1' +inspect $ 'lhsScanl1'0 =/= 'rhsScanl1' diff --git a/vec/test/Inspection/DataFamily/SpineStrict.hs b/vec/test/Inspection/DataFamily/SpineStrict.hs index 29d0bad..527cf41 100644 --- a/vec/test/Inspection/DataFamily/SpineStrict.hs +++ b/vec/test/Inspection/DataFamily/SpineStrict.hs @@ -93,3 +93,75 @@ rhsReverse :: Vec N.Nat3 Char rhsReverse = 'a' ::: 'b' ::: 'c' ::: VNil inspect $ 'lhsReverse === 'rhsReverse + +------------------------------------------------------------------------------- +-- scanr +------------------------------------------------------------------------------- + +lhsScanr :: Vec N.Nat5 Int +lhsScanr = I.scanr (-) 0 $ 1 ::: 2 ::: 3 ::: 4 ::: VNil + +rhsScanr :: Vec N.Nat5 Int +rhsScanr = (-2) ::: 3 ::: (-1) ::: 4 ::: 0 ::: VNil + +inspect $ 'lhsScanr === 'rhsScanr + +------------------------------------------------------------------------------- +-- scanl +------------------------------------------------------------------------------- + +lhsScanl :: Vec N.Nat5 Int +lhsScanl = I.scanl (-) 0 $ 1 ::: 2 ::: 3 ::: 4 ::: VNil + +rhsScanl :: Vec N.Nat5 Int +rhsScanl = 0 ::: (-1) ::: (-3) ::: (-6) ::: (-10) ::: VNil + +inspect $ 'lhsScanl === 'rhsScanl + +------------------------------------------------------------------------------- +-- scanl' +------------------------------------------------------------------------------- + +lhsScanl' :: Vec N.Nat5 Int +lhsScanl' = I.scanl' (-) 0 $ 1 ::: 2 ::: 3 ::: 4 ::: VNil + +rhsScanl' :: Vec N.Nat5 Int +rhsScanl' = 0 ::: (-1) ::: (-3) ::: (-6) ::: (-10) ::: VNil + +inspect $ 'lhsScanl' === 'rhsScanl' + +------------------------------------------------------------------------------- +-- scanr1 +------------------------------------------------------------------------------- + +lhsScanr1 :: Vec N.Nat4 Int +lhsScanr1 = I.scanr1 (-) $ 1 ::: 2 ::: 3 ::: 4 ::: VNil + +rhsScanr1 :: Vec N.Nat4 Int +rhsScanr1 = (-2) ::: 3 ::: (-1) ::: 4 ::: VNil + +inspect $ 'lhsScanr1 === 'rhsScanr1 + +------------------------------------------------------------------------------- +-- scanl1 +------------------------------------------------------------------------------- + +lhsScanl1 :: Vec N.Nat4 Int +lhsScanl1 = I.scanl1 (-) $ 1 ::: 2 ::: 3 ::: 4 ::: VNil + +rhsScanl1 :: Vec N.Nat4 Int +rhsScanl1 = 1 ::: (-1) ::: (-4) ::: (-8) ::: VNil + +inspect $ 'lhsScanl1 === 'rhsScanl1 + +------------------------------------------------------------------------------- +-- scanl1' +------------------------------------------------------------------------------- + +lhsScanl1' :: Vec N.Nat4 Int +lhsScanl1' = I.scanl1' (-) $ 1 ::: 2 ::: 3 ::: 4 ::: VNil + +rhsScanl1' :: Vec N.Nat4 Int +rhsScanl1' = 1 ::: (-1) ::: (-4) ::: (-8) ::: VNil + +inspect $ 'lhsScanl1' === 'rhsScanl1'