为什么GHC在内联时考虑LHS *的语法* [英] Why does GHC consider the LHS *syntactically* when inlining?
问题描述
根据GHC 文档:
... GHC只会在函数完全应用时内联函数,其中
完全应用表示应用于与出现的参数一样多的参数$
其中给出的例子是两个语义等价的定义: b $ b(语法上)在函数定义的LHS上。 p>
comp1 ::(b - > c) - > (a - > b) - > a - > c
{ - #INLINE comp1# - }
comp1 f g = \ x - > f(g x)
comp2 ::(b→c)→> (a - > b) - > a - > c
{ - #INLINE comp2# - }
comp2 fgx = f(gx)
我的问题:
-
是否只有在INLINE pragmas的存在下才能得到这个严格的
行为(即LHS的严格语法视图,RHS内联,不包括
优化)? 当没有给出INLINE pragmas时,GHC是否会转换函数 -
如果不是,为什么?一般来说,编译器在函数的语义中查找
并确定
部分应用和INLINE有多少以及在哪里是非常困难的? -
如果GHC只是将所有函数转换为
级联的let ...在
表达式中使用lambda表达式且在$ b上没有绑定,会发生什么情况$ b the LHS?
像
comp2
到 comp1
?
code> c 本身就是一个函数类型?我不清楚你的提案在这种情况下会如何解决。
在任何情况下,肯定有一些情况你不希望所有函数的参数拉到前面。例如,你可能有这样的代码:
foo :: [Int] - > Int - > Int - > Int
foo list = let
- 昂贵的预计算在这里
bar x y = ...
in \ x y - > bar xy
您需要 foo
获得部分应用,然后对结果函数的多个应用程序共享昂贵的预计算工作。相反,如果您将其作为 foo list x y
前移,您将无法分享昂贵的预计算。 (我在严重的应用程序中遇到过这种情况。)
According to the GHC docs:
...GHC will only inline the function if it is fully applied, where "fully applied" means applied to as many arguments as appear (syntactically) on the LHS of the function definition.
Where the example given is two semantically-equivalent definitions:
comp1 :: (b -> c) -> (a -> b) -> a -> c
{-# INLINE comp1 #-}
comp1 f g = \x -> f (g x)
comp2 :: (b -> c) -> (a -> b) -> a -> c
{-# INLINE comp2 #-}
comp2 f g x = f (g x)
My questions:
Is it only in the presence of INLINE pragmas that we get this strict behavior (i.e. strict syntactic view of LHS, RHS inlined w/out optimizations)?
when no INLINE pragmas are given, does GHC ever transform a function like
comp2
tocomp1
?if not, why? Is it too difficult in general for the compiler to look at the semantics of the function and decide how much and where to partially-apply and INLINE?
what would happen if GHC just transformed all functions into a cascade of
let... in
expressions with lambdas and no bindings on the LHS?
What if, in this example, c
is itself a function type? I'm not clear how your proposal would work out in that scenario.
In any event, there are definitely cases where you don't want all of a function's arguments "pulled to the front." For example, you might have some code like this:
foo :: [Int] -> Int -> Int -> Int
foo list = let
-- expensive precomputation here
bar x y = ...
in \ x y -> bar x y
You want foo
to get partially applied, and then for multiple applications of the resulting function to share the expensive precomputation work. If instead you pulled it forward as foo list x y
, you wouldn't get to share that expensive precomputation. (I've encountered this case in serious applications.)
这篇关于为什么GHC在内联时考虑LHS *的语法*的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!