Ich versuche, das folgende minimale Beispiel von Numeric.AD zu kompilieren:minimal Numeric.AD Beispiel nicht kompiliert
import Numeric.AD
timeAndGrad f l = grad f l
main = putStrLn "hi"
und ich laufe in diesen Fehler:
test.hs:3:24:
Couldn't match expected type ‘f (Numeric.AD.Internal.Reverse.Reverse
s a)
-> Numeric.AD.Internal.Reverse.Reverse s a’
with actual type ‘t’
because type variable ‘s’ would escape its scope
This (rigid, skolem) type variable is bound by
a type expected by the context:
Data.Reflection.Reifies s Numeric.AD.Internal.Reverse.Tape =>
f (Numeric.AD.Internal.Reverse.Reverse s a)
-> Numeric.AD.Internal.Reverse.Reverse s a
at test.hs:3:19-26
Relevant bindings include
l :: f a (bound at test.hs:3:15)
f :: t (bound at test.hs:3:13)
timeAndGrad :: t -> f a -> f a (bound at test.hs:3:1)
In the first argument of ‘grad’, namely ‘f’
In the expression: grad f l
Jeder Hinweis als warum passiert das? bei den vorherigen Beispielen aus der Betrachtung entnehme ich, dass dies „Abflachung“ grad
‚s Typ:
grad :: (Traversable f, Num a) => (forall s. Reifies s Tape => f (Reverse s a) -> Reverse s a) -> f a -> f a
aber ich brauche eigentlich so etwas wie dies in meinem Code zu tun. In der Tat ist dies das minimalste Beispiel, das nicht kompiliert wird. Je komplizierter, was ich tun möchte, ist so etwas wie diese:
example :: SomeType
example f x args = (do stuff with the gradient and gradient "function")
where gradient = grad f x
gradientFn = grad f
(other where clauses involving gradient and gradient "function")
Hier ist eine etwas kompliziertere Version mit Typ-Signaturen, die kompilieren lassen.
{-# LANGUAGE RankNTypes #-}
import Numeric.AD
import Numeric.AD.Internal.Reverse
-- compiles but I can't figure out how to use it in code
grad2 :: (Show a, Num a, Floating a) => (forall s.[Reverse s a] -> Reverse s a) -> [a] -> [a]
grad2 f l = grad f l
-- compiles with the right type, but the resulting gradient is all 0s...
grad2' :: (Show a, Num a, Floating a) => ([a] -> a) -> [a] -> [a]
grad2' f l = grad f' l
where f' = Lift . f . extractAll
-- i've tried using the Reverse constructor with Reverse 0 _, Reverse 1 _, and Reverse 2 _, but those don't yield the correct gradient. Not sure how the modes work
extractAll :: [Reverse t a] -> [a]
extractAll xs = map extract xs
where extract (Lift x) = x -- non-exhaustive pattern match
dist :: (Show a, Num a, Floating a) => [a] -> a
dist [x, y] = sqrt(x^2 + y^2)
-- incorrect output: [0.0, 0.0]
main = putStrLn $ show $ grad2' dist [1,2]
aber ich kann nicht herausfinden, wie die erste Version zu verwenden, grad2
, im Code, weil ich nicht weiß, wie man mit Reverse s a
beschäftigen. Die zweite Version, grad2'
, hat den richtigen Typ, weil ich den internen Konstruktor Lift
verwende, um eine Reverse s a
zu erstellen, aber ich muss nicht verstehen, wie die Interna (speziell der Parameter s
) funktioniert, weil der Ausgabegradient alle 0s ist. Die Verwendung des anderen Konstruktors Reverse
(hier nicht gezeigt) erzeugt ebenfalls den falschen Gradienten.
Alternativ gibt es Beispiele für Bibliotheken/Code, wo Menschen den Code ad
verwendet haben? Ich denke, mein Anwendungsfall ist sehr verbreitet.
Was passiert, wenn Sie timeAndGrad eine Art signiture zur Verfügung stellen? Vielleicht haben Sie auch mehr Glück mit dem Rang-1-Ansatz. – ocharles
Ich habe meine Frage bearbeitet, um eine Typensignatur und einen anderen Ansatz hinzuzufügen (was auch nicht funktioniert). – kye