【问题标题】:Python-"is"-like equality operator for Haskell/GHC用于 Haskell/GHC 的 Python-“is”-like 等式运算符
【发布时间】:2011-10-02 05:15:40
【问题描述】:

是否有特定于 GHC 的“不安全”扩展来询问两个 Haskell 引用是否指向同一位置?

我知道如果使用不当,这可能会破坏参考透明度。但是,如果非常小心地使用它作为一种通过捷径递归(或昂贵)数据遍历进行优化的手段,应该不会有什么危害(除非我遗漏了什么),例如用于实现优化的Eq 实例,例如:

instance Eq ComplexTree where
   a == b  = (a `unsafeSameRef` b) || (a `deepCompare` b)

如果unsafeSameRef 决定为真,则提供deepCompare 保证为真(但不一定反过来)。

EDIT/PS:感谢指向System.Mem.StableName 的答案,我还能够找到Stretching the storage manager: weak pointers and stable names in Haskell 的论文,它恰好在10 多年前就已经解决了这个问题。 .

【问题讨论】:

  • 我经常想要这个功能,正是为了这个目的:更快的相等性检查。
  • @FUZxxl:如果他问这个问题(并且问题清楚地表明他知道他在说什么),那么显然他需要那个。在不知道他的问题的情况下指责 OP 执行过早的优化有点……为时过早。
  • @Roman Cheplyaka:对不起。我不想评论太粗鲁,所以我删除了它。
  • +1 对于完美提出的问题。但是,我相信编译器会自动为我做这个优化。不是吗?
  • @Tarrasch:不,有很多理由不这样做。特别是,正如 Lennart Augustsson 在他的回应中指出的那样,平等并不完全是自反的。

标签: haskell reference ghc


【解决方案1】:

GHC 的System.Mem.StableName 正好解决了这个问题。

【讨论】:

    【解决方案2】:

    有一个陷阱需要注意:

    指针相等可以改变严格性。即,您可能会得到指针相等性为 True,而实际上真正的相等性测试会因为例如循环结构而循环。所以指针相等破坏了语义(但你知道的)。

    【讨论】:

      【解决方案3】:

      我认为 StablePointers 在这里可能会有所帮助 http://www.haskell.org/ghc/docs/6.12.2/html/libraries/base-4.2.0.1/Foreign-StablePtr.html 也许这就是您正在寻找的解决方案:

      import Foreign.StablePtr (newStablePtr, freeStablePtr)
      import System.IO.Unsafe (unsafePerformIO)
      
      unsafeSameRef :: a -> a -> Bool
      unsafeSameRef x y = unsafePerformIO $ do
          a <- newStablePtr x
          b <- newStablePtr y
          let z = a == b
          freeStablePtr a
          freeStablePtr b
          return z;
      

      【讨论】:

      • StableName 会按照您的建议行事。 StablePtr 不进行任何重复数据删除/共享。它根本不经过哈希表之类的。
      • 啊,感谢您的更新。我看到StablePtr这个用途的缺点。
      【解决方案4】:

      unpackClosure# in GHC.Prim,类型如下:

      unpackClosure# :: a -> (# Addr#,Array# b,ByteArray# #)
      

      使用它你可以掀起类似的东西:

      {-# LANGUAGE MagicHash, UnboxedTuples #-} 
      import GHC.Prim
      
      eq a b = case unpackClosure# a of 
          (# a1,a2,a3 #) -> case unpackClosure# b of 
              (# b1,b2,b3 #) -> eqAddr# a1 b1
      

      在同一个包中,有一个有趣的reallyUnsafePtrEquality# 类型

      reallyUnsafePtrEquality#  :: a -> a -> Int#
      

      但我不确定它的返回值是什么 - 就名字而言,它会导致咬牙切齿。

      【讨论】:

      • @yatima2975:我问了一个关于reallyUnsafePtrEquality# 在#ghc 频道中的作用的问题。答案是:FUZxxl: (...) 但它需要两个对象并告诉您它们在内存中的地址是否相同(=> 它们是同一个对象)。你甚至可以在 ghci 中尝试!但是,您会发现问题出在哪里:它只在某些情况下有效。
      • 它返回 0# 表示不等式,1# 表示相等。但请注意,可能同时存在误报和误报。
      • @FYZxxl 误报误报...换句话说...没用?
      • @FUZxxl - 感谢您发现这一点!假阴性并没有那么糟糕(对于提问者),因为他只需要进行“正常”比较,但假阳性的可能性使reallyUnsafePtrEquality 对这个问题完全无用。大概是因为物体被 GC 移动了?
      • @Dan 他们应该将其重命名为reallyUselessPtrEquality# 然后:)
      猜你喜欢
      • 1970-01-01
      • 2020-08-16
      • 2019-02-06
      • 2019-11-27
      • 2012-04-07
      • 2011-08-09
      • 1970-01-01
      • 2012-09-03
      • 2011-03-14
      相关资源
      最近更新 更多