【问题标题】:Haskell Rewrite Rules and Function CompositionHaskell 重写规则和函数组合
【发布时间】:2012-03-04 10:47:03
【问题描述】:

为什么 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

这是为什么?我是否必须为每个可能的实现编写重写规则?

【问题讨论】:

  • 我实际上不知道,但我猜这是因为重写规则不适用于您导入的函数。而$. 只是从 Prelude 导入的函数。

标签: haskell rules ghc function-composition


【解决方案1】:

我原以为默认情况下这会起作用,但是您可以再添加两个重写规则以使 ./$ 简化为 lambdas/application,这样它就会始终匹配:

{-# RULES
"f/f" forall a. f ( f a ) = 4*a

"app" forall f x. f $ x = f x
"comp" forall f g. f . g = (\x -> f (g x))
  #-}

f a = 3 * a -- make this 3*a so can see the difference

测试:

main = do
    print (f . f $ 1)
    print (f (f 1))
    print (f $ f 1)
    print (f $ f $ 1)
    print (f $ f $ f $ f $ 1)
    print (f . f . f . f $ 1)
    print (f $ f $ f $ 1)
    print (f . f . f $ 1)
    print (f $ 1)

输出:

4
4
4
4
16
16
12
12
3

由于其他重写规则,这也适用于一些(但不是全部)更晦涩的情况。例如,所有这些都可以工作:

mapf x = map f $ map f $ [x]
mapf' x = map (f.f) $ [x]
mapf'' x = map (\x -> f (f x)) $ [x]

【讨论】:

    【解决方案2】:

    在许多情况下,规则不会触发,因为非常简单的函数 f 在规则有机会触发之前已内联。如果你延迟内联,

    {-# INLINE [1] f #-}
    

    规则

    {-# RULES "f/f" forall a. f (f a) = 4*a #-}
    

    应该针对所有这些情况触发(在此处使用 7.2.2 和 7.4.1)。

    原因是规则匹配器并不过分复杂,它只匹配具有规则句法形式的表达式(不完全正确,规则体也经过了一些规范化)。表达式f $ f 3f . f $ 4 与规则的句法形式不匹配。为了匹配规则,必须进行一些重写,($)(.) 必须在规则匹配表达式之前内联。但是,如果您不阻止 f 在简化器的第一阶段内联,它会在与 ($)(.) 内联的同一运行中被其主体替换,因此在下一次迭代中,简化器不会'不再看到f,它只看到2*(2*x),不符合规则。

    【讨论】:

      猜你喜欢
      • 2015-04-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-30
      相关资源
      最近更新 更多