【问题标题】:How to match the rest of the list, no matter the length无论长度如何,如何匹配列表的其余部分
【发布时间】:2019-06-17 13:06:15
【问题描述】:

我想编写一个函数,它采用模式匹配的Strings 的list。例如,我检查关键字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"] 而不是更多条目。

我将如何实现这一目标?

【问题讨论】:

    标签: list haskell pattern-matching


    【解决方案1】:

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

    【讨论】:

    • 好的,再次非常感谢您!您会采用另一种方法而不是模式匹配吗?案例越多,我需要写的行就越多……有没有更好的方法?
    • @Biskit1943:但是这里有三种可能的结果,所以看起来这三个条款在这里是合理的。您可以抽象出长度比较,因此创建一个确定列表长度的函数,并使用参数返回"Too much""Too few"
    • 是的,但我的命令不止set,假设我还有三个,你还会用这个吗?
    • @Biskit1943:不,如前所述,您可以在单独的函数中将其抽象出来。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-12
    • 1970-01-01
    相关资源
    最近更新 更多