鉴于以下内容:
#light
//any function returning bool * 'a
let foo =
let x = ref 10
fun () ->
x := !x - 1
if !x <> 0 then
(true, x)
else
(false, x)
while let (c,x) = foo() in c do print_any x;//can't access x, but would be convinent.
//this is how I want it to work, without all the typing
let rec loop f =
match f() with
| (true, x) ->
print_any x
loop f
| (false, _) -> ()
loop foo
我该如何解决这个问题? 或者我应该通过麻烦将“foo”转换为序列表达式?
答案 0 :(得分:1)
这是一个解决方案,但我个人认为这是滥用时间构造。
#light
while
(let (c,x) = foo()
if c then print_any !x
c)
do ()
答案 1 :(得分:1)
另一种解决方案在我看来略好一些。它从while的条件子句范围中获取x,并将其放在更高范围内可用的引用y中。仍然不是最好的(功能性)解决方案,但它有效。
let y = ref 1
while (let (c,x) = foo()
y := !x
c)
do printf "%i" !y
我认为你的rec loop
解决方案效果最好,因为它是最具功能性的(避免副作用,尽管foo使用状态)和最常用的解决方案(它适用于与foo同时的所有功能)。它的输入时间更长,但是如果你将使用更多的函数,比如foo,那么循环比foo的单一最短解决方案更有效率。
我甚至会更多地概括循环,并在“真实”的情况下抽象出你想要做的事情的行为:
let loop f a =
let rec loop2() =
match f() with
| (true, x) ->
a x
loop2()
| (false, _) -> ()
loop2()
loop foo print_any
答案 2 :(得分:1)
我喜欢关于如何使用“foo”的其他建议,假设foo被固定。
我的鼻子,“foo”的代码闻起来。如果按照
的方式将“foo”转换为“bar”是合理的let bar =
let x = ref 10
seq {
x := !x - 1
while !x <> 0 do
yield x
x := !x - 1
}
bar |> Seq.iter print_any
然后我会这样做,但“酒吧”,虽然有点好,但仍然看起来很可疑。 (在“bar”中,我保留了奇怪的方面,它返回“int ref”而不仅仅是“int”,就像“foo”那样,但希望这方面是无意的?)
我认为关于“foo”的那种时髦的东西是那种从数据类型中不明显的隐含信息(只要bool部分为真,你就可以继续调用它),这就是seq的原因版本更具吸引力。