Ответ 1
GHC System.Mem.StableName решает именно эту проблему.
Существует ли специальное небезопасное расширение GHC, чтобы спросить, указывают ли две ссылки Haskell на одно и то же местоположение?
Я знаю, что это может сломать ссылочную прозрачность, если она не используется должным образом. Но не должно быть никакого вреда (если я не пропущу что-то), если он используется очень осторожно, в качестве средства для оптимизации путем короткого рекурсивного (или дорогого) обхода данных, например. для реализации оптимизированного экземпляра Eq
, например:
instance Eq ComplexTree where
a == b = (a `unsafeSameRef` b) || (a `deepCompare` b)
обеспечение deepCompare
гарантируется как истина, если unsafeSameRef
принимает значение true (но не обязательно наоборот).
EDIT/PS: благодаря ответу, указывающему на System.Mem.StableName
, мне также удалось найти документ Растяжение хранилища менеджер: слабые указатели и стабильные имена в Haskell, которые, как оказалось, уже рассматривали эту проблему уже более 10 лет назад...
GHC System.Mem.StableName решает именно эту проблему.
Там есть ошибка, о которой нужно знать:
Уравнение указателя может изменить строгость. I.e., вы можете получить равенство указателя, обозначающее True, когда на самом деле реальный тест равенства будет зацикливаться из-за, например, круговой структуры. Таким образом, равенство указателя разрушает семантику (но вы это знали).
Я думаю, что 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;
Там unpackClosure#
в 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#
Но я не уверен, что такое возвращаемое значение - идя по имени, это приведет к большому скрежет зубов.