是否有任何理由不使用INLINABLE pragma作为函数?

gla*_*erl 44 haskell inline pragma ghc

文件规定:

函数f上的{ - #INLINABLE f# - } pragma具有以下行为:

  • 虽然INLINE说"请内联我",INLINABLE说"请随意内联我;请自行决定".换句话说,选择留给GHC,它使用与无编译指示函数相同的规则.与INLINE不同,该决定是在呼叫站点进行的,因此会受到内联阈值,优化级别等因素的影响.

  • 与INLINE类似,INLINABLE pragma保留原始RHS的副本以用于内联,并且无论RHS的大小如何,都将其保留在接口文件中.

  • 使用INLINABLE的一种方法是结合内联特殊函数(第7.18节"特殊内置函数").调用内联f非常难以内联f.为了确保f可以内联,最好将f的定义标记为INLINABLE,以便GHC保证在不管它有多大的情况下展开展开.此外,通过将f注释为INLINABLE,可以确保f的原始RHS内联,而不是f GHC优化器产生的任何随机优化版本.

  • INLINABLE pragma也适用于SPECIALIZE:如果将函数f标记为INLINABLE,那么随后可以在另一个模块中进行SPECIALIZE(参见第7.16.8节"SPECIALIZE pragma").

  • 与INLINE不同,可以在递归函数上使用INLINABLE编译指示.主要原因是允许以后使用SPECIALIZE

它的缺点是什么?

它是否使界面文件更大,更大?它是否使编译速度慢得多?

有没有理由我不应该在我写的每个导出函数上放置一个INLINABLE pragma?是否有任何理由GHC没有在我写的每个导出函数上放置一个INLINABLE pragma?

Sim*_*low 49

使用INLINABLE和完全不使用pragma有三个区别:

  • 如果没有INLINABLE,接口文件中的定义是优化的代码,而使用INLINABLE,则是您编写的代码(或多或少).特别是,没有INLINABLE,GHC可能会将其他函数内联到函数的定义中.

  • 如果没有INLINABLE,GHC将忽略接口文件中的定义,如果它太大.如果其他一些功能被内联到右侧,这可能很容易超过限制.

  • INLINABLE还打开一些聪明的机器,自动专门使用它们的重载函数,并与其他模块共享专用版本,这些模块可传递地导入创建专用版本的模块.

  • 再做一次尝试:如果我们生活在一个每个函数自动获得一个不可用的编译指示的世界中,它会有什么不好的? (19认同)
  • 我试图了解实际的后果.第一点是否意味着函数没有内联,它会使用未经优化的代码并且速度较慢?或者如果内联但是规则不会开火会慢吗?或者它有时会更快,有时在个案基础上更慢?关于第二点,将它包含在磁盘空间以外的接口文件中是否有任何缺点?他们可以变得如此之大以至于存在问题(磁盘很大)吗?并且重新:第三点,有什么理由它不是一件好事吗?它会导致有问题的代码膨胀吗? (10认同)
  • 我故意避免谈论实际的后果,因为在大多数情况下我不确定:-)我说服Simon PJ添加INLINABLE,因为我想要一个INLINE的变体,它不会导致如此多的代码膨胀,使用GHC已经相当关于何时内联的复杂启发式方法.回答你的第一个问题:不,还会有编译到原始模块中的函数的优化版本(与INLINE一样),这将用于未内联的调用.在界面中包含大量函数定义可能会减慢速度. (5认同)
  • 我知道这个问题已经过时了,但我只是想问一个问题,以确保我理解你的答案:这是否意味着使用`INLINABLE`而不使用它的唯一缺点是减慢编译时间或增加大小的接口文件? (5认同)