我制作了一个数据结构来表示房屋迷宫。它的工作方式是,一条路径可能导致存在蛋糕,冰淇淋或烤箱的死角,或者可能导致左,右,双(左和右路径)或三重(左,中和右路径)。
这是房屋的类型和布局
type path =
|End of string
|Double of path * path
|Triple of path * path * path
|Left of path
|Right of path
let GingerbreadHouse = Triple(
Double( Double(End("*"), End("X")), Left(Right(End("X"))) ),
Left( Double(End("*") , Left( Double(End("X") , Right(End("O")))))) ,
Left( Triple(Right(End("X")) , Double( Double(End("*") , End("X")) , End("X")) , Double(End("X") , Right(End("*"))) ))
)
现在我要做的是计算到达烤箱之前先到达最右边的路径的蛋糕数量。
我首先尝试使用一个简单的辅助功能来完成此操作,该功能可以跟踪计数,当到达烤箱时,它将重新运行计数。但是我碰壁了,因为我无法以这种方式准确地返回死角。
let YummyKids house =
let rec helper house count =
match t with
|Left(p) -> helper p count
|Right(p) -> helper p
|Double(lp,rp) -> helper count + helper count
|Triple(lp, fp, rp) -> helper rp count + helper mp count + helper lp count
|End(treat) when treat = "*" -> helper ??? count
|End(treat) when treat = "X" -> helper ??? (count+1)
|End(treat) when treat = "O" -> count
helper house 0
所以我的第二次尝试是我会坚持使用普通的向后递归方法,但是我碰到了另一堵墙,因为我不知道如何在到达烤箱后真正结束整个过程。
let YummyKids house =
match t with
|Left(p) -> YummyKids p
|Right(p) -> YummyKids p
|Double(lp,rp) -> YummyKids rp + YummyKids lp
|Triple(lp, fp, rp) -> YummyKids rp + YummyKids mp + YummyKids lp
|End(treat) when treat = "*" -> 0
|End(treat) when treat = "X" -> 1
|End(treat) when treat = "O" -> //???
如果要计算整个迷宫中的蛋糕数量,这会起作用,但是我只想计数直到某个点,直到它到达烤箱。我该怎么办?
答案 0 :(得分:4)
您的递归函数的结果需要指出到目前为止您发现了多少个蛋糕,还需要指出该过程是否已经到达烤箱,因此应该终止。
然后,您可以实施分支,以便在尚未找到烤箱的情况下继续到其他分支(加上蛋糕数),但是当在一个分支中找到烤箱时立即返回-在查看另一分支之前分支。
在下面,返回类型为int * bool
,其中int
代表蛋糕的数量,bool
为true
。有趣的情况是Double
的处理:
let rec YummyKids path =
match path with
| Left(p) -> YummyKids p
| Right(p) -> YummyKids p
| Double(lp,rp) ->
let cakes, finished = YummyKids rp
if finished then cakes, finished else
let moreCakes, finished = YummyKids lp
cakes + moreCakes, finished
| End(treat) when treat = "*" -> 0, false
| End(treat) when treat = "X" -> 1, false
| End(treat) when treat = "O" -> 0, true
在Double
中,我们首先查看右边的分支,如果找到烤箱,则返回到目前为止的蛋糕数。如果为finished = false
,我们将查看右侧分支并添加蛋糕。
我没有执行Triple
情况,但是您应该能够按照与Double
情况相同的模式很容易地完成该工作。
答案 1 :(得分:3)
Tomas已回答您的问题。我只想指出一些可能的优化方法:
let func arg = match arg with...
上的匹配项可以替换为模式匹配函数let func = function...
"X"
,"O"
,true
,从而可以避免使用关键字when
的保护模式匹配规则Triple
案例可以由两个Double
案例构成_
因此我们也可能会得出以下结论:
let rec YummyKids = function
| Double(lp,rp) ->
match YummyKids rp with
| _, true as result -> result
| cakes, _ ->
let moreCakes, finished = YummyKids lp
cakes + moreCakes, finished
| Triple(lp,mp,rp) -> YummyKids (Double(Double(rp,mp),lp))
| Left p | Right p -> YummyKids p
| End "X" -> 1, false
| End "O" -> 0, true
| End _ -> 0, false