Haskell STM -Prüffunktion, die undefiniert zurücksend
Frage
Gibt es einen guten Grund, warum die check
Funktion in der Contol.Concurent.STM
Bibliothek hat Typ Bool -> STM a
und kehrt zurück undefined
auf Erfolg, anstatt den Typ zu haben Bool -> STM ()
? Die Art und Weise, wie es implementiert wird, wird der Typ Checker Polity ein Do -Block -Block miteinander kompilieren check foo
Nur um zur Laufzeit mit der Laufzeit zu scheitern *** Exception: Prelude.undefined
.
Lösung
Es sieht so aus, als wäre es eine Platzhalterdefinition für a GHC Primop, wie die "Definition" seq _ y = y
Das wird durch den Compiler durch den tatsächlichen primitiven Implementierungscode ersetzt. Das Primop -Implementierung von check
nimmt einen Ausdruck und fügt ihn zu einer globalen Liste von Invarianten hinzu, wie in der beschrieben STM Invariants Paper.
Hier ist ein superkontrolliertes Beispiel, das aus diesem Papier modifiziert wurde, um den neuen Typ von zu passen check
:
import Control.Concurrent.STM
data LimitedTVar = LTVar { tvar :: TVar Int
, limit :: Int
}
newLimitedTVar :: Int -> STM LimitedTVar
newLimitedTVar lim = do
tv <- newTVar 0
return $ LTVar tv lim
incrLimitedTVar :: LimitedTVar -> STM ()
incrLimitedTVar (LTVar tv lim) = do
val <- readTVar $ tv
let val' = val + 1
check (val' <= lim)
writeTVar tv val'
test :: STM ()
test = do
ltv <- newLimitedTVar 2
incrLimitedTVar ltv -- should work
incrLimitedTVar ltv -- should work still
incrLimitedTVar ltv -- should fail; we broke the invariant
Realistisch gesehen wäre dies nützlich, um Invarianten in den gemeinsamen Zustand zu gründen, in dem die Behauptung möglicherweise ein Zeichen für eine vorübergehende Inkonsistenz sein könnte. Vielleicht möchten Sie dann die Erwartung wiederholen, dass diese Invariante irgendwann wieder wahr wird, aber da dieses Beispiel dauerhaft die Invariante bricht, ruft es nur an retry
für immer und scheint zu hängen. Schauen Sie sich das Papier für viel bessere Beispiele an, aber denken Sie daran, dass sich der Typ seit seiner Veröffentlichung geändert hat.