Сравнение паттернов Хаскелла по векторам
Можно ли использовать сопоставление шаблонов стиля списка на векторах?
т.е.
import qualified Data.Vector as V
f :: V.Vector a -> a
f (x:xs) = x
выдает ошибку
2 ответа
-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
?
@Cactus указал -XPatternSynonym
(введено в 7.8) в сочетании с -XViewPattern
может использоваться для сопоставления с образцом на векторах. Я здесь, чтобы расширить его комментарий немного дальше.
pattern Empty <- (V.null -> True)
Вышесказанное определяет синоним шаблона Empty
для пустого вектора. Empty
сопоставление с пустым вектором с использованием шаблона представления (V.null -> True
). Однако его нельзя использовать в качестве выражения в другом месте, т. Е. Однонаправленного синонима, поскольку система на самом деле не знает, что Empty
как вектор (мы только знаем, что null v
является True
но могут быть и другие векторы, дающие True
также).
Чтобы исправить это, where
может быть добавлено предложение, указывающее, что Empty на самом деле является пустым вектором, то есть двунаправленным синонимом, а также сигнатурой типа:
pattern Empty :: Vector a
pattern Empty <- (V.null -> True) where Empty = V.empty
Этот синоним шаблона может быть использован для определения uncons
без выражения if:
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))
В любом случае, мы наконец-то можем сопоставить шаблоны для векторов, как списки:
vsum :: Num a => Vector a -> a
vsum Empty = 0
vsum (x :<| xs) = x + vsum xs
Полный код здесь.
Векторы не предназначены для такого типа сопоставления с образцом - они были созданы для предоставления списков Haskell O(1) или списков, к которым можно эффективно обращаться из любой точки.
Самое близкое к тому, что вы написали, было бы примерно так:
f v = V.head v
Или, если вы ищете рекурсию, tail
Функция получит остальную часть списка.
Но если вы пытаетесь сделать что-то, что движется по списку, то есть векторные эквиваленты функций, таких как foldl
, find
, map
, и тому подобное. Это зависит от того, что вы собираетесь делать.