简体   繁体   English

GHC StablePointer平等推理

[英]GHC StablePointer equality reasoning

I just learned about GHC's StablePointer feature, which is really cool, but I can't figure out why it has won't show things as equal. 我刚刚了解了GHC的StablePointer功能,这非常酷,但我无法弄清楚为什么它不会显示相同的东西。 Here is my test case: 这是我的测试用例:

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

Pretty simple, but when I do runhaskell with GHC 7.8.4, I get a result of false. 很简单,但是当我使用GHC 7.8.4运行runhaskell时,我得到了错误的结果。 What about a simpler case? 一个更简单的案例怎么样? Let's try this: 我们试试这个:

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

I still get a result of False. 我仍然得到False的结果。 The only way I can get eqStableName to return True is when I call makeStableName on the same exact bound variable. 我可以让eqStableName返回True的唯一方法是在同一个精确绑定变量上调用makeStableName Like this: 像这样:

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

But this is no longer helpful. 但这不再有用。 I already know that every expression is equal to itself, so this doesn't give me any new information. 我已经知道每个表达式都等于它自己,所以这并没有给我任何新的信息。 My question is twofold: 我的问题是双重的:

  1. What use cases is StablePointer intended to satisfy? StablePointer打算满足哪些用例?
  2. How can we reason about the equality of StablePointer . 我们如何StablePointer的相等性。 I know that it gives false negatives, but under what circumstances can I expect these to always occur? 我知道它会给出假阴性,但在什么情况下我可以期望它们总是会发生?

Thanks for any insights. 感谢您的任何见解。 They are much appreciated. 非常感谢他们。

-- EDIT -- - 编辑 -

I discovered that if I build it with ghc instead of runhaskell , then Example 2 actually does show that they are equal. 我发现如果我用ghc而不是runhaskell构建它,那么实例2确实表明它们是相同的。 Example 1 still fails. 示例1仍然失败。 The question still stands. 问题仍然存在。

The reason those return False is probably laziness. 那些返回False的原因可能是懒惰。 In GHC, m and n will refer to different thunks, since they are not evaluated yet. 在GHC中, mn将引用不同的thunk,因为它们尚未被评估。 makeStableName does not force the value. makeStableName不强制该值。 If you manually force the thunk, they will be the same: 如果您手动强制thunk,它们将是相同的:

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

This prints True (The $! will force the value returned by getWrapper to WHNF). 这打印为True$!将强制getWrapper返回的值到WHNF)。

Note that if you don't use runhaskell but instead compile with -O1 , GHC will actually compile this code such that it prints True . 请注意,如果你不使用runhaskell而是与编译-O1 ,GHC实际上将编译这段代码,使得它打印True From looking at the Core, it seems that what GHC has done is inlining m and getWrapper so that the code that is run is effectively this: 从核心看,似乎GHC所做的是内联mgetWrapper以便运行的代码实际上是这样的:

a <- makeStableName myFunc
b <- makeStableName myFunc

Which then of course generates the same stable pointer. 然后当然会生成相同的稳定指针。

So if you want maximum equality, always force your values before making stable pointers to them. 因此,如果您想要最大程度的相等,请在制作稳定指针之前强制使用您的值。 There is no guarrante though that if two values are equal that they are assigned equal stable pointers. 但是没有保证,如果两个值相等,则它们被赋予相同的稳定指针。

If you haven't read it yet, I also recommend reading Stretching the storage manager which explains the implementation of stable pointers. 如果您尚未阅读,我还建议阅读Stretching the storage manager ,它解释了稳定指针的实现。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM