Вы можете использовать конструкцию списка " cons ":
parseArgs :: [String] -> Either String Command
parseArgs ["set", k, v] = Right $ Command k v
parseArgs ["set", _] = Left "To few arguments for set"
parseArgs <b>("set": _: _: _)</b> = 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 <b>("set":_)</b> = 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