Performance 部分求值右撇子部分

Performance 部分求值右撇子部分,performance,haskell,ghc,Performance,Haskell,Ghc,我有一个函数(*~)。计算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 是否有办法

我有一个函数
(*~)
。计算
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
在进行翻转之前需要所有的参数

一种方法是翻转运算符本身,但当昂贵的操作数位于右侧时,它的读取更自然,因为它与现有的表示法对齐


一个精心设计的
{-#规则#-}
能帮我摆脱困境吗?如果是,它应该说什么?(我不清楚在规则查找匹配项之前,分段语法会被删除多少。)

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


然而,您的问题实际上只是代码组合不当的一个迹象。您的功能是做多个不相关的事情<代码>昂贵的y应该简单地从中剔除,然后您的问题将被删除。也就是说,使用模式应该是
x*~y
而不是
x*~y

我不确定部分评估会给你带来什么好处<代码>y'已被共享。你想要回忆录吗?你需要自己添加备忘录。您希望编写哪种规则?如果使用自定义的
翻转
,会发生什么情况
flip'f x=\y->inline f y x
@ReinHenrichs将
y'
已共享吗?如果是这样的话,那么我的理解是相当破碎的,我愿意接受一个解释如何理解的答案。如果我做了
fmap(*~y)一些长列表
,它不是每次都会被重新计算吗?我指的是
(*~)
定义中的
y'
,但是我知道你现在想要什么样的共享,我认为这取决于GHC以一种不明显的方式如何进行节段,所以我不知道它是否会。你可以试着阅读核心并找出答案。@ErikAllik我认为问题在于必须共享的不是
y
,而是
(*~)
y
执行的一些中间计算的结果。这是一个好观点,可以解决问题。但是,
昂贵的
的结果类型目前是一个隐藏的实现细节,因为公开
(*~)
的库的用户实际上对它不感兴趣。实际上,在您的情况下,它也不是一个隐藏的实现细节,您只是以不同的方式公开它。您还将混淆您的意图并将其隐藏在类型系统中,因此必须以其他方式通知用户您的特殊函数应该如何使用。从可用性的角度来看,这可能不是件好事。同样,这也不利于关注点的分离。你已经有了一系列表明你的方法不正确的迹象,所以最好三思而后行。