From db7b272097c09edc7da5c58cf1f33a574ec75f03 Mon Sep 17 00:00:00 2001 From: Ziyang Liu Date: Sun, 25 Jul 2021 13:59:53 -0700 Subject: [PATCH 1/3] Add scanr, scanl, scanr1, scanl1 --- vec/src/Data/Vec/DataFamily/SpineStrict.hs | 41 +++++++++++++++++-- vec/src/Data/Vec/Lazy.hs | 28 +++++++++++++ vec/src/Data/Vec/Lazy/Inline.hs | 33 +++++++++++++-- vec/src/Data/Vec/Pull.hs | 20 +++++++++ vec/test/Inspection.hs | 21 +++++++++- vec/test/Inspection/DataFamily/SpineStrict.hs | 24 +++++++++++ 6 files changed, 158 insertions(+), 9 deletions(-) diff --git a/vec/src/Data/Vec/DataFamily/SpineStrict.hs b/vec/src/Data/Vec/DataFamily/SpineStrict.hs index 22e4b70..36746ef 100644 --- a/vec/src/Data/Vec/DataFamily/SpineStrict.hs +++ b/vec/src/Data/Vec/DataFamily/SpineStrict.hs @@ -91,6 +91,11 @@ module Data.Vec.DataFamily.SpineStrict ( ifoldMap1, foldr, ifoldr, + -- * Scans + scanr, + scanl, + scanr1, + scanl1, -- * Special folds length, null, @@ -582,10 +587,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 +601,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 +850,36 @@ ifoldr = getIFoldr $ N.induction1 start step where newtype IFoldr a n b = IFoldr { getIFoldr :: (Fin n -> a -> b -> b) -> b -> Vec n a -> b } +scanr :: forall a b n. N.SNatI n => (a -> b -> b) -> b -> Vec n a -> Vec ('S n) b +scanr f z = getScan $ N.induction1 start step where + start :: Scan a 'Z b + start = Scan $ \_ -> singleton z + + step :: Scan a m b -> Scan a ('S m) b + step (Scan go) = Scan $ \(x ::: xs) -> let ys@(y ::: _) = go xs in f x y ::: ys + +newtype Scan a n b = Scan { getScan :: Vec n a -> Vec ('S n) b } + +scanl :: forall a b n. N.SNatI n => (b -> a -> b) -> b -> Vec n a -> Vec ('S n) b +scanl f z = reverse . scanr (flip f) z . reverse + +scanr1 :: forall a n. N.SNatI n => (a -> a -> a) -> Vec n a -> Vec n a +scanr1 f = getScan1 $ N.induction1 start step where + start :: Scan1 'Z a + start = Scan1 $ \_ -> VNil + + step :: forall m. N.SNatI m => Scan1 m a -> Scan1 ('S m) a + step (Scan1 go) = Scan1 $ \(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 Scan1 n a = Scan1 { getScan1 :: Vec n a -> Vec n a } + +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..1fb3c9c 100644 --- a/vec/src/Data/Vec/Lazy.hs +++ b/vec/src/Data/Vec/Lazy.hs @@ -55,6 +55,11 @@ module Data.Vec.Lazy ( foldr, ifoldr, foldl', + -- * Scans + scanr, + scanl, + scanr1, + scanl1, -- * Special folds length, null, @@ -691,6 +696,29 @@ foldl' f z = go z where go !acc VNil = acc go !acc (x ::: xs) = go (f acc x) xs +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) = let ys@(y ::: _) = go xs in f x y ::: ys + +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 + +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@(_ ::: _)) = let ys@(y ::: _) = go xs in f x y ::: ys + +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..d386425 100644 --- a/vec/src/Data/Vec/Lazy/Inline.hs +++ b/vec/src/Data/Vec/Lazy/Inline.hs @@ -12,7 +12,7 @@ -- The hypothesis is that these (goursive) functions could be fully unrolled, -- if the 'Vec' size @n@ is known at compile time. -- --- The module has the same API as "Data.Vec.Lazy" (sans 'L.withDict' and 'foldl''). +-- The module has the same API as "Data.Vec.Lazy" (sans 'L.withDict', 'foldl'', 'scanl' and 'scanl1'). -- /Note:/ instance methods aren't changed, the 'Vec' type is the same. module Data.Vec.Lazy.Inline ( Vec (..), @@ -51,6 +51,9 @@ module Data.Vec.Lazy.Inline ( ifoldMap1, foldr, ifoldr, + -- * Scans + scanr, + scanr1, -- * Special folds length, null, @@ -260,10 +263,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 +277,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 +523,28 @@ ifoldr = getIFoldr $ N.induction1 start step where newtype IFoldr a n b = IFoldr { getIFoldr :: (Fin n -> a -> b -> b) -> b -> Vec n a -> b } +scanr :: forall a b n. N.SNatI n => (a -> b -> b) -> b -> Vec n a -> Vec ('S n) b +scanr f z = getScan $ N.induction1 start step where + start :: Scan a 'Z b + start = Scan $ \_ -> singleton z + + step :: Scan a m b -> Scan a ('S m) b + step (Scan go) = Scan $ \(x ::: xs) -> let ys@(y ::: _) = go xs in f x y ::: ys + +newtype Scan a n b = Scan { getScan :: Vec n a -> Vec ('S n) b } + +scanr1 :: forall a n. N.SNatI n => (a -> a -> a) -> Vec n a -> Vec n a +scanr1 f = getScan1 $ N.induction1 start step where + start :: Scan1 'Z a + start = Scan1 $ \_ -> VNil + + step :: forall m. N.SNatI m => Scan1 m a -> Scan1 ('S m) a + step (Scan1 go) = Scan1 $ \(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 Scan1 n a = Scan1 { getScan1 :: Vec n a -> Vec n a } + -- | 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..07c5a3e 100644 --- a/vec/src/Data/Vec/Pull.hs +++ b/vec/src/Data/Vec/Pull.hs @@ -43,6 +43,11 @@ module Data.Vec.Pull ( foldr, ifoldr, foldl', + -- * Scans + scanr, + scanl, + scanr1, + scanl1, -- * Special folds length, null, @@ -69,7 +74,10 @@ import Prelude import Control.Applicative (Applicative (..), (<$>)) import Data.Boring (Boring (..)) import Data.Fin (Fin (..)) +import qualified Data.List as List import Data.List.NonEmpty (NonEmpty (..)) +import qualified Data.List.NonEmpty as NonEmpty +import Data.Maybe (fromJust) import Data.Monoid (Monoid (..)) import Data.Nat (Nat (..)) import Data.Proxy (Proxy (..)) @@ -380,6 +388,18 @@ ifoldr f z (Vec v) = I.foldr (\a b -> f a (v a) b) z F.universe foldl' :: N.SNatI n => (b -> a -> b) -> b -> Vec n a -> b foldl' f z (Vec v) = I.foldl' (\b a -> f b (v a)) z F.universe +scanr :: forall a b n. N.SNatI n => (a -> b -> b) -> b -> Vec n a -> Vec ('S n) b +scanr f z = fromJust . fromList . NonEmpty.toList . NonEmpty.scanr f z + +scanl :: forall a b n. N.SNatI n => (b -> a -> b) -> b -> Vec n a -> Vec ('S n) b +scanl f z = fromJust . fromList . NonEmpty.toList . NonEmpty.scanl f z + +scanr1 :: forall a n. N.SNatI n => (a -> a -> a) -> Vec n a -> Vec n a +scanr1 f = fromJust . fromList . List.scanr1 f . toList + +scanl1 :: forall a n. N.SNatI n => (a -> a -> a) -> Vec n a -> Vec n a +scanl1 f = fromJust . fromList . List.scanl1 f . toList + -- | Yield the length of a 'Vec'. length :: forall n a. N.SNatI n => Vec n a -> Int length _ = N.reflectToNum (Proxy :: Proxy n) diff --git a/vec/test/Inspection.hs b/vec/test/Inspection.hs index 900d588..8b07717 100644 --- a/vec/test/Inspection.hs +++ b/vec/test/Inspection.hs @@ -6,6 +6,7 @@ module Inspection where import Prelude hiding (zipWith) import Data.Fin (Fin (..)) +import qualified Data.List as List import Data.List.NonEmpty (NonEmpty (..)) import Data.Vec.Lazy (Vec (..)) import Test.Inspection @@ -131,7 +132,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 +168,20 @@ 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 diff --git a/vec/test/Inspection/DataFamily/SpineStrict.hs b/vec/test/Inspection/DataFamily/SpineStrict.hs index 29d0bad..4f9ec8c 100644 --- a/vec/test/Inspection/DataFamily/SpineStrict.hs +++ b/vec/test/Inspection/DataFamily/SpineStrict.hs @@ -93,3 +93,27 @@ 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 From c39baba8e7dd44e0c1ef45dd7f25c6a53dcfd7bb Mon Sep 17 00:00:00 2001 From: Ziyang Liu Date: Mon, 26 Jul 2021 10:05:10 -0700 Subject: [PATCH 2/3] Address review comments --- vec/src/Data/Vec/DataFamily/SpineStrict.hs | 34 ++++++++----- vec/src/Data/Vec/Lazy.hs | 4 +- vec/src/Data/Vec/Lazy/Inline.hs | 47 ++++++++++++------ vec/src/Data/Vec/Pull.hs | 22 +-------- vec/test/Inspection.hs | 49 ++++++++++++++++++- vec/test/Inspection/DataFamily/SpineStrict.hs | 24 +++++++++ 6 files changed, 129 insertions(+), 51 deletions(-) diff --git a/vec/src/Data/Vec/DataFamily/SpineStrict.hs b/vec/src/Data/Vec/DataFamily/SpineStrict.hs index 36746ef..8c914d2 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 #-} @@ -851,29 +852,36 @@ ifoldr = getIFoldr $ N.induction1 start step where newtype IFoldr a n b = IFoldr { getIFoldr :: (Fin n -> a -> b -> b) -> b -> Vec n a -> b } scanr :: forall a b n. N.SNatI n => (a -> b -> b) -> b -> Vec n a -> Vec ('S n) b -scanr f z = getScan $ N.induction1 start step where - start :: Scan a 'Z b - start = Scan $ \_ -> singleton z +scanr f z = getScanr $ N.induction1 start step where + start :: Scanr a 'Z b + start = Scanr $ \_ -> singleton z - step :: Scan a m b -> Scan a ('S m) b - step (Scan go) = Scan $ \(x ::: xs) -> let ys@(y ::: _) = go xs in f x y ::: ys + 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 Scan a n b = Scan { getScan :: Vec n a -> Vec ('S n) b } +newtype Scanr a n b = Scanr { getScanr :: Vec n a -> Vec ('S n) b } scanl :: forall a b n. N.SNatI n => (b -> a -> b) -> b -> Vec n a -> Vec ('S n) b -scanl f z = reverse . scanr (flip f) z . reverse +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 } scanr1 :: forall a n. N.SNatI n => (a -> a -> a) -> Vec n a -> Vec n a -scanr1 f = getScan1 $ N.induction1 start step where - start :: Scan1 'Z a - start = Scan1 $ \_ -> VNil +scanr1 f = getScanr1 $ N.induction1 start step where + start :: Scanr1 'Z a + start = Scanr1 $ \_ -> VNil - step :: forall m. N.SNatI m => Scan1 m a -> Scan1 ('S m) a - step (Scan1 go) = Scan1 $ \(x ::: xs) -> case N.snat :: N.SNat m of + 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 Scan1 n a = Scan1 { getScan1 :: Vec n a -> Vec n a } +newtype Scanr1 n a = Scanr1 { getScanr1 :: Vec n a -> Vec n a } 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 diff --git a/vec/src/Data/Vec/Lazy.hs b/vec/src/Data/Vec/Lazy.hs index 1fb3c9c..499985e 100644 --- a/vec/src/Data/Vec/Lazy.hs +++ b/vec/src/Data/Vec/Lazy.hs @@ -700,7 +700,7 @@ 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) = let ys@(y ::: _) = go xs in f x y ::: ys + go (x ::: xs) = case go xs of ys@(y ::: _) -> f x y ::: ys scanl :: forall a b n. (b -> a -> b) -> b -> Vec n a -> Vec ('S n) b scanl f = go where @@ -713,7 +713,7 @@ scanr1 f = go where go :: Vec m a -> Vec m a go VNil = VNil go (x ::: VNil) = x ::: VNil - go (x ::: xs@(_ ::: _)) = let ys@(y ::: _) = go xs in f x y ::: ys + go (x ::: xs@(_ ::: _)) = case go xs of ys@(y ::: _) -> f x y ::: ys scanl1 :: forall a n. (a -> a -> a) -> Vec n a -> Vec n a scanl1 _ VNil = VNil diff --git a/vec/src/Data/Vec/Lazy/Inline.hs b/vec/src/Data/Vec/Lazy/Inline.hs index d386425..ca41f9f 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 #-} @@ -12,7 +13,7 @@ -- The hypothesis is that these (goursive) functions could be fully unrolled, -- if the 'Vec' size @n@ is known at compile time. -- --- The module has the same API as "Data.Vec.Lazy" (sans 'L.withDict', 'foldl'', 'scanl' and 'scanl1'). +-- The module has the same API as "Data.Vec.Lazy" (sans 'L.withDict' and 'foldl''). -- /Note:/ instance methods aren't changed, the 'Vec' type is the same. module Data.Vec.Lazy.Inline ( Vec (..), @@ -53,7 +54,9 @@ module Data.Vec.Lazy.Inline ( ifoldr, -- * Scans scanr, + scanl, scanr1, + scanl1, -- * Special folds length, null, @@ -524,26 +527,42 @@ ifoldr = getIFoldr $ N.induction1 start step where newtype IFoldr a n b = IFoldr { getIFoldr :: (Fin n -> a -> b -> b) -> b -> Vec n a -> b } scanr :: forall a b n. N.SNatI n => (a -> b -> b) -> b -> Vec n a -> Vec ('S n) b -scanr f z = getScan $ N.induction1 start step where - start :: Scan a 'Z b - start = Scan $ \_ -> singleton z +scanr f z = getScanr $ N.induction1 start step where + start :: Scanr a 'Z b + start = Scanr $ \_ -> singleton z - step :: Scan a m b -> Scan a ('S m) b - step (Scan go) = Scan $ \(x ::: xs) -> let ys@(y ::: _) = go xs in f x y ::: ys + 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 Scan a n b = Scan { getScan :: Vec n a -> Vec ('S n) b } +newtype Scanr a n b = Scanr { getScanr :: Vec n a -> Vec ('S n) b } + +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 } scanr1 :: forall a n. N.SNatI n => (a -> a -> a) -> Vec n a -> Vec n a -scanr1 f = getScan1 $ N.induction1 start step where - start :: Scan1 'Z a - start = Scan1 $ \_ -> VNil +scanr1 f = getScanr1 $ N.induction1 start step where + start :: Scanr1 'Z a + start = Scanr1 $ \_ -> VNil - step :: forall m. N.SNatI m => Scan1 m a -> Scan1 ('S m) a - step (Scan1 go) = Scan1 $ \(x ::: xs) -> case N.snat :: N.SNat m of + 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 + N.SS -> case go xs of ys@(y ::: _) -> f x y ::: ys + +newtype Scanr1 n a = Scanr1 { getScanr1 :: Vec n a -> Vec n a } -newtype Scan1 n a = Scan1 { getScan1 :: Vec n a -> Vec n a } +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 diff --git a/vec/src/Data/Vec/Pull.hs b/vec/src/Data/Vec/Pull.hs index 07c5a3e..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 @@ -43,11 +43,6 @@ module Data.Vec.Pull ( foldr, ifoldr, foldl', - -- * Scans - scanr, - scanl, - scanr1, - scanl1, -- * Special folds length, null, @@ -74,10 +69,7 @@ import Prelude import Control.Applicative (Applicative (..), (<$>)) import Data.Boring (Boring (..)) import Data.Fin (Fin (..)) -import qualified Data.List as List import Data.List.NonEmpty (NonEmpty (..)) -import qualified Data.List.NonEmpty as NonEmpty -import Data.Maybe (fromJust) import Data.Monoid (Monoid (..)) import Data.Nat (Nat (..)) import Data.Proxy (Proxy (..)) @@ -388,18 +380,6 @@ ifoldr f z (Vec v) = I.foldr (\a b -> f a (v a) b) z F.universe foldl' :: N.SNatI n => (b -> a -> b) -> b -> Vec n a -> b foldl' f z (Vec v) = I.foldl' (\b a -> f b (v a)) z F.universe -scanr :: forall a b n. N.SNatI n => (a -> b -> b) -> b -> Vec n a -> Vec ('S n) b -scanr f z = fromJust . fromList . NonEmpty.toList . NonEmpty.scanr f z - -scanl :: forall a b n. N.SNatI n => (b -> a -> b) -> b -> Vec n a -> Vec ('S n) b -scanl f z = fromJust . fromList . NonEmpty.toList . NonEmpty.scanl f z - -scanr1 :: forall a n. N.SNatI n => (a -> a -> a) -> Vec n a -> Vec n a -scanr1 f = fromJust . fromList . List.scanr1 f . toList - -scanl1 :: forall a n. N.SNatI n => (a -> a -> a) -> Vec n a -> Vec n a -scanl1 f = fromJust . fromList . List.scanl1 f . toList - -- | Yield the length of a 'Vec'. length :: forall n a. N.SNatI n => Vec n a -> Int length _ = N.reflectToNum (Proxy :: Proxy n) diff --git a/vec/test/Inspection.hs b/vec/test/Inspection.hs index 8b07717..e63353a 100644 --- a/vec/test/Inspection.hs +++ b/vec/test/Inspection.hs @@ -6,7 +6,6 @@ module Inspection where import Prelude hiding (zipWith) import Data.Fin (Fin (..)) -import qualified Data.List as List import Data.List.NonEmpty (NonEmpty (..)) import Data.Vec.Lazy (Vec (..)) import Test.Inspection @@ -185,3 +184,51 @@ 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 + +lhsScanl' :: Vec N.Nat5 Int +lhsScanl' = 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' =/= '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 + +lhsScanl1' :: Vec N.Nat4 Int +lhsScanl1' = L.scanl1 (-) $ 1 ::: 2 ::: 3 ::: 4 ::: VNil + +rhsScanl1 :: Vec N.Nat4 Int +rhsScanl1 = 1 ::: (-1) ::: (-4) ::: (-8) ::: VNil + +inspect $ 'lhsScanl1 === 'rhsScanl1 +inspect $ 'lhsScanl1' =/= 'rhsScanl1 diff --git a/vec/test/Inspection/DataFamily/SpineStrict.hs b/vec/test/Inspection/DataFamily/SpineStrict.hs index 4f9ec8c..1d169c6 100644 --- a/vec/test/Inspection/DataFamily/SpineStrict.hs +++ b/vec/test/Inspection/DataFamily/SpineStrict.hs @@ -117,3 +117,27 @@ 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 From c2d72a41dc6a30f2c758e1776fc6acfec8d41cda Mon Sep 17 00:00:00 2001 From: Ziyang Liu Date: Mon, 26 Jul 2021 18:32:25 -0700 Subject: [PATCH 3/3] Add scanl' and scanl1' --- vec/src/Data/Vec/DataFamily/SpineStrict.hs | 21 +++++++++ vec/src/Data/Vec/Lazy.hs | 18 ++++++++ vec/src/Data/Vec/Lazy/Inline.hs | 21 +++++++++ vec/test/Inspection.hs | 44 ++++++++++++++++--- vec/test/Inspection/DataFamily/SpineStrict.hs | 24 ++++++++++ 5 files changed, 122 insertions(+), 6 deletions(-) diff --git a/vec/src/Data/Vec/DataFamily/SpineStrict.hs b/vec/src/Data/Vec/DataFamily/SpineStrict.hs index 8c914d2..bd018ab 100644 --- a/vec/src/Data/Vec/DataFamily/SpineStrict.hs +++ b/vec/src/Data/Vec/DataFamily/SpineStrict.hs @@ -95,8 +95,10 @@ module Data.Vec.DataFamily.SpineStrict ( -- * Scans scanr, scanl, + scanl', scanr1, scanl1, + scanl1', -- * Special folds length, null, @@ -851,6 +853,7 @@ 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 @@ -861,16 +864,27 @@ scanr f z = getScanr $ N.induction1 start step where 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 @@ -883,11 +897,18 @@ scanr1 f = getScanr1 $ N.induction1 start step where 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 499985e..5821636 100644 --- a/vec/src/Data/Vec/Lazy.hs +++ b/vec/src/Data/Vec/Lazy.hs @@ -58,8 +58,10 @@ module Data.Vec.Lazy ( -- * Scans scanr, scanl, + scanl', scanr1, scanl1, + scanl1', -- * Special folds length, null, @@ -696,18 +698,28 @@ 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 @@ -715,10 +727,16 @@ scanr1 f = go where 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 ca41f9f..73910a1 100644 --- a/vec/src/Data/Vec/Lazy/Inline.hs +++ b/vec/src/Data/Vec/Lazy/Inline.hs @@ -55,8 +55,10 @@ module Data.Vec.Lazy.Inline ( -- * Scans scanr, scanl, + scanl', scanr1, scanl1, + scanl1', -- * Special folds length, null, @@ -526,6 +528,7 @@ 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 @@ -537,16 +540,27 @@ scanr f z = getScanr $ N.induction1 start step where 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 @@ -559,11 +573,18 @@ scanr1 f = getScanr1 $ N.induction1 start step where 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/test/Inspection.hs b/vec/test/Inspection.hs index e63353a..9ee1166 100644 --- a/vec/test/Inspection.hs +++ b/vec/test/Inspection.hs @@ -192,14 +192,30 @@ inspect $ 'lhsScanr' =/= 'rhsScanr lhsScanl :: Vec N.Nat5 Int lhsScanl = I.scanl (-) 0 $ 1 ::: 2 ::: 3 ::: 4 ::: VNil -lhsScanl' :: Vec N.Nat5 Int -lhsScanl' = L.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 $ '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 @@ -224,11 +240,27 @@ inspect $ 'lhsScanr1' =/= 'rhsScanr1 lhsScanl1 :: Vec N.Nat4 Int lhsScanl1 = I.scanl1 (-) $ 1 ::: 2 ::: 3 ::: 4 ::: VNil -lhsScanl1' :: Vec N.Nat4 Int -lhsScanl1' = L.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 $ '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 1d169c6..527cf41 100644 --- a/vec/test/Inspection/DataFamily/SpineStrict.hs +++ b/vec/test/Inspection/DataFamily/SpineStrict.hs @@ -118,6 +118,18 @@ 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 ------------------------------------------------------------------------------- @@ -141,3 +153,15 @@ 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'