locked
what's the scope of range variable in foreach block? RRS feed

  • Question

  • In the example

       let pixel = new Range(10)
       let bools = Variable.Array<bool>(pixel);

       Variable.ForeachBlock pixel ( fun pixel ->
                    bools.[pixel] <- Variable.Bernoulli(0.7) ||| Variable.Bernoulli(0.4)())

    I don't understand the scope of pixel in the lambda function.

    Is it equivalent to this:

        let pixel = new Range(10)
        let bools = Variable.Array<bool>(pixel)

        let myFun (p: Range) =
            bools.[p] <- Variable.Bernoulli(0.7) ||| Variable.Bernoulli(0.4)
        
        Variable.ForeachBlock pixel myFun

    Or this:

        let pixel = new Range(10)
        let bools = Variable.Array<bool>(pixel)

        let myFun () =
            bools.[pixel] <- Variable.Bernoulli(0.7) ||| Variable.Bernoulli(0.4)
        
        Variable.ForeachBlock pixel (fun _ -> myFun ())



    • Edited by colinfang Wednesday, October 8, 2014 10:44 AM
    Wednesday, October 8, 2014 10:36 AM

Answers

  • Hi again,

    If you inline the code for ForeachBlock and the two function arguments (myFun() and (fun pixel -> ...))  they actually expand to the same code (because (fun pixel -> body) is applied to pixel). That's why they both work and produce the same result. 

    The Variable.ForEach(R) statement is opening a new block, the body of a loop, that is then closed by calling block.Dispose().

    The Infer.NET API is very imperative in that you open and close scopes and conditionals by using side-effecting calls to methods such as ForEach(r) and block.Dispose().

    It takes a little getting used to but once you've written the code to construct the model, you can discern the intended model by squinting at the code. 

    Hope that helps,

    Claudio

    • Marked as answer by colinfang Friday, October 10, 2014 5:49 PM
    Friday, October 10, 2014 3:08 PM

All replies

  • In general, it should be equivalent to the first variant.

    The scope of pixel in the lambda function is just the body of that function. This first declaration of pixel is shadowed (hidden) by the second.

    If it helps, this the definition of Variable.ForeachBlock:

        /// Apply the function body for each element in Range r
        let ForeachBlock (r:Range) (body:Range -> unit) =
            let block = Variable.ForEach(r)
            body r
            block.Dispose()

    Regards,

    Claudio

    Friday, October 10, 2014 8:55 AM
  • It is the fact that 2nd variant works too that confuses me.

    I cannot work out  what effect 'block' has brought in, in the F# language perspective.  (although I vaguely understand it somehow magically attach .foreach to all variables in the body r, I don't know how F# allows it to do so in this syntax.)

    Friday, October 10, 2014 10:03 AM
  • Hi again,

    If you inline the code for ForeachBlock and the two function arguments (myFun() and (fun pixel -> ...))  they actually expand to the same code (because (fun pixel -> body) is applied to pixel). That's why they both work and produce the same result. 

    The Variable.ForEach(R) statement is opening a new block, the body of a loop, that is then closed by calling block.Dispose().

    The Infer.NET API is very imperative in that you open and close scopes and conditionals by using side-effecting calls to methods such as ForEach(r) and block.Dispose().

    It takes a little getting used to but once you've written the code to construct the model, you can discern the intended model by squinting at the code. 

    Hope that helps,

    Claudio

    • Marked as answer by colinfang Friday, October 10, 2014 5:49 PM
    Friday, October 10, 2014 3:08 PM
  • Thank you.
    Friday, October 10, 2014 5:51 PM