我想编写一个函数,该函数采用list
个String
中的模式匹配。例如,我检查像这样的关键字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"]
的匹配项,而不是更多条目。
我将如何实现?
答案 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