[英]F#: Partial application and precalculation
查看今天我的代码中的函数,我想知道是否可以组合部分组合和优化:
let foo (X:float) y1 y2 dx =
y1 + (y2 - y1) * dx / X
基本上,只需应用一个比率 - 所以前三个参数在给定的循环中通常是相同的。
我想也许如果我这样做:
let foo2 (X:float) y1 y2 dx =
let dy = (y2 - y1) / X
y1 + dy * dx
当我部分应用前三个参数时,F#会变得聪明并为我优化,但是调试模式似乎并非如此(尽管我不确定我是否以正确的方式测试它)。
问题是,这应该有效吗? 如果不是有更好的方法(除了用两个参数编写另一个函数)?
我认为大多数这样的“魔术优化”都需要“效果分析”,这只能通过神话般的“足够聪明的编译器”完成。
考虑一下:
let Expensive x y =
printfn "I am a side-effect of Expensive"
x + y // imagine something expensive
let F x y z =
let tmp = Expensive x y
z + tmp
printfn "Least chance of magic compiler optimization"
for i in 1..3 do
F 3 4 i
printfn "Slightly better chance"
let Part = F 3 4
for i in 1..3 do
Part i
printfn "Now for real"
let F2 x y =
let tmp = Expensive x y
(fun z -> z + tmp)
printfn "Of course this still re-does it"
for i in 1..3 do
F2 3 4 i
printfn "Of course this finally saves re-do-ing Expensive"
let Opt = F2 3 4
for i in 1..3 do
Opt i
(* output
Least chance of magic compiler optimization
I am a side-effect of Expensive
I am a side-effect of Expensive
I am a side-effect of Expensive
Slightly better chance
I am a side-effect of Expensive
I am a side-effect of Expensive
I am a side-effect of Expensive
Now for real
Of course this still re-does it
I am a side-effect of Expensive
I am a side-effect of Expensive
I am a side-effect of Expensive
Of course this finally saves re-do-ing Expensive
I am a side-effect of Expensive
*)
关键是,关于效果的语言语义要求编译器的行为与此类似,除非“昂贵”没有效果,编译器真的非常聪明并且可以自己发现它。
(这不是声誉唠叨,当我开始问我的问题时,老实说我没有想到这一点)
这是我提出的一个解决方案,不确定它是否是最好的:
let foo3 (X:float) y1 y2 =
let dy = (y2 - y1) / X
(fun dx -> y1 + dy * dx)
工作得更快。
在调试模式下没有任何明显不同的东西我并不感到惊讶。 你为什么不实际重复N次( #time;;
在F#交互式提示下)。
至于你希望分享除dx之外的所有固定值的通用计算,试试这个:
let fdx = foo2 X y1 y2
for dx in dxes do
fdx dx
也就是说,fdx是部分应用程序。 在循环之外明确地存储它使我希望从优化器中获得更多。
至少在交互式提示中(我认为没有完全优化,是吗?)看起来我的建议只有15%的加速(奇怪的是有任何加速,因为它肯定会重复foo2的全部内容)。 这样做要快得多:
let fdx = foo3 X y1 y2
for dx in dxes do
fdx dx
其中foo3是(来自Benjlol):
let foo3 (X:float) y1 y2 =
let dy = (y2 - y1) / X
(fun dx -> y1 + dy * dx)
请注意,在循环中仅使用foo3作为4参数函数的速度是foo2的两倍,但将部分应用程序存储在循环外部,速度提高了3倍。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.