不确定这是否是这个问题的正确位置,但我有一个函数,我很确定可以简化它,但我不确定如何简化。

let rec probOK = function
| Branch(ds, p, Leaf l1, Leaf l2) when p <= 1.0 && p >= 0.0     ->  true
| Branch(ds, p, b1, b2)           when p <= 1.0 && p >= 0.0     ->  probOK b1 && probOK b2
| Branch(ds, p , b1, Leaf l1)     when p <= 1.0 && p >= 0.0     ->  probOK b1
| Branch(ds, p , Leaf l2, b2)     when p <= 1.0 && p >= 0.0     ->  probOK b2
| _                                                             ->  false

任务是定义一个接受 probability tree 的函数(见下文)并检查它是否满足每个概率 p0 <= p <= 1probability tree 具有类型
type ProbTree = | Branch of string * float * ProbTree * ProbTree
                | Leaf of string
probability tree 的意思是表示顺序过程的样本空间的树,其中过程中每个阶段的结果要么成功要么失败。

一个 probability tree 的例子,其中掷出一个六面骰子,它是 >2 的概率是 2/3 ,它是 <= 2 的概率是 1/3 等等:

F# 缩短树上的模式匹配-LMLPHP

在我的示例中,我正在处理的概率树是:
let test = Branch(">2",0.67, Branch(">3",0.5, Leaf "A", Leaf "B")
                           , Branch(">3",0.5, Leaf "C", Leaf "D"))

这将返回 true,因为 p 的所有概率都在 0 和 1 之内。

现在,我定义的函数可以工作,但我觉得可以简化模式匹配,也许通过做一些类似于 ([],Leaf _ )-> true 的事情,但我不太明白。

任何提示?

EDIT1:一个缩短的建议(现在有更少的空格):
let rec probOK = function
| Branch(ds, p, b1, b2) when p <= 1.0 && p >= 0.0 ->  probOK b1 && probOK b2
| Leaf _                                          ->  true
| _                                               ->  false

最佳答案

您可以通过将树节点的遍历与对它们的操作分开来简化代码。这是一个检查节点是否有效的函数:

let nodeProbOk = function
| Branch(_, p, _, _)-> p <= 1.0 && p >= 0.0
| Leaf _ -> true

这是一个测试所有节点是否满足谓词的函数:
let rec forAllNodes pred = function
| Branch(_, _, a, b) as branch -> pred branch && forAllNodes pred a && forAllNodes pred b
| Leaf _ as leaf               -> pred leaf

这就是您将它们一起使用的方式:
test |> forAllNodes nodeProbOk

这种方法的优点是您有两个相对简单的函数,您可以将 forAllNodes 重用于验证以外的目的。这限制了您需要在代码中使用递归的位置数量,并且应该使事情更容易推理。

关于F# 缩短树上的模式匹配,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/46583228/

10-09 20:31