F#-在给定元组条件的困境中
时间:2020-03-06 15:00:54 来源:igfitidea点击:
给定以下内容:
#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"转换为序列表达式?
解决方案
这是一种解决方案,但我个人认为这是对while构造的滥用。
#light
while
(let (c,x) = foo()
if c then print_any !x
c)
do ()
我认为另一种解决方案稍微好一点。它使x脱离while的条件子句范围,并将其放入引用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
我喜欢其他假设,假设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"虽然好一点,但看起来仍然很脏。 (在" bar"中,我保留了一个奇怪的方面,即它像" foo"一样返回" int ref"而不是" int",但希望该方面不是故意的吗?)
我认为关于" foo"的事情很奇怪,是隐式信息,这种隐式信息在数据类型中并不明显(只要布尔部分为真,就可以继续调用它),这使seq版本有点更具吸引力。

