Haskell 中的叶树 - 非详尽模式

Leaf Trees in Haskell - non-exhaustive pattern

此函数遵循布尔路径,分别根据 False 或 True 向左或向右移动

data LTree a = Leaf a 
             | Fork (LTree a) (LTree a)
             deriving (Show)

select :: LTree a -> [Bool] -> (Maybe a)
select (Fork (Leaf a) (Leaf b)) (l:ls)  = if l==False  then Just a 
                                                       else Just b
select (Fork l r) (b:bs) = if b==False  then select l bs
                                        else select r bs

问题是,LTree 没有声明 Empty 值,我怎么知道它是我的函数落入的节点或分支?

好的,

这很简单,我想我需要休息一下:

缺少这个:

select (Fork l r) [] = Nothing

询问编译器

GHC 可以在编译时就非详尽模式向您发出警告,而不是等待 运行 时间来发现它们。如果我把你的代码放到一个文件中并用 -fwarn-incomplete-patterns flag

编译它
ghc -fwarn-incomplete-patterns nonExhaustiveLeafTree.hs

它产生以下错误信息:

    Pattern match(es) are non-exhaustive
    In an equation for `select':
        Patterns not matched:
            (Leaf _) _
            (Fork (Fork _ _) _) []
            (Fork (Leaf _) (Fork _ _)) []
            (Fork (Leaf _) (Leaf _)) []

在添加 以覆盖 [] 之后,它仍然会针对任何树是 Leaf _

的地方发出警告
    Pattern match(es) are non-exhaustive
    In an equation for `select': Patterns not matched: (Leaf _) _

包罗万象

如果我们分别处理 LeafFork,我们可以很容易地涵盖所有模式。这也删除了当 Fork 的直接后代为叶子时决定以何种方式继续执行的重复代码。

到了Leaf就知道有结果了,无路可走

select (Leaf a) [] = Just a

当你到达 Leaf 并且还有一条路你需要走时,你需要决定要做什么。

select (Leaf a) (l:ls) = ????

就像您在回答中提到的那样,当没有剩余路径并且您处于 Fork.

时,您会知道没有结果
select (Fork _ _) [] = Nothing

您可以简化存在分叉和单个规则路径时发生的情况。

select (Fork l r) (b:bs) = if b
                           then select r bs
                           else select l bs