隐式参数是GHC中内联的难点吗?

Jef*_*ges 5 haskell lambda-calculus ghc implicit-parameters

我很好奇Kiselyov和Shan 在" 功能性珍珠:隐式配置"一文中讨论的对隐式参数的反对意见.

在存在隐式参数的情况下内联代码(β-reduce)是不可靠的.

真?我希望GHC应该内联到与传递的隐式参数相同的范围,不是吗?

我相信我理解他们的反对意见:

如果添加,删除或更改其签名,则术语的行为可能会发生变化.

GHC的用户文档解释说,程序员必须注意多态递归单态限制.这是不是因为内联问题意味着什么?

我假设这个多态递归示例还涵盖了"概括隐含参数"的意思吗?还要别的吗?

Data.ReflectionReifiesStorable类型类是否真的是解决这些困难的合理解决方案?它似乎每次访问时都会对整个隐式数据结构进行反序列化,这听起来对性能来说是灾难性的.例如,我们可能希望我们的隐含信息是Cayley表或占用ram gig的字符表,并且必须在数百万代数运算期间访问.

是否有一些更好的解决方案采用隐式参数,或者编译器可以在幕后轻松优化的另一种技术,同时仍然通过类型系统使用状态线程或其他保证更多?

ehi*_*ird 7

是的,GHC手册中的示例显示了如何添加类型签名可以使用隐式参数更改代码的语义,我相信这就是破坏内联的意思; 尽管两者具有不同的语义,但内联应用程序len_acc1与应用程序len_acc2生成相同的代码.

至于对隐式参数的概括,这意味着你不能编写一个可以对多个隐式参数进行操作的函数; 没有机制来抽象它们,因为函数使用的隐式参数由其类型固定.通过反射,您可以轻松编写类似的函数doSomethingWith :: (Reifies s a, Num a) => Proxy s -> a,该函数可以在任何具有数值的类型上运行.

至于ReifiesStorable,您正在查看旧版本的反射包; 在最新的版本有一个非常有效的实现中,reify不仅费用高达函数调用.1请注意,即使使用旧的实现,您通常也不会ReifiesStorable直接使用该类,而是Reifies使用它ReifiesStorable来进行reify StablePtr,因此只有几个字节最终被复制,而不是整个对象.(这也是本文最初的实现方式.)两种实现方式对于实际应用来说肯定足够快,旧的"慢"实现需要大约100 ms来实现并反映100000个值,而新的实现方式在10以下女士.

(完全披露:我参与了新的实施.)

1快速实现取决于Haskell实现细节.较旧,较慢的实现自动用于Haskell实现,快速实现尚未经过测试; 到目前为止,GHC和Hugs已被证明可以快速实施.您可以请求缓慢的实现-fslow,但除非GHC显着改进其类型类的实现,否则它不太可能停止工作.(即使它确实如此,您只需重新编译使用反射的包以使其再次工作.)