我们使用(x:xs)
在第一个元素上进行模式匹配,如本例所示:
head' :: [a] -> a
head' xs = case xs of [] -> error "No head for empty lists!"
(x:_) -> x
有没有办法在最后一个元素上进行图案匹配?
答案 0 :(得分:6)
否,因为没有匹配的[a] -> a -> [a]
类型的构造函数。
您可以使用[]
和:
进行模式匹配,因为根据定义,它们是列表值的基础。 []
是创建空列表的 方法。 :
是从一个元素和另一个列表构建新列表的 方法。像append
这样的函数不会自行创建新列表;它们返回由:
和/或[]
创建的列表。
例外情况是,如果您碰巧事先知道列表的长度,则可以通过显式匹配元素的 all 来匹配最后一个元素。
lastOfFour :: [a] -> a
lastOfFour (_:_:_:x:[]) = x
lastOfFour (_:_:_:_:_) = error "Too many elements"
lastOfFour _ = error "Too few elements"
如果您可以匹配至少4个元素,则将触发第一条错误消息,而其余列表为 not 为空;第二个是与前两个之一不匹配的任何列表。
答案 1 :(得分:5)
要获取列表的最后一个元素,您需要遍历整个列表。
如果需要在最后一个元素上进行匹配,则可能需要一个类似列表的数据结构,该结构使这种匹配高效且易于使用,例如Sequence(两端为O(1)):
{-# LANGUAGE OverloadedLists #-}
import Data.Sequence
last' :: Seq a -> a
last' Empty = error "Empty sequence"
last' (_:|>a) = a
test = last' [1..5]
答案 2 :(得分:3)
如果确实需要,您可以在GHC中为此定义一个pattern synonym。当然,它仍然是 O ( n )。
<DataTemplate x:Key=“MyViewmodelType”>
<MyViewControl />
</DataTemplate>
({-# LANGUAGE PatternSynonyms, ViewPatterns #-}
unsnoc :: [a] -> Maybe ([a], a)
unsnoc [] = Nothing
unsnoc xs = Just (init xs, last xs)
{-# COMPLETE [], (:>) #-}
infixl 5 :>
pattern (:>) :: [a] -> a -> [a]
pattern xs :> x <- (unsnoc -> Just (xs, x))
where xs :> x = xs ++ [x]
-- example:
last' :: [a] -> a
last' [] = error "last': empty list"
last' (_ :> x) = x
也在Data.List.Extra
中。)
答案 3 :(得分:1)
您不能直接在最后一个元素上进行匹配,因为模式匹配仅根据类型的具体构造函数来解构事物,并且列表仅包含两个构造函数:[]
和(:)
。
但是,您可以反转列表,然后在反转列表的开头进行匹配:
last' xs = case reverse xs of
[] -> error "last' []"
x : _ -> x
使用ViewPatterns
,您可以直接在模式中进行逆转:
{-# LANGUAGE ViewPatterns #-}
last' (reverse -> xs) = case xs of
[] -> error "last' []"
x : _ -> x
或者使用PatternGuards
,您可以在守卫中进行逆转:
{-# LANGUAGE PatternGuards #-}
last' xs
| x : _ <- reverse xs = x
| otherwise = error "last' []"
最后,您可以使用PatternSynonyms
将其打包为一个名称:
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE ViewPatterns #-}
pattern Reversed xs x <- (reverse -> x : xs)
-- This part is optional, but allows writing:
--
-- Reversed [3, 2, 1] 0
--
-- As a synonym for:
--
-- [0, 1, 2, 3]
--
where Reversed xs x = x : reverse xs
last' (Reversed _ x) = x
last' _ = error "last' []"
所有这些解决方案在列表长度上都是O( n )(线性),这是不可避免的。因此,您最好使遍历尽可能明确,而不是隐藏线性成本并无意间遍历列表,而不是使用预期的遍历,或者对最后一个元素使用O(1)(恒定)索引的不同数据结构,例如Seq
或Vector
。
答案 4 :(得分:1)
如果您拥有GHC 6.10或更高版本,请使用view pattern。
视图模式允许在模式内部调用view函数,并且 与结果匹配:
size (view -> Unit) = 1 size (view -> Arrow t1 t2) = size t1 + size t2
也就是说,我们添加了一种新的模式,即书面形式
expression -> pattern
表示“将表达式应用于我们尝试匹配的任何内容 反对,然后将该申请的结果与 该表达式可以是任何Haskell函数表达式 类型,并且无论当前使用哪种模式,都可以使用视图模式 使用。
将head'
定义为
{-# LANGUAGE ViewPatterns #-}
head' :: [a] -> a
head' (last -> l) = l
它可以按预期工作。
λ> head' [3,5,7]
7
λ> head' []
*** Exception: Prelude.last: empty list
答案 5 :(得分:-2)
chepner指出,没有内置的方法可以做到这一点,但是编写自己的也不难:
foo :: [Maybe a] -> a
foo [] = error "empty list"
foo xs =
case last xs
(Just a) -> a
Nothing -> error "last element is a Nothing!"
另一种方法是reverse
列表,然后在第一个元素上进行模式匹配!