pracuję z typów danych tego kształtu, używając V
z linear
:Czy mogę uzyskać KnownNat n sugerować KnownNat (n * 3), etc?
type Foo n = V (n * 3) Double -> Double
Mając to ustalone na n
jest bardzo ważne, ponieważ chcę, aby być w stanie zapewnić, że ja przechodząc w prawo liczba elementów podczas kompilacji. To część mojego programu, który działa już dobrze, niezależnie od tego, co tu robię.
Dla każdego KnownNat n
, mogę wygenerować Foo n
spełniając zachowanie, które mój program potrzebuje. Dla celów tej kwestii może być coś głupie jak
mkFoo :: KnownNat (n * 3) => Foo n
mkFoo = sum
lub dla bardziej znaczący przykład, może wygenerować losowy V
o tej samej długości i używać dot
na dwie części. Ograniczenie KnownNat
jest tutaj zbędne, ale w rzeczywistości konieczne jest zrobienie Foo
. Tworzę jeden Foo
i używam go do całego mojego programu (lub z wieloma wejściami), więc to gwarantuje, że za każdym razem, gdy go używam, używam rzeczy o tej samej długości i na rzeczach, które dyktuje struktura Foo
.
I wreszcie, mam funkcję, która sprawia, że wejść do Foo
:
bar :: KnownNat (n * 3) => Proxy n -> [V (n * 3) Double]
poprzeczkę jest rzeczywiście powodem używam n * 3
jako funkcja typu, zamiast po prostu ręcznie ją rozszerza . Powodem jest to, że bar
może wykonać swoją pracę, używając trzech wektorów o długości n
i dołączając je wszystkie razem jako wektor o długości n * 3
. Ponadto, n
jest znacznie bardziej znaczącym parametrem dla funkcji, semantycznie niż n * 3
. To także pozwala mi zabronić niewłaściwych wartości jak n
„s, które nie są wielokrotnością 3, itd
Teraz, zanim wszystko działało w porządku tak długo, jak zdefiniowano synonim typu od początku:
type N = 5
I mogę po prostu przekazać w Proxy :: Proxy N
do bar
i użyć mkFoo :: Foo N
. I wszystko działało dobrze.
-- works fine
doStuff :: [Double]
doStuff = let inps = bar (Proxy :: Proxy N)
in map (mkFoo :: Foo N) inps
Ale teraz chcę, aby móc dostosować N
podczas wykonywania przez załadowanie danych z pliku lub z argumentów wiersza poleceń.
Próbowałem robić to poprzez wywołanie reflectNat
:
doStuff :: Integer -> Double
doStuff n = reflectNat 5 $ \[email protected](Proxy :: Proxy n) ->
let inps = bar (Proxy :: Proxy n)
in map (mkFoo :: Foo n) inps
Ale ... bar
i mkFoo
wymagają KnownNat (n * 3)
, ale reflectNat
po prostu daje mi KnownNat n
.
Czy istnieje sposób, w jaki mogę uogólnić dowód, że reflectNat
daje mi do spełnienia foo
?
Nie, nie możesz. Jeśli możesz podać nieco więcej kontekstu na temat tego, co próbujesz osiągnąć, ktoś może Ci pomóc. – dfeuer
Spróbuj napisać krótką, własnoręcznie napisaną, poprawną (kompilowaną), przykładową (sscce.org), abyśmy mogli spróbować samemu. – Hjulle
@dfeuer dodał konkretne przykłady z tym, co uważam za odpowiednie wyjaśnienia motywacji do decyzji projektowych. dzięki! –