Ich baute eine Funktion zum Auffinden der Determinante einer Matrix mit der ST-Monade und unboxed STArrays (STUArray). Der Typ für eine Matrix ist die folgende:Kann keine richtige Signatur für eine Funktion mit STUArray finden (keine kann GHC)
newtype Matrix e = Matrix (Array Int (UArray Int e))
, die eine unveränderliche Array mit unveränderlichen unboxed Arrays enthalten, die ist. Dazu muss ich das Prädikat IArray UArray e
zu Funktionen hinzufügen, die sich auf Matrix
beziehen, was wiederum FlexibleContexts
erfordert. OK, erledigt.
Die Funktion verwendet die Determinante zu berechnen hat die folgende Signatur:
detST :: (IArray UArray e, MArray (STUArray s) e (ST s),
Num e, Eq e, Division e)
=> Array Int (UArray Int e) -> ST s e
I benötigt werde, um auch die Predicate MArray (STUArray s) e (ST s)
hinzuzufügen, da intern die Arrays in änderbare Arrays umgewandelt werden (die äußere eingerahmt, die innere unboxed) .
main = do
let [email protected](Matrix x) = matrix [ [1,-2,3,234]
, [5,2,3,-3]
, [7,18,3,40]
, [2,9,71,0] ]
d = runST (detST x) :: Int -- needed for type check, ambiguous otherwise
print d
Works, fein:
Diese Funktion kann wie so verwendet werden. Aber schau, wie hässlich es ist! Natürlich möchte ich nicht die Interna von Matrix
verraten (zumindest nicht weiter als die Prädikate, die an meine Funktionen geknüpft sind). Ich möchte folgende Funktion definieren:
det :: Matrix e -> e
Und ich kann nicht.
Ich habe versucht, ohne eine richtige Signatur:
det (Matrix arr) = runST (detST arr)
ausfällt. Fair genug, ich werde mein Gehirn an die Arbeit setzen: detST
erfordert IArray UArray e, MArray (STUArray s) e (ST s), Num e, Eq e, Division e
, tut dies auch det
, nicht wahr?
det :: (IArray UArray e, MArray (STUArray s) e (ST s),
Num e, Eq e, Division e) => Matrix e -> e
schlägt fehl. Aber ich sehe nicht wie. Die Nachricht, die GHC (7.4.2) gibt mir ist:
Could not deduce (MArray (STUArray s) t (ST s))
arising from a use of `detST'
aber der genaue Begriff ist in den Prädikaten!
GHC schlägt vor:
add (MArray (STUArray s) t (ST s)) to the context of
a type expected by the context: ST s t
or the inferred type of
det :: (Eq t, Num t, IArray UArray t, Division t) => Matrix t -> t
or add an instance declaration for (MArray (STUArray s) t (ST s))
Okay. Zu meinem Verständnis habe ich das zuerst getan. Auch gibt es eine Instanz für diese (MArray ...)
(sonst, wie könnte ich es erfolgreich in main verwendet haben ?!).
Ich bin mir nicht sicher, was hier falsch ist. Ich glaube, dass es etwas mit dem "versteckten" ST-Zustand in s
zu tun hat, und dass das von detST
einige andere s
als die s
in det
wäre, aber ich weiß nicht, wie man einen Typ dafür schreibt.
Was ist die richtige Definition von det
- und warum ?!
Das Programm ohne det
kompiliert nur mit FlexibleContexts
, keine Warnungen mit -Wall
.Der vollständige Quellcode kann as a gist here gefunden werden.
Beginnen Sie mit - warum nicht einfach ein UArray verwenden, das mit (Int, Int) anstelle eines Arrays von Arrays indiziert ist? –
Damit kann ich einfach die Zeilen wechseln. Wie auch immer, es gibt natürlich andere mögliche Versionen dieses Programms. Aber ich möchte wissen, warum ich diese bestimmte Funktion nicht definieren kann und was damit nicht stimmt. – scravy
Können Sie uns die Definition von 'detST' zeigen, damit wir Ihren Code testen können? Ich verstehe nicht ganz, warum es in "ST" sein muss. –