是否可以在矢量上使用列表样式模式匹配?
即
import qualified Data.Vector as V
f :: V.Vector a -> a
f (x:xs) = x
给出错误
答案 0 :(得分:7)
-XViewPatterns
可以让你这样做:
{-# 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
或-XLambdaCase
import Control.Category ((>>>))
-- ...
vsum :: Num a => Vector a -> a
vsum = uncons >>> \case
Just (a,av) -> a + vsum av
Nothing -> 0
但老实说,当你使用一种数据结构(Vector
)作为另一种数据结构([]
)时,这似乎有点像代码味道,这表明你可能选择的数据结构是关闭的
如果您真的只想将其视为某些算法的列表,为什么不使用toList
?
答案 1 :(得分:1)
向量并不适用于那种模式匹配 - 它们是为了给Haskell O(1)列表或可以从任何点有效访问的列表而创建的。
与你所写的最接近的是这样的事情:
f v = V.head v
或者,如果您正在寻找递归,tail
函数将获得列表的其余部分。
但是如果你试图做一些沿着这样的列表移动的东西,那么就有像foldl
,find
,map
等函数的Vector等价物。这取决于你打算做什么。
答案 2 :(得分:1)
@Cactus指出-XPatternSynonym
(在7.8中引入)与-XViewPattern
结合可以用于对向量进行模式匹配。我在这里进一步扩大他的评论。
pattern Empty <- (V.null -> True)
上面为空向量定义了模式同义词Empty
。 Empty
模式使用视图模式(V.null -> True
)与空向量匹配。但是,它不能在其他地方用作表达式,即 uni 方向的同义词,因为系统实际上不知道Empty
作为向量是什么(我们只知道{{ 1}}是null v
,但也可能有其他向量也提供True
。
为解决这个问题,可以添加一个True
子句,以指定Empty实际上是一个空向量,即 bi 方向的同义词以及类型签名:
where
此模式同义词可用于定义pattern Empty :: Vector a
pattern Empty <- (V.null -> True) where Empty = V.empty
而不使用if表达式:
uncons
我们使用uncons :: Vector a -> Maybe (a, Vector a)
uncons Empty = Nothing
uncons v = Just (unsafeHead v, unsafeTail v)
来定义单向同义词。请注意,由于uncons
对于矢量而言代价高昂,因此我不会将其设为双向:
cons
无论如何,我们终于能够像列表一样对向量进行模式匹配:
pattern (:<|) :: a -> Vector a -> Vector a
pattern x :<| xs <- (uncons -> Just (x, xs))
完整的代码是here。