2017-01-30 212 views
2

阅读我有了一个例子功能的控制台应用程序行:功能与在其他数据文件

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) 

如何在函数中使用的ci变量?他们在最后两行之前是否只读过一次,并且只是反复使用,然而长aList是?或者他们在'aList'中每q执行一次?

如果是后者,有没有更好的方法去编写这样的函数?我可以以某种方式编写函数,使ci只运行一次,但通过了很多次,但必须在aList

+1

这也许是最常见的F#初学者问题;看到答案[这里](http://stackoverflow.com/questions/41049285/when-are-f-function-calls-evaluated-lazily-or-immediately/41049323#41049323)。 – TeaDrivenDev

+3

为什么人们再次低估完全有效的问题,甚至不说为什么? – TeaDrivenDev

+0

我的猜测是他们的论点是我应该使用搜索框。虽然,我甚至没有想到F#会被急切地评估,除非另有说明(或者在'Sequence'上),因此'c'和'i'应该一次读入内存,然后重复使用。这意味着为了节省时间,我需要查看实际功能中的其他位置。感谢链接@TeaDrivenDev。 – Steven

回答

2

最明显的解决方案是将它们移出函数体:

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) 

通常,如果你的功能的模块内声明的,那么这两个let绑定可以在同一级别上声明作为功​​能,在这种情况下在模块层面。

这是我会考虑的第一件事。现在,如果您希望在第一次调用aFxUsedFromTheEntryPoint函数时调用它们,那么您可以使用其他技术,如memoization或惰性值,如其他答案中所述,但请注意,第一次调用该函数将比后续更慢调用。

1

也许包装成lazy会有帮助吗?

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