列表的第一个和最后一个项目的模式匹配

时间:2015-02-16 04:38:40

标签: haskell

是否可以在“以f开头”,然后是任何文字,以“以b结尾?”模式匹配?

我试过了:

f :: String -> Bool
f ('f':xs:'b') = True
f _            = False

但我收到了一个错误:

explore/PatternMatching.hs:2:11:
    Couldn't match expected type ‘[Char]’ with actual type ‘Char’
    In the pattern: 'b'
    In the pattern: xs : 'b'
    In the pattern: 'f' : xs : 'b'
Failed, modules loaded: none.

6 个答案:

答案 0 :(得分:7)

没有模式匹配语言扩展,没有简单的方法可以做到这一点。我会把它写成:

f :: String -> Bool
f str = case (take 1 str, drop (length str - 1) str) of
    ("f", "b") -> True
    otherwise -> False

(使用takedrop以避免在使用例如head!!时特别处理可能导致错误的空字符串的情况

Prelude> f "flub"
True
Prelude> f "foo"
False
Prelude> f "fb"
True
Prelude> f "fbbbb"
True
Prelude> f "fbbbbf"
False
Prelude> f ""
False

答案 1 :(得分:2)

正如先前的答案所述,没有办法直接为此进行模式匹配。人们可以按如下方式实现它:

f 'f':xs@(_:_) = last xs == 'b'  -- @(_:_) ensures nonempty tail
f _            = False

答案 2 :(得分:1)

不,不可能直接。

:想要左侧的列表元素和右侧的列表。

'f':xs:'b'无效,因为第二个:右侧的内容不是列表。

'f':xs:"b"有效,但不会做你想做的事,因为xs被推断为列表元素,而不是列表。

我会这样做:

f s = f' (s, reverse s) where
   f' ('f':_, 'b':_) = True
   f' _              = False

测试:

*Main> f ""
False
*Main> f "f"
False
*Main> f "b"
False
*Main> f "fb"
True
*Main> f "feeeeeeeb"
True
*Main> f (repeat 'b')
False
*Main> f (repeat 'f')
(hangs indefinitely)

答案 3 :(得分:1)

对于类似列表的数据结构,允许您在常量时间中访问其第一个和最后一个元素,您可能需要查看Hinze和Paterson的指尖。

它们由例如containershere are the relevant views解构它们。如果您经常使用这种模式,您可能想要编写自己的视图,将左侧和右侧的解构结合起来:

data ViewLR a = EmptyLR | SingleLR a | BothSides a (Seq a) a

viewlr :: Seq a -> ViewLR a
viewlr seq =
  case viewl seq of
    EmptyL     -> EmptyLR
    hd :< rest ->
      case viewr rest of
        EmptyR       -> SingleLR hd
        middle :> tl -> BothSides hd middle tl

您可能还希望阅读View Patterns,以便能够在左侧“模式匹配”,而不必使用case ... of

答案 4 :(得分:0)

定义专用的String数据类型,从而形成模式匹配,例如考虑

data HString = Ends Char Char | Plain String 
  deriving (Show, Eq)

因此

f :: HString -> Bool
f (Ends h l) = (h,l) == ('f','b')
f (Plain "") = False
f (Plain xs) = f $ Ends (head xs) (last xs)

等等

*Main> f (Plain "")
False
*Main> f (Plain "fabs")
False
*Main> f (Plain "fab")
True

<强>更新

同样,考虑使用中缀运算符:-:来表示构造函数,例如

infixr 5 :-:

data HString = Char :-: Char | Plain String 
  deriving (Show, Eq)

因此

f :: HString -> Bool
f (h :-: l)  = (h,l) == ('f','b')
f (Plain "") = False
f (Plain xs) = f $ (head xs) :-: (last xs)

答案 5 :(得分:0)

要了解错误,只需检查签名:operator

Prelude> :t (:)
(:) :: a -> [a] -> [a]

它可以接受一个元素和一个列表来给出附加列表。当你提供'f':xs:'b'时,它与函数调用不匹配。