2015-04-15 18 views
7

Ho appena saputo della funzione StablePointer di GHC, che è davvero interessante, ma non riesco a capire perché non abbia mostrato le cose come uguali. Qui è il mio banco di prova:GHC StablePointer ragionamento sull'uguaglianza

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

Abbastanza semplice, ma quando lo faccio runhaskell con GHC 7.8.4, ottengo un risultato di falso. Che dire di un caso più semplice? Proviamo questo:

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

ho ancora ottenere un risultato di falso. L'unico modo per ottenere eqStableName per restituire True è quando chiamo makeStableName sulla stessa variabile vincolata esatta. Come questo:

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

Ma questo non è più utile. So già che ogni espressione è uguale a se stessa, quindi questo non mi dà alcuna nuova informazione. La mia domanda è duplice:

  1. Quali casi d'uso sono StablePointer destinati a soddisfare?
  2. Come possiamo ragionare sull'eguaglianza di StablePointer. So che fornisce falsi negativi, ma in quali circostanze posso aspettarmi che si verifichino sempre?

Grazie per eventuali approfondimenti. Sono molto apprezzati.

- EDIT -

ho scoperto che se io costruisco con ghc invece di runhaskell, poi Esempio 2 in realtà esse indicano che sono uguali. L'Esempio 1 non funziona ancora. La domanda è ancora valida.

+2

Hai provato a usare '==' invece di 'eqStableName'? – Bakuriu

+0

Ho appena provato e non fa differenza. Non avevo nemmeno notato che 'StablePointer a' aveva un'istanza 'Eq', ma ora che l'hai fatto notare, vedo che usare' == 'sembra più appropriato per il mio caso, dal momento che sto facendo controlli di uguaglianza su cose dello stesso tipo. –

risposta

8

Il motivo per cui restituiscono False è probabilmente la pigrizia. In GHC, m e n faranno riferimento a diversi thunk, poiché non sono ancora stati valutati. makeStableName non impone il valore. Se si forza manualmente il thunk, saranno lo stesso:

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

Questo stampa True (Il $! costringerà il valore restituito da getWrapper a WHNF).

Si noti che se non si utilizza runhaskell ma invece si compila con -O1, GHC compilerà questo codice in modo tale da stampare True. Guardando il Core, sembra che ciò che ha fatto è GHC inlining m e getWrapper modo che il codice che viene eseguito è effettivamente questo:

a <- makeStableName myFunc 
b <- makeStableName myFunc 

Che poi, naturalmente, genera lo stesso puntatore stabile.

Quindi, se si desidera la massima uguaglianza, forzare sempre i propri valori prima di renderli puntatori stabili. Tuttavia, non c'è guarrante che se due valori sono uguali vengono assegnati uguali puntatori stabili.

Se non l'hai ancora letto, ti consiglio anche di leggere Stretching the storage manager che spiega l'implementazione dei puntatori stabili.

+0

Grazie. Questo risponde alla mia domanda e sicuramente leggerò il giornale stasera. –

+1

Per le future persone interessate, pagina 7 spiega le idee in questa risposta abbastanza bene. –