2012-08-03 10 views
7

Wenn ich versuche, dies zu kompilieren:Haskell: „Kann nicht ableiten“ Fehler mit runST

module Main where 

import qualified Data.Vector.Unboxed.Mutable as MV 
import Control.Monad.ST 

myRead mv = runST $ MV.read mv 0 

bekomme ich folgende Fehlermeldung:

Could not deduce (t ~ U.MVector s a) 
    from the context (U.Unbox a) 
     bound by the inferred type of myRead :: U.Unbox a => t -> a 
     at src/Main.hs:53:1-32 
     `t' is a rigid type variable bound by 
      the inferred type of myRead :: U.Unbox a => t -> a 
      at src/Main.hs:53:1 
    Expected type: U.MVector (PrimState (ST s)) a 
     Actual type: t 
    In the first argument of `MV.read', namely `mv' 
    In the second argument of `($)', namely `MV.read mv 0' 
    In the expression: runST $ MV.read mv 0 

Kann ich einen Lesevorgang von einem wandelbaren Vektor machen rein mit runST? Wenn das so ist, wie? Ich nehme an, dass es eine Typ-Signatur für myRead enthält, aber alles, was ich versucht habe, hat nur zu mehr und mehr unverständlichen Fehlermeldungen geführt.

EDIT: einige Kontext Hervorhebungen ich unten in einem Kommentar setzen gerade: Der Kontext ist hier, dass ich eine Funktion haben, die in einem wandelbaren Vektor nimmt, hat einige Berechnungen der wandelbaren Vektor als temporäre Scratch-Bereich verwendet wird, dann braucht um einen Gleitkommawert zurückzugeben. Da mir die Änderungen am veränderbaren Vektor egal sind, habe ich mich gefragt, ob es eine Möglichkeit gibt, die "Zustandsänderung" zu ignorieren und einfach einen der Werte aus dem Inneren des Vektors zurückzugeben.

+1

Ich denke, die Meinung der Weisen, nämlich Breitner und Fischer, ist, dass wir mehr darüber wissen müssen, wie Sie zu diesem Punkt gekommen sind. Welche Funktion erzeugt den veränderbaren Vektor, auf den Sie myRead anwenden möchten? Siehe den letzten Satz in Breitners Antwort. Wenn wir wüssten, was dich in diese Ecke bringt, könnten wir sagen, wie man Dinge neu analysiert, damit sie zusammenhängen. Ein paar weitere Zeilen Code wären daher hilfreich. Wenn sich beispielsweise "mv" in einem ST-Block befindet, könnte die einfachere Definition "myRead mv = MV.read mv 0" (kein "runST") verwendet werden. – applicative

+0

Lassen Sie mich verstärken, was anwendungs ​​gesagt: Wir brauchen mehr Kontext. Ohne zu wissen, was Sie eigentlich erreichen wollen, können wir keine geeignete Lösung finden. –

Antwort

2

Die anderen Antworten sind gut, aber ich denke, es gibt eine grundlegende Sache über ST, die Sie vermissen. Jeder Aufruf von runST macht effektiv ein neues "ST-Universum", in dem ein imperativer Code läuft. Wenn Sie also einen Aufruf von runST haben, um das Array zu erstellen, und einen separaten Aufruf von runST, um einen Wert aus diesem Array zu erhalten, können die Dinge unmöglich funktionieren. Die beiden runST-Aufrufe möchten ihre eigenen eindeutigen Universen haben, während Sie möchten, dass sie eins gemeinsam nutzen.

Was die Antworten in einigen Details erklärt, ist, wie diese einzigartigen Universen durch eine Art System-Trickserei erzeugt werden.

+0

Dies. 'runST' soll von außen rein aussehen, also kann nichts veränderbares aus der' ST'-Monade entkommen. – MathematicalOrchid

3

Der Compiler sieht standardmäßig das Argument mv auf der linken Seite eines bestimmten Typs, erfordert jedoch etwas von polymorphem Typ auf der rechten Seite. Eine Typ-Signatur kann Dinge reparieren.

