Haskell 什么';在函数式语言中,部分求值和函数内联有什么区别?
我知道:Haskell 什么';在函数式语言中,部分求值和函数内联有什么区别?,haskell,optimization,functional-programming,compiler-optimization,inlining,Haskell,Optimization,Functional Programming,Compiler Optimization,Inlining,我知道: 函数内联是用函数定义替换函数调用 部分求值是在编译时对程序的已知(静态)部分求值 在命令式语言(如C)中,运算符和函数是不同的,两者之间存在区别。然而,在Haskell这样的函数语言中,操作符也是函数,这两者之间有什么区别吗 这两者之间的唯一区别是,函数内联可以在程序的某些部分上执行,而部分计算可以在整个程序上执行(即∃vs∀) 这两种优化技术在语义上有什么区别?这两种技术之间有区别 在编译器(甚至预处理器)已知的一组给定运算符和函数上计算常量表达式,这在编译时发生。例如,编译器将p
∃代码>vs∀代码>)
这两种优化技术在语义上有什么区别?这两种技术之间有区别
- 在编译器(甚至预处理器)已知的一组给定运算符和函数上计算常量表达式,这在编译时发生。例如,编译器将
print(2*2)
编译为print(4)
。这决不需要像您所暗示的那样局限于运算符表达式(例如,print(sqrt(2.0)
)
- 部分求值,这是一个更广泛的概念。编译器可以意识到
print(myfunc(2))
可以转换为print(c)
,其中c
是调用myfunc(2)
的结果。然后它可以(在“专业化时间”)调用myfunc(2)
来确定c
。当然,如果myfunc
有副作用,比如擦自己的硬盘而不是程序用户的硬盘,那么这将出现严重错误。因此编译器需要某种注释或属性来知道何时允许/需要(例如c++11)
内联是一个不相关的概念。内联函数调用意味着用被调用函数的主体替换调用。此主体不进行计算
在C这样的命令式语言中,运算符和函数是不同的。然而,在Haskell这样的函数式语言中,运算符也是函数,两者之间有什么区别吗
这种区别(运算符与函数)纯粹是句法上的,与内联和部分求值之间的区别无关:
函数调用和带有运算符的表达式都可以内联,并在C中进行编译时计算。编译时计算仅限于一组固定的运算符和函数上的表达式(主要是运算符,但这是历史事故)
这两个概念都是有意义的,并且在Haskell中是不同的
- 内联:
ghc
具有{-#内联f#-}
,其中f
不能递归,原因很明显
- 部分求值:这通常推广到不仅转换基类型的表达式,甚至转换函数,例如将
map f(map g xs
)转换为map(f.g)xs
)。它也可以(但不需要)进行内联。是在编译时(明确地)评估程序部分的另一种方法
因此,您的标题问题的答案是:内联和部分求值之间的差异与函数和运算符之间的差异无关,在函数语言中与在C中几乎相同。由于副作用,部分求值在C中可能更困难(参见上面的擦除硬盘)考虑以下代码:
map f xs = case xs of [] -> []; (x:xs') -> f x : map f xs'
f x y = if x % 2 == 0 then y + x / 2 else y + x
main = map (f 3) [1..100]
部分评估后f3
:
f3 y = if 3 % 2 == 0 then y + 3 / 2 else y + 3
main = map f3 [1..100]
然后在不断折叠后3%2==0
:
f3 y = y + 3
main = map f3 [1..100]
main = map (\y -> y + 3) [1..100]
现在让我们考虑内联<代码> f>代码>:
注意:f3
中的f
不会内联,因为它不是一个完整的应用程序,但我们可以调整f
的定义以实现它,有关更多详细信息,请参阅
然后在不断折叠后3%2==0
:
f3 y = y + 3
main = map f3 [1..100]
main = map (\y -> y + 3) [1..100]
上面的例子表明,内联和部分评估都可以提供额外的优化机会,但它们仍然有很大的不同:
当特殊版本(f3
在上面的示例中)多次出现时,内联将产生大量重复的代码
当第一个参数不是静态常量时,部分求值仍然有效,但内联将不起作用
第二点,考虑下面的例子:
main = [f x y | x <- [1..10], y <- [1..100]]
main=[f x y | x从一点研究来看,在我看来,函数内联实际上只是在替换函数定义(模变量名)为了减少函数调用的开销并允许在调用站点进行更多优化,在其调用站点中没有执行任何评估。部分评估的一个示例是将60*1000
转换为60000
,或者找到一些可以简化为等效表达式的表达式但是更简单的一个。我不完全确定这个位置,所以我不打算把它作为一个答案发表,但这是我的解释。我应该在下面给出我的回答之前问这个问题:为什么你认为在一种运算符也是函数的语言中,内联和部分求值之间的区别会有任何不同?