2017-10-05 49 views
4

不知道这是否适合这个问题,但我有一个功能,我很确定它可以被简化,但我不知道如何。F#缩短树上的图案匹配

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 <= 1。甲probability tree具有类型

type ProbTree = | Branch of string * float * ProbTree * ProbTree 
       | Leaf of string 

什么是probability tree意思是表示顺序处理的样本空间,其中,在过程中的每个阶段的结果是成功或失败的树。

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

Probability tree

在我的例子,我正在处理的概率树是:

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 
+0

该函数似乎不适用于您的示例,因为您错过了分支包含2个分支的情况。 – TheQuickBrownFox

+0

是的。我发布了错误版本的功能,但我现在更新了该帖子。 – Khaine775

+0

仅供参考我在下面编辑了我的答案,完全不同。 – TheQuickBrownFox

回答

4

您可以简化通过作用于他们分离出树节点的遍历代码。下面是一个检查,如果一个节点是有效的函数:

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用于验证以外的目的。这限制了您在代码中使用递归所需的位置数量,并且应该让事情更容易推理。

+0

这是一个很好的建议。您如何看待EDIT1中的建议? – Khaine775