GHC StablePointer平等推理

And*_*tin 7 haskell ghc

我刚刚了解了GHC的StablePointer功能,这很酷,但我无法弄清楚为什么它不会显示相同的东西.这是我的测试用例:

-- Example 1
import System.Mem.StableName

data Wrapper = Wrapper { getWrapper :: Int -> Bool }

myFunc :: Int -> Bool
myFunc = (> 4)

main :: IO ()
main = do
  let m = Wrapper myFunc
  a <- makeStableName $ getWrapper m
  b <- makeStableName $ getWrapper m
  print (a `eqStableName` b)
  putStrLn "Done"
Run Code Online (Sandbox Code Playgroud)

非常简单,但是当我runhaskell使用GHC 7.8.4时,我得到了错误的结果.一个更简单的案例怎么样?我们试试这个:

-- Example 2
import System.Mem.StableName

main :: IO ()
main = do
  let m = (+2) :: Int -> Int
      n = m
  a <- makeStableName m
  b <- makeStableName n
  print (a `eqStableName` b)
  putStrLn "Done"
Run Code Online (Sandbox Code Playgroud)

我仍然得到False的结果.我可以eqStableName返回的唯一方法True是当我调用makeStableName相同的精确绑定变量时.像这样:

  -- in this example, r can be anything
  a <- makeStableName r
  b <- makeStableName r
  print (a `eqStableName` b)
Run Code Online (Sandbox Code Playgroud)

但这不再有用.我已经知道每个表达式都等于它自己,所以这并没有给我任何新的信息.我的问题是双重的:

  1. 哪些用例StablePointer旨在满足?
  2. 我们怎样才能推断出平等StablePointer.我知道它会给出假阴性,但在什么情况下我可以期望它们总是会发生?

感谢您的任何见解.非常感谢他们.

- 编辑 -

我发现如果我用它ghc代替它runhaskell,那么实例2确实表明它们是相同的.示例1仍然失败.问题仍然存在.

ben*_*ofs 8

那些回归的原因False可能是懒惰.在GHC中,m并且n将引用不同的thunk,因为它们尚未被评估.makeStableName不强迫价值.如果您手动强制thunk,它们将是相同的:

  let m = Wrapper myFunc
  a <- makeStableName $! getWrapper m
  b <- makeStableName $! getWrapper m
  print (a `eqStableName` b)
Run Code Online (Sandbox Code Playgroud)

这打印True($!将强制返回getWrapperWHNF 的值).

请注意,如果您不使用runhaskell而是使用编译-O1,GHC将实际编译此代码以便打印True.从核心看,似乎GHC所做的是内联m,getWrapper因此运行的代码实际上是这样的:

a <- makeStableName myFunc
b <- makeStableName myFunc
Run Code Online (Sandbox Code Playgroud)

然后当然会生成相同的稳定指针.

因此,如果您希望获得最大的相等性,请始终在为其提供稳定指针之前强制使用您的值 虽然如果两个值相等,则它们被赋予相同的稳定指针,但是没有保证.

如果您尚未阅读,我还建议阅读Stretching the storage manager,它解释了稳定指针的实现.