F# - 虽然给出了元组条件的困境

时间:2008-10-02 08:29:48

标签: f#

鉴于以下内容:

#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”转换为序列表达式?

3 个答案:

答案 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的原因版本更具吸引力。