Osiągam niewielki sukces, owijając głowę podstawowymi instalacjami typów z pakietu ad
. Na przykład, następujący działa perfekcyjnie:Dopuszczalne typy w funkcjach Numeric.AD
import Numeric.AD
ex :: Num a => [a] -> a
ex [x, y] = x + 2*y
> grad ex [1.0, 1.0]
[1.0, 2.0]
gdzie grad
ma typ:
grad
:: (Num a, Traversable f) =>
(forall (s :: * -> *). Mode s => f (AD s a) -> AD s a)
-> f a -> f a
Gdybym zmienić podpis typu z ex
do [Double] -> Double
i spróbuj to samo, mam
Couldn't match expected type `AD s a0' with actual type `Double'
Expected type: f0 (AD s a0) -> AD s a0
Actual type: [Double] -> Double
To samo zachowanie występuje podczas zastępowania Double
konstruktorem pozornie dowolnego typu z rodzajem *
, która tworzy instancję Num
.
Gdy Traversable f
jest na liście, pierwszy argument grad
musi typu [AD s a] -> AD s a
przez pewien dopuszczalny Mode
- przykład Reverse
. Ale oczywiście użytkownik grad
nie musi zajmować się bezpośrednio konstruktorem AD
lub . Zaglądanie do tych wewnętrznych elementów pozostawiło mnie trochę zagubionego; w szczególności nie mogę podążać ścieżką rodzaju/typu do różnicy między używaniem Num a => [a] -> a
i [Double] -> Double
.
Dlaczego podpis typu [Double] -> Double
powoduje problemy z grad
? A jeśli chodzi o zwykłe stare wykorzystanie biblioteki: czy jest jakiś sposób na użycie wersji [Double] -> Double
ex
, czy jest to wersja polimorficzna?
(tytuł zainspirowany this similar question)
Ahhhh ok, więc 'AD' jest instancją' Num'. Nie zauważyłem tego na liście instancji, ale widzę to teraz. – jtobin
Ponadto, jeśli masz jakieś stałe leżące wokół jako Doubles, powiedzmy, w innych strukturach danych, być może będziesz musiał użyć Numeric.AD.Types.lift lub innych kombinatorów w Trybie, aby mieć interakcję z Twoimi AD Podwójne argumenty i wynik . –