部分评估右手操作员部分

Partially evaluating right-handed operator sections

我有一个函数(*~)。评估 x *~ y 的大部分成本来自检查第二个参数,大致如下:

(*~) :: a -> b d -> c d a
x *~ y = case y' of
           Bar -> cheapFunction y' x
           Baz -> cheapFunction2 y' x
           Quux -> cheapFunction3 y' x
  where
    y' = expensive y

有什么方法可以说服 GHC 部分评估像 (*~ y) 这样的运算符部分吗?

我试过重写它:

(*~) = flip go
  where
    go y = let y' = expensive y
            in case y' of
                 Bar -> cheapFunction y'
                 Baz -> cheapFunction2 y'
                 Quux -> cheapFunction3 y'

但这似乎没有帮助。我认为这可能是因为 flip 在翻转之前需要所有参数?

一种方法就是翻转运算符本身,但当昂贵的操作数在右侧时,它读起来更自然,因为它与现有符号对齐。

精心制作的 {-# RULE #-} 可以保释我吗?如果是这样,它应该怎么说? (我不清楚在规则寻找匹配项之前,分段语法将被去除多远。)

要触发这样的优化,您需要确保您的函数是内联的。将 {-# INLINE (*~) #-} 编译指示放在 (*~) 函数声明之前。我不能向你保证它会解决你的问题,但这是我看到它被接近的唯一方式。之后我会使用 "ghc-core" 之类的工具检查生成的核心代码以确保。

但是,您的问题实际上只是代码组成不当的迹象。您的功能正在做多个不相关的事情。 expensive y 应该简单地从中排除,然后您的问题将被删除。即,使用模式应该是 x *~ expensive y 而不是 x *~ y.