Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add scanr, scanl, scanr1, scanl1 #92

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 38 additions & 3 deletions vec/src/Data/Vec/DataFamily/SpineStrict.hs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,11 @@ module Data.Vec.DataFamily.SpineStrict (
ifoldMap1,
foldr,
ifoldr,
-- * Scans
scanr,
scanl,
scanr1,
scanl1,
-- * Special folds
length,
null,
Expand Down Expand Up @@ -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 }

Expand All @@ -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

Expand Down Expand Up @@ -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
zliu41 marked this conversation as resolved.
Show resolved Hide resolved

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
Expand Down
28 changes: 28 additions & 0 deletions vec/src/Data/Vec/Lazy.hs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ module Data.Vec.Lazy (
foldr,
ifoldr,
foldl',
-- * Scans
scanr,
scanl,
scanr1,
scanl1,
-- * Special folds
length,
null,
Expand Down Expand Up @@ -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
Expand Down
33 changes: 29 additions & 4 deletions vec/src/Data/Vec/Lazy/Inline.hs
Original file line number Diff line number Diff line change
Expand Up @@ -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 (..),
Expand Down Expand Up @@ -51,6 +51,9 @@ module Data.Vec.Lazy.Inline (
ifoldMap1,
foldr,
ifoldr,
-- * Scans
scanr,
scanr1,
-- * Special folds
length,
null,
Expand Down Expand Up @@ -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 }

Expand All @@ -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

Expand Down Expand Up @@ -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
Expand Down
20 changes: 20 additions & 0 deletions vec/src/Data/Vec/Pull.hs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ module Data.Vec.Pull (
foldr,
ifoldr,
foldl',
-- * Scans
scanr,
scanl,
scanr1,
scanl1,
-- * Special folds
length,
null,
Expand All @@ -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 (..))
Expand Down Expand Up @@ -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
zliu41 marked this conversation as resolved.
Show resolved Hide resolved

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)
Expand Down
21 changes: 19 additions & 2 deletions vec/test/Inspection.hs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -167,4 +168,20 @@ rhsToNonEmpty :: NonEmpty Char
rhsToNonEmpty = 'a' :| ['b', 'c']

inspect $ 'lhsToNonEmpty === 'rhsToNonEmpty
inspect $ 'lhsToNonEmpty' =/= 'rhsToNonEmpty
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
24 changes: 24 additions & 0 deletions vec/test/Inspection/DataFamily/SpineStrict.hs
Original file line number Diff line number Diff line change
Expand Up @@ -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