专门化没有内联的相关多态函数

以下是我正在处理的一个实际问题的最简单示例:

一个库模块:

module Lib where

class H h where
  hash :: (S s)=> s -> h -> s

class S s where
  mix :: s -> Int -> s

instance (H x, H y)=> H (x,y) where
  hash s = (x,y) ->
    s `hash` x `hash` y
      -- make this look "big":
      `hash` x `hash` y `hash` x `hash` y `hash` x `hash` y `hash` x `hash` y
      `hash` x `hash` y `hash` x `hash` y `hash` x `hash` y `hash` x `hash` y
      `hash` x `hash` y `hash` x `hash` y `hash` x `hash` y `hash` x `hash` y
      `hash` x `hash` y `hash` x `hash` y `hash` x `hash` y `hash` x `hash` y
      `hash` x `hash` y `hash` x `hash` y `hash` x `hash` y `hash` x `hash` y
      `hash` x `hash` y `hash` x `hash` y `hash` x `hash` y `hash` x `hash` y
      `hash` x `hash` y `hash` x `hash` y `hash` x `hash` y `hash` x `hash` y
      `hash` x `hash` y `hash` x `hash` y `hash` x `hash` y `hash` x `hash` y
      `hash` x `hash` y `hash` x `hash` y `hash` x `hash` y `hash` x `hash` y
      `hash` x `hash` y `hash` x `hash` y `hash` x `hash` y `hash` x `hash` y
      `hash` x `hash` y `hash` x `hash` y `hash` x `hash` y `hash` x `hash` y
      `hash` x `hash` y `hash` x `hash` y `hash` x `hash` y `hash` x `hash` y
      `hash` x `hash` y `hash` x `hash` y `hash` x `hash` y `hash` x `hash` y
      `hash` x `hash` y `hash` x `hash` y `hash` x `hash` y `hash` x `hash` y
      `hash` x `hash` y `hash` x `hash` y `hash` x `hash` y `hash` x `hash` y
      `hash` x `hash` y `hash` x `hash` y `hash` x `hash` y `hash` x `hash` y
      `hash` x `hash` y `hash` x `hash` y `hash` x `hash` y `hash` x `hash` y
      `hash` x `hash` y `hash` x `hash` y `hash` x `hash` y `hash` x `hash` y
      `hash` x `hash` y `hash` x `hash` y `hash` x `hash` y `hash` x `hash` y
      `hash` x `hash` y `hash` x `hash` y `hash` x `hash` y `hash` x `hash` y
      `hash` x `hash` y `hash` x `hash` y `hash` x `hash` y `hash` x `hash` y
      `hash` x `hash` y `hash` x `hash` y `hash` x `hash` y `hash` x `hash` y
      `hash` x `hash` y `hash` x `hash` y `hash` x `hash` y `hash` x `hash` y
      `hash` x `hash` y `hash` x `hash` y `hash` x `hash` y `hash` x `hash` y
      `hash` x `hash` y `hash` x `hash` y `hash` x `hash` y `hash` x `hash` y

instance H Int where
  hash s = n -> s `mix` n

另一种可能由用户定义:

module S where

import Lib

newtype Foo = Foo Int
    deriving Show

instance S Foo where
  mix (Foo x) y = Foo (x+y)

而我们的Main

module Main where

import Lib
import S

import Criterion.Main

main = defaultMain [
    bench "foo" $ whnf (hash (Foo 1)) (2::Int,3::Int)
  ]

使用ghc编译ghc 8.0.1 ghc --make -Wall -O2 -rtsopts -ddump-to-file -ddump-simpl -dsuppress-module-prefixes -dsuppress-uniques -ddump-core-stats -ddump-inlinings -fforce-recomp Main.hs

上述基准测试运行时间为4μs 。 但是,如果我们将INLINE hash放在Lib的两个hash声明中,我们会看到期望的特化,并获得66 ns的运行时间。

但我并不真正想要内联一切(在用户真正的Main她可能会在相同类型上多次调用hash ),我只是希望为用户代码中的每个HS实例组合专门设置该函数。

INLINE INLINABLE更改为INLINABLE导致旧行为回归(预计我认为,因为GHC的内联启发式算法仍在发挥作用)。 然后我尝试添加

{-# SPECIALIZE hash :: H a=> Foo -> a -> Foo #-}

Main模块和S模块,但这会产生

Ignoring useless SPECIALISE pragma for class method selector ‘hash’

...警告和相同的错误代码。

一些限制:

  • 尽管并不理想,但要求每个S实例声明包含有限数量的编译指示(可能与H有关)
  • 对于H也是如此
  • 要求用户对SH每个组合都进行SPECIALIZE是不可接受的。
  • 没有INLINE可以这样做吗?

    这可能与具有约束的专业化和相关的trac ticket https://ghc.haskell.org/trac/ghc/ticket/8668相同,但我想我会再次提问,并可能将此作为更简单的示例发布到GHC Trac 。


    编辑 :继续并打开ghc票:https://ghc.haskell.org/trac/ghc/ticket/13376

    链接地址: http://www.djcxy.com/p/33197.html

    上一篇: Specializing related polymorphic functions without inlining

    下一篇: Haskell Performance by Example