Сравнение паттернов Хаскелла по векторам

Можно ли использовать сопоставление шаблонов стиля списка на векторах?

т.е.

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, и тому подобное. Это зависит от того, что вы собираетесь делать.

Другие вопросы по тегам