无论长度如何,如何匹配列表的其余部分

时间:2019-06-17 13:06:15

标签: list haskell pattern-matching

我想编写一个函数,该函数采用listString中的模式匹配。例如,我检查像这样的关键字set

parseArgs :: [String] -> Either String Command
parseArgs ["set", k, v] = Right $ Command k v
parseArgs ["set", _] = Left "To few arguments for set"
parseArgs ["set", _, _, _] = Left "To much arguments for set"

如您所见,我要匹配parseArgs ["set", "key", "value", ...]。 但是目前的方法只给我一个["set", "key", "value", "something"]的匹配项,而不是更多条目。

我将如何实现?

1 个答案:

答案 0 :(得分:2)

您可以使用“ cons ”列表构造:

parseArgs :: [String] -> Either String Command
parseArgs ["set", k, v] = Right $ Command k v
parseArgs ["set", _] = Left "To few arguments for set"
parseArgs ("set": _: _: _) = Left "To much arguments for set"

("set": _: _: _)("set": (_: (_: _)))的紧凑形式,因此我们在这里匹配一个非空的列表,并且尾部为非空,而尾部为非空,因此至少包含三个元素的列表。

实际上["set", _, _, _]只是("set": (_: (_: (_:[]))))语法糖。因此,通过使用通配符_而不是尾部的空白列表[],我们将其保持打开状态。

您忘记了一个人简单地通过["set"]的情况,我们也可以使用相同的技术:

parseArgs :: [String] -> Either String Command
parseArgs ["set", k, v] = Right $ Command k v
parseArgs ("set": _: _: _) = Left "To much arguments for set"
parseArgs ("set":_) = Left "To few arguments for set"

因此,这将匹配一个单例列表以及一个包含两个元素的列表,其中第一个元素每次是"set"

我们可以决定参数化长度检查,例如:

checkLength :: Int -> [a] -> Either String b
checkLength n _ | n < 0 = Left "Too much arguments"
checkLength n [] = Left "Too few arguments"
checkLength n (_:xs) = checkLength (n-1) xs

或更简单的drop

checkLength :: Int -> [a] -> Either String b
checkLength n = Left . foldr (const . const "Too much") "Too few" . drop n 

然后我们可以将其检查为:

parseArgs :: [String] -> Either String Command
parseArgs ["set", k, v] = Right $ Command k v
parseArgs ("set": xs) = checkLength 2 xs