{-#LANGUAGE Rank2Types#-} 
module Main where 

import qualified Data.Vector.Unboxed.Mutable as MV 
import Control.Monad.ST 

myRead :: MV.Unbox a => (forall s . MV.MVector s a) -> a 
myRead mv = runST $ MV.read mv 0 

Die Möchtegern-Signatur Ihrer Funktion etwas so sein würde, wenn ich verstehe:

-- myBadRead :: forall s a . MV.Unbox a => MV.MVector s a -> a 
-- myBadRead mv = runST $ MV.read mv 0 

aber hier runST :: (forall s. ST s a) -> a würde eine s -unabhängigen Sache nicht arbeiten müssen, da s ist behoben, wenn Sie mv auf der LHS schreiben.

Edit: Allerdings, wie Joachim B und Daniel F. betonen, obwohl die obige Definition kohärent ist, wird es in der Praxis keinen Nutzen bringen, da Sie nicht in der Lage sein werden, einen Vektor mv zu konstruieren. Um es grob auszudrücken, jede Art, eine mv zu erzeugen, wird bereits eine Deteminierung s haben, die ihr vom Compiler unter der Haube zugewiesen wird. Eine Standardmethode ist ein solche Funktion wirkt auf einem ‚reinen‘ Vektor aus Data.Vector.Unboxed dann zu machen, auf der rechten Seite, auftauen es vor Operationen vom .Mutable Modul

import qualified Data.Vector.Unboxed as UV 
import qualified Data.Vector.Unboxed.Mutable as MV 
import Control.Monad.ST 

myRead :: MV.Unbox a => UV.Vector a -> a 
myRead v = runST $ do mv <- UV.unsafeThaw v 
         MV.read mv 0 

Natürlich Anwendung diese spezielle Definition entspricht so etwas zu myRead = (UV.! 0) in ähnlicher Weise würde Sinn machen, schlägt die runST in der Definition von myRead

mhead :: MV.Unbox a => MV.MVector s a -> ST s a 
mhead mv0 = MV.read mv0 0 

mrx = runST $ do mv <- UV.unsafeThaw $ UV.enumFromStepN 0 1 20 
          -- ^^^ or however the mv is generated. 
        x <- MV.unsafeRead mv 17 -- arbitrary 'scratch pad' 
        MV.unsafeWrite mv 17 (2*x) -- computations 
        mhead mv 
        -- ^^^ we return just the first element, after all the mutation 

Hier, anstatt Absperren myRead oder mhead mit runST wir halten i t polymorph in s und kann es dann innerhalb desselben ST Blocks verwenden, in dem der veränderbare Vektor mv erscheint. Der Compiler wird somit in der Lage sein, das 'Geheimnis' s zu verwenden, das es für den Do-Block als Ganzes verwendet, das Ergebnis der Anwendung von mhead bis mv zu interpretieren, da es eine der Möglichkeiten unserer polymorphen Definition von mhead

ist
3

Die Antwort von applicative sagt Ihnen, wie Sie Ihren Code kompilieren können. Aber der Code wird nicht benutzbar sein: Der Punkt runST ist, dass die Imperativberechnung nicht aufgrund der dort existentiell gebundenen Typvariablen entkommen kann.

Nun kann jeder änderbaren Array, die Sie irgendwo schaffen Typ MVector s a für ein festen s haben, während myRead Wert erwartet, die einen Vektor für beliebigen s zur Verfügung stellt.

Es scheint, dass es ein Problem früher gab, dass Sie diese (unmögliche) Funktion haben wollte.

+0

Ich stimme zu, dass es eine unerwünschte Funktion ist, ich versuchte, den Typfehler zu erklären. Ist die Erklärung unpassend? Wenn ja, sollte ich es entfernen. Ich dachte an den Schreiber, der sich darüber klar wird, wie Typinferenz mit ST funktioniert. – applicative

+0

@applicative Nein, die Erklärung ist in Ordnung. Vielleicht hinzufügen, dass die Funktion unbrauchbar wäre, so dass beide Antworten diese wichtige Tatsache haben. –

+0

Ich kann nicht sagen, dass ich viel von dem, was Sie oben gesagt haben, verstanden habe, aber ich frage mich, ob Sie weiter erklären könnten, warum diese Funktion unmöglich ist. Der Kontext ist, dass ich eine Funktion habe, die einen veränderbaren Vektor aufnimmt, einige Berechnungen durchführt, die den veränderbaren Vektor als temporären Scratch-Space verwenden, und dann einen Float-Wert zurückgeben muss. Da mir die Änderungen am veränderbaren Vektor egal sind, habe ich mich gefragt, ob es eine Möglichkeit gibt, die "Zustandsänderung" zu ignorieren und einfach einen der Werte aus dem Inneren des Vektors zurückzugeben. – brooks94

Verwandte Themen