在列表的最后一个元素上进行模式匹配

时间:2019-02-05 17:29:22

标签: haskell pattern-matching

我们使用(x:xs)在第一个元素上进行模式匹配,如本例所示:

head' :: [a] -> a  
head' xs = case xs of [] -> error "No head for empty lists!"  
                      (x:_) -> x  

有没有办法在最后一个元素上进行图案匹配?

6 个答案:

答案 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)(恒定)索引的不同数据结构,例如SeqVector

答案 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列表,然后在第一个元素上进行模式匹配!