在我的小程序中解析模式错误

Parse error in pattern in my little program

left :: [String]->[Char]->Char
left [] _ = []
left (x:xs) (head xs) = x    -- it says error at head

我使用了正确的括号,但仍然采用解析 error.By 的方式,我试图获取列表中的前一个元素,例如 [["A"],["B"],["C"],["D"],["E"]] 。也许我还有其他错误。请纠正我。

第二个问题是如何选取前一个元素的前一个索引字符。比如给函数这个列表 [["J","O","H","N"],["A","L","I","C","E"]] 和 "C" ,我希望得到 "H"。我的意思是 "C" 是第二个元素的第四个索引,而 "H" 是前一个元素的第三个索引。提前致谢

要访问 "previous" 列表元素,您必须使用不同的递归。例如

foo []  = baseCase
foo [x] = onlyOneElement x
foo (x1:x2:xs) = use x1 x2 (foo (x2:xs))

调用 foo [1,2,3,4,5] 时,您可以访问 x1=1, x2=2。递归时,您将获得 x1=2, x2=3 的访问权限,依此类推。因此,您可以认为 x2 是 "current" 元素,而 x1 是前一个元素。

如果我理解得很好,您需要一个函数来查找 String 列表中的字符,以及 return 前面索引处前面字符串的字符。

类似于:

f ["JOHN", "ALICE"] 'C' == 'H'

首先你需要知道 Char 字面量在 Haskell 中用单引号分隔('A'),而 String 字面量用双引号分隔("ABC").

由于在Haskell中String[Char]的别名,"ABC"等同于['A', 'B', 'C']

也就是说,在 Haskell 中你不能定义这样的函数:f a a = stuff。 GHC 会抱怨 a 被定义了多次。 所以要检查两个参数是否有一些 属性,你需要 guard patterns.

所以我会这样写你的第一个函数:

left :: [String] -> String -> String
left [] _ = ""
left [x] _ = ""
left (x1:x2:xs) str
    | x2 == str = x1
    | otherwise = left (x2:xs) str

关于你的第二个问题:

import Data.List

f :: [String] -> Char -> Maybe Char
f [] _ = Nothing
f [a] _ = Nothing
f (x1:x2:xs) c
    | Just i <- elemIndex c x2 = Just $ x1 !! (i-1)
    | otherwise = f (x2:xs) c

备注:

  • left 也应该 return 一个 Maybe String 以防 str 找不到或第一个出现。
  • f 不检查 x1 是否真的足够长
  • 通常在Haskell中,列表参数在最后,以允许currying

编辑:

使用 zip 的更聪明的方法(在模块 Data.List 中)。

f :: [String] -> Char -> Maybe Char
f [] _ = Nothing
f [_] _ = Nothing
f (x1:"":xs) c = f xs c
f (x1:x2:xs) c = f' (zip x1 (tail x2))
    where f' [] = f (x2:xs) c
          f' ((a,b):l) = if b == c then a else f' l

这个版本不会崩溃。它会return第一个满足"being mth character in nth string, while the (m+1)th character in (n+1)th string"的字符是c。结果将包装在 Maybe (Just 'H') 中。否则,它 returns NothingMaybe 大致是 Haskell 的可空类型)。

zip 是一个将两个列表合并成一对列表的函数:

zip ['a', 'b', 'c'] [1, 2] == [('a', 1), ('b', 2)]

结果列表的大小是最小的。所以在这个例子中,发生的是:

zip "JOHN" (tail "ALICE") == [('J','L'), ('O', 'I'), ('H', 'C'), ('N', 'E')]

然后您只需检查第二个字符是否是搜索到的字符,然后 return 这对字符中的第一个字符。