鉴于以下内容:

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

有帮助吗?

解决方案

这是一个解决方案,但我个人认为这是滥用时间构造。

#light
while 
   (let (c,x) = foo()
    if c then print_any !x
    c)
   do ()

其他提示

另一种解决方案在我看来略好一些。它从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

我喜欢关于如何消费“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”中,我保留了奇怪的方面,它返回“int ref”而不仅仅是“int”,如“foo”那样,但希望这方面是无意的?)

我觉得关于“foo”的东西太酷了。是一种隐含的信息,从数据类型来看并不明显(只要bool部分为真,你就可以继续调用它),这就是使seq版本更有吸引力的原因。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top