GHC StablePointer平等推理

时间:2015-04-15 14:48:52

标签: 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"

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

-- 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"

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

  -- in this example, r can be anything
  a <- makeStableName r
  b <- makeStableName r
  print (a `eqStableName` b)

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

  1. StablePointer打算满足哪些用例?
  2. 我们如何推理StablePointer的平等。我知道它会给出假阴性,但在什么情况下我可以期望它们总是发生?
  3. 感谢您的任何见解。非常感谢他们。

    - 编辑 -

    我发现如果我使用ghc而不是runhaskell构建它,那么示例2确实显示它们是相等的。示例1仍然失败。问题仍然存在。

1 个答案:

答案 0 :(得分:8)

返回False的原因可能是懒惰。在GHC中,mn将引用不同的thunk,因为它们尚未进行评估。 makeStableName不强制该值。如果您手动强制thunk,它们将是相同的:

  let m = Wrapper myFunc
  a <- makeStableName $! getWrapper m
  b <- makeStableName $! getWrapper m
  print (a `eqStableName` b)

这会打印True$!会强制getWrapper返回给WHNF的值。

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

a <- makeStableName myFunc
b <- makeStableName myFunc

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

因此,如果你想要最大程度的相等,那么在为它们提供稳定的指针之前总是强制你的值。但是没有保证,如果两个值相等,则它们被赋予相同的稳定指针。

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