为什么 haskell 需要多个重写规则,具体取决于函数组合技术和长度?有没有办法避免这种情况?
例如,给定以下代码...
{-# RULES
"f/f" forall a. f ( f a ) = 4*a
#-}
f a = 2 * a
这适用于
test1 = f ( f 1 )
但是我们需要为
test2 = f . f $ 1
和
test3 = f $ f 1
给我们留下以下规则
{-# RULES
"f/f1" forall a. f ( f a ) = 4 * a
"f/f2" forall a. f . f $ a = 4 * a
"f/f3" forall a. f $ f $ a = 4 * a
#-}
但是,当我们将它们串在一起或使用其他形式的组合时,规则不会触发。
test4 = f . f . f $ 1
test5 = f $ f $ f $ 1
test6 = f $ 1
为什么是这样?我是否必须为每个可能的实现编写重写规则?
最佳答案
在许多情况下,该规则不会触发,因为非常简单的函数 f
在规则有机会触发之前内联。如果你延迟内联,
{-# INLINE [1] f #-}
规则
{-# RULES "f/f" forall a. f (f a) = 4*a #-}
应该针对所有这些情况触发(在此处使用 7.2.2 和 7.4.1)。
原因是规则匹配器并不过分复杂,它只匹配具有规则语法形式的表达式(不完全正确,规则体也经过了一些规范化)。表达式
f $ f 3
或 f . f $ 4
不匹配规则的句法形式。为了匹配规则,必须进行一些重写,($)
和 (.)
必须在规则匹配表达式之前内联。但是如果你不阻止f
从在简化器的第一阶段内联,它在与 ($)
相同的运行中被其主体替换和 (.)
是内联的,所以在下一次迭代中,简化器看不到 f
不再,它只看到 2*(2*x)
,不符合规则。
关于Haskell 重写规则和函数组合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9253650/