Is it possible to use list style pattern matching on vectors?
ie
import qualified Data.Vector as V
f :: V.Vector a -> a
f (x:xs) = x
gives an error
Is it possible to use list style pattern matching on vectors?
ie
import qualified Data.Vector as V
f :: V.Vector a -> a
f (x:xs) = x
gives an error
-XViewPatterns
can let you do this:
{-# LANGUAGE ViewPatterns #-}
module VecViewPats where
import Data.Vector (Vector)
import qualified Data.Vector as V
uncons :: Vector a -> Maybe (a, Vector a)
uncons v = if V.null v
then Nothing
else Just (V.unsafeHead v, V.unsafeTail v)
vsum :: Num a => Vector a -> a
vsum (uncons -> Just (a,av)) = a + vsum av
vsum (uncons -> Nothing) = 0
Or -XLambdaCase
import Control.Category ((>>>))
-- ...
vsum :: Num a => Vector a -> a
vsum = uncons >>> \case
Just (a,av) -> a + vsum av
Nothing -> 0
But honestly, that's seems like a bit of a code smell as you're using one data structure (Vector
) as another ([]
) which suggests that maybe your choice of data structure is off.
If you really just want to treat it like a list for the purposes of some algorithm, why not use toList
?
Statistics
library, which work on Vectors
. So I apparently would have to toList
to work over my list then fromList
to use the functions? which seems to defeat the point? –
Communicate fmap
. A single value? Use fold
. A selection of the elements? Use filter
. With both lists and vectors, specialized higher-order functions exist to make various tasks both more efficient and easier for others to read. –
Summersummerhouse @Cactus has pointed out -XPatternSynonym
(introduced in 7.8) combined with -XViewPattern
can be used to pattern match on vectors. I am here to extend his comment a bit further.
pattern Empty <- (V.null -> True)
The above defines a pattern synonym Empty
for the empty vector. The Empty
pattern matches against an empty vector using view pattern (V.null -> True
). However, it cannot be used as an expression elsewhere, i.e. a uni-directional synonym, since the system doesn't really know what Empty
is as a Vector (we only know that null v
is True
but there could be other vectors giving True
as well).
To remedy this, a where
clause can be added specifying that Empty actually is a empty vector, i.e. a bi-directional synonym, as well as a type signature:
pattern Empty :: Vector a
pattern Empty <- (V.null -> True) where Empty = V.empty
This pattern synonym can be used to define uncons
without an if expression:
uncons :: Vector a -> Maybe (a, Vector a)
uncons Empty = Nothing
uncons v = Just (unsafeHead v, unsafeTail v)
We use uncons
to define uni-directional synonym. Note I don't make it bi-directional since cons
is costly for vector:
pattern (:<|) :: a -> Vector a -> Vector a
pattern x :<| xs <- (uncons -> Just (x, xs))
Anyway, we are finally able to pattern match on vectors just like lists:
vsum :: Num a => Vector a -> a
vsum Empty = 0
vsum (x :<| xs) = x + vsum xs
A complete code is here.
Vectors aren't intended for that kind of pattern matching--they were created to give Haskell O(1) lists, or lists that can be accessed from any point efficiently.
The closest thing to what you wrote would be something like this:
f v = V.head v
Or, if recursion is what you are looking for, the tail
function will get the rest of the list.
But if you are trying to do something that moves along a list like that, there are Vector equivalents of functions such as foldl
, find
, map
, and the like. It depends on what you intend to do.
f :: Vector a -> a
on a vector, but I want to move across the vector and recalculate (while keeping the other values) as each new item is added. ie on [1,2,3,4,5,6,7,8,10]
, i want to [f [1], f [1,2], f [1,2,3]..]
and so on. –
Communicate f
. If there exists g
s.t. f [a_0...a_i] = g (f [a_0...a_{i-1}]) a_i
forall i
and b
s.t. f [] = b
, then scanl g b [a_0 .. a_n]
will yield [ f [], f [a_0], f [a_0,a_1], f [a_0, a_1, a_2] ..., f [a_0, a_1, ... a_n ] ]
. Such implementations are often more efficient, as they only need to do O(n)
work, rather than O(n^2)
. –
Summersummerhouse inits
for Data.Vector, which wouldn't be too hard to implement using init
. inits [ a_0, a_1 ... a_n ] = [ [], [a_0], [a_0, a_1], [a_0, a_1, a_2], ..., [a_0, a_1, ..., a_n] ]
, so you could do fmap f . inits
. –
Summersummerhouse © 2022 - 2024 — McMap. All rights reserved.
pattern x ::: xs <- (uncons -> Just (x, xs))
– Eboh