2

I have a console app that has an example function:

let aFxUsedFromTheEntryPoint () = 
    let aHelperFx (cThing) (iThing) (qThing) = 
        Unchecked.defaultof<Quote>

    let c = 
        thisFx() //this line reads in and process lots of data; takes some time

    let i = 
        thatFx() //this line also reads in and processes lots of data; takes some time

    aList
    |> List.map (fun q -> aHelperFx c i q)

How are the c and i variables used in the function? Are they read in once before last two lines and just used repeatedly, for however long aList is? Or are they executed once for every q in `aList'?

If the latter, is there a better way to go about writing a function like this? Can I somehow write the function so that c and i are run only once, yet passed however many times it's necessary in aList?

Steven
  • 3,238
  • 21
  • 50
  • 1
    This is maybe the most common F# beginner question; see answer [here](http://stackoverflow.com/questions/41049285/when-are-f-function-calls-evaluated-lazily-or-immediately/41049323#41049323). – TeaDrivenDev Jan 30 '17 at 22:13
  • 3
    Why are people downvoting perfectly valid questions again without even saying why? – TeaDrivenDev Jan 30 '17 at 22:37
  • My guess is that their argument is that I should have used the search box. Although, it hadn't even occurred to me that F# is *eagerly* evaluated, unless otherwise specified (or, on `Sequence`), thus `c` and `i` should be into memory read in once and then used repeatedly. This means that somewhere else in my actual function do I need to look in order to save time. Thanks for the link @TeaDrivenDev. – Steven Jan 30 '17 at 22:40
  • What are `c` and `i`? If they are collections you can certainly cache them via [`Seq.cache`](https://msdn.microsoft.com/en-us/visualfsharpdocs/conceptual/seq.cache%5B't%5D-function-%5Bfsharp%5D) – s952163 Jan 30 '17 at 23:25
  • `c` and `i` are functions. – Steven Jan 30 '17 at 23:30
  • `thisFx()` is a function. I would expect `c` to be the bound result from the function. You can also use[`lazy`](https://learn.microsoft.com/en-us/dotnet/articles/fsharp/language-reference/lazy-computations) that is referred to in the above link by TDD, and `.Force` it once. For example if `q` were an actual parameter to these functions I would understand but they are parameterless (take unit). So what is the output of running `thisFx()`? – s952163 Jan 30 '17 at 23:45
  • 1
    The output of running `thisFx()` is another function. `thisFx()` reads in other files that then take parameters from down-stream functions. Initially, I bound `thisFx()` and `thatFx()` to variables so that I could call them repeatedly, thinking that with the initial `let c = thisFx()` statement, they'd be read in once. – Steven Jan 31 '17 at 00:18
  • Seems like partially applied functions? what if you wrap it in lazy? – s952163 Jan 31 '17 at 00:41

2 Answers2

2

The most obvious solution is to move them out of the function body:

let c = thisFx() //this line reads in and process lots of data; takes some time
let i = thatFx() //this line also reads in and processes lots of data; takes some time

let aFxUsedFromTheEntryPoint () = 
    let aHelperFx (cThing) (iThing) (qThing) = Unchecked.defaultof<Quote>
    aList |> List.map (fun q -> aHelperFx c i q)

Typically if your function is declared inside a module, then those two let bindings can be declared at the same level as the function, in this case at the module level.

This is the first thing I will consider. Now if you want them to be called the first time the aFxUsedFromTheEntryPoint function is called then you can use other techniques like memoization or the lazy value as explained in the other answer, but note that the first call to the function will be slower than the subsequent calls.

Gus
  • 25,839
  • 2
  • 51
  • 76
0

Maybe wrapping it into lazy will help?

let x4 = lazy (
            printfn "%A" "Long Running stuff"
            let addX (x:int) = x + 1   
            addX)
//val x4 : Lazy<(int -> int)> = Value is not created.
let c = x4.Force() 4
//"Long Running stuff"
//val c : int = 5
c // val it : int = 5
c
s952163
  • 6,276
  • 4
  • 23
  • 47