Question

Given the following:

#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

How should I go about solving this? Or should I just go through the hassle to convert "foo" to a sequence expression?

Was it helpful?

Solution

This is one solution, but I personally think it is abuse of the while construction.

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

OTHER TIPS

Another solution which is slightly better in my opinion. It gets x out of the condition clause scope of the while and puts it in a reference y which is available in the higher scope. Still not the best (functional) solution but it works.

let y = ref 1
while (let (c,x) = foo()
       y := !x
       c)
       do printf "%i" !y

I think your rec loop solution works best since it is the most functional one (avoiding side effects, although foo uses state) and the most general one (it works on all functions of the same time as foo). It is longer typing, but if you will use more functions like foo, loop is more productive than the single one shortest solution just for foo.

I would even generalize loop some more and abstract away the action of what you want to do with a value in a 'true' situation:

let loop f a = 
   let rec loop2() = 
      match f() with
      | (true, x) ->
         a x
         loop2()
      | (false, _) -> ()
   loop2()

loop foo print_any

I like the other suggestions for how to consume "foo" assuming foo is held fixed.

To my nose, the code for "foo" smells. If it's reasonable to convert "foo" to "bar" along the lines of

let bar =    
    let x = ref 10    
    seq {
        x := !x - 1        
        while !x <> 0 do
            yield x
            x := !x - 1        
    }
bar |> Seq.iter print_any

then I would do it, but "bar", while somewhat better, still seems fishy. (In "bar", I preserved the odd aspect that it returns "int ref" rather than just "int", as "foo" did, but hopefully that aspect was unintentional?)

I think the thing that is so funky about "foo" is the kind of implicit information that's not obvious from the data type (you can keep calling this so long as the bool portion is true), which is what makes the seq version a little more attractive.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top