您可以使用“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