为什么管道(pipes)定义内部函数

6
我正在查看pipes库的源代码,在Core module中举例,我不明白作者为什么总是使用以下定义函数的模式:
runEffect = go
  where
    go p = ...

或者:

pull = go
  where
    go a' = ...

或者:

reflect = go
  where
    go p = ...

这是一种启用某些优化的技巧吗?如果是出于优化目的,我觉得这很丑陋,但如果编译器可以在不使用这种技巧的情况下实现优化就好了。但也许还有其他原因?

1个回答

7

GHC仅会内联非递归函数,并且仅当从语法角度来看它们被“完全应用”时才会这样做(即在调用点,它们被应用到与左侧在定义中出现的参数数量相同的参数上)。

在您发布的示例中没有参数,但是定义可能是递归的,并且不会被内联。进行此转换可能允许在调用点处将定义内联和专门化(针对m等的具体类型)。

这是启用某些优化的技巧吗? 如果是一些优化技巧,我觉得很丑陋,我希望编译器可以在不使用这种方法的情况下执行它。

是的,这太糟糕了。


2
“pipes”是一个小型库,具有可组合的抽象,可以用于构建许多复杂的逻辑,因此在核心库级别进行重度优化是很自然的。它还具有非平凡的重写规则。相比之下,在正常的生产代码中,我们不需要关注手动工作包装器。 GHC通常做得很好。 - András Kovács
1
谢谢。感谢您的关键词“完全应用”,我现在发现了这个:https://dev59.com/5Wgt5IYBdhLWcg3w8h_e,希望对我解决问题有所帮助。当你看到Haskell可以实现的所有其他魔法时,这是相当令人失望的。 - Emmanuel Touzery
1
顺便问一下,如果左侧出现的参数数量很重要,你能否编写 runEffect = \p -> ... 并获得相同的性能特征?我认为这看起来会少得多。 - Emmanuel Touzery
1
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - jberryman
只是为了确保我理解:GHC可以内联递归吗?即使知道它超出惊人的范畴,我也从未想过它会这样做。如果是的话,那就非常令人印象深刻。 - MasterMastic
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接