Python- "is" -подобный оператор равенства для Haskell / GHC - PullRequest
12 голосов
/ 18 апреля 2011

Существует ли специфичное для GHC «небезопасное» расширение, чтобы спросить, указывают ли две ссылки на Haskell на одно и то же местоположение?

Я знаю, что это может нарушить ссылочную прозрачность, если не используется должным образомНо должно быть мало вреда (если я что-то упускаю), если это используется очень осторожно, как средство оптимизации путем краткого рекурсивного (или дорогого) обхода данных, например, для реализации оптимизированного экземпляра Eq, например:

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

при условии deepCompare гарантированно будет истинным, если unsafeSameRef решит истинным (но не обязательно наоборот).

РЕДАКТИРОВАТЬ / PS : Благодаря ответу, указывающему на System.Mem.StableName, я также смог найти статью Растяжение диспетчера хранилища: слабые указатели и стабильные имена в Haskell , который, как оказалось, решил эту самую проблему уже более 10 лет назад...

Ответы [ 4 ]

12 голосов
/ 18 апреля 2011

GHC's System.Mem.StableName решает именно эту проблему.

8 голосов
/ 18 апреля 2011

Есть ловушка, о которой следует знать:

Равенство указателей может изменить строгость. То есть, вы можете получить указатель равенства, говоря «True», когда на самом деле тест на равенство был бы зациклен, например, из-за круговой структуры. Таким образом, равенство указателей разрушает семантику (но вы это знали).

2 голосов
/ 18 апреля 2011

Есть 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#

Но я не уверен, что возвращаемое значение этого - имя, которое приведет к сильному скрежетанию зубов.

2 голосов
/ 18 апреля 2011

Я думаю, что 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;
...