Wyrażenie „algebraiczne” dla typów danych algebraicznych wygląda bardzo sugestywnie dla kogoś z doświadczeniem w matematyce. Pozwól mi wyjaśnić, co mam na myśli.
Po zdefiniowaniu podstawowych typów
- Produkt
•
- Unia
+
- Singel
X
- Jednostka
1
i używając skrótów X²
dla X•X
i 2X
dla X+X
et cetera, możemy następnie zdefiniować wyrażenia algebraiczne dla np. list połączonych
data List a = Nil | Cons a (List a)
↔ L = 1 + X • L
i drzewa binarne:
data Tree a = Nil | Branch a (Tree a) (Tree a)
↔ T = 1 + X • T²
Teraz moim pierwszym instynktem jako matematyka jest zwariowanie z tymi wyrażeniami i próba rozwiązania dla L
i T
. Mógłbym to zrobić poprzez wielokrotne zastępowanie, ale znacznie łatwiejsze jest nadużywanie horroru w notacji i udawanie, że mogę go dowolnie zmieniać. Na przykład dla połączonej listy:
L = 1 + X • L
(1 - X) • L = 1
L = 1 / (1 - X) = 1 + X + X² + X³ + ...
gdzie użyłem rozszerzenia szeregu mocy 1 / (1 - X)
w całkowicie nieuzasadniony sposób, aby uzyskać interesujący wynik, a mianowicie, że L
typ jest albo Nil
zawiera 1 element, albo zawiera 2 elementy, lub 3 itd.
Staje się bardziej interesujący, jeśli robimy to dla drzew binarnych:
T = 1 + X • T²
X • T² - T + 1 = 0
T = (1 - √(1 - 4 • X)) / (2 • X)
T = 1 + X + 2 • X² + 5 • X³ + 14 • X⁴ + ...
ponownie, używając rozszerzenia serii mocy (wykonanego z Wolfram Alpha ). To wyraża nieoczywisty (dla mnie) fakt, że istnieje tylko jedno drzewo binarne z 1 elementem, 2 drzewa binarne z dwoma elementami (drugi element może znajdować się na lewej lub prawej gałęzi), 5 drzew binarnych z trzema elementami itp. .
Więc moje pytanie brzmi - co ja tu robię? Operacje te wydają się nieuzasadnione (co to właściwie jest pierwiastek kwadratowy typu danych algebraicznych?), Ale prowadzą do sensownych wyników. czy iloraz dwóch algebraicznych typów danych ma jakieś znaczenie w informatyce, czy jest to tylko sztuczka notacyjna?
A może, co ciekawsze, czy można rozszerzyć te pomysły? Czy istnieje teoria algebry typów, która pozwala na przykład na dowolne funkcje na typach, czy też typy wymagają reprezentacji szeregów mocy? Jeśli potrafisz zdefiniować klasę funkcji, to czy ich składanie ma jakieś znaczenie?
źródło
Branch x (Branch y Nil Nil) Nil
albo wyglądaBranch x Nil (Branch y Nil Nil)
.undefined
,throw
itp Powinniśmy go używać.Odpowiedzi:
Zrzeczenie się: Wiele z tych rzeczy nie działa całkiem dobrze, gdy bierzesz pod uwagę ⊥, więc rażąco zignoruję to ze względu na prostotę.
Kilka początkowych punktów:
Zauważ, że „unia” nie jest chyba najlepsze określenie dla A + B - to tutaj konkretnie rozłączne unia z dwóch rodzajów, ponieważ obie strony wyróżniają nawet jeśli ich typy są takie same. Co jest warte, bardziej powszechnym terminem jest po prostu „typ sumy”.
Typy singletonów to w rzeczywistości wszystkie typy jednostek. Zachowują się identycznie podczas manipulacji algebraicznych, a co ważniejsze, ilość obecnych informacji jest nadal zachowana.
Prawdopodobnie chcesz również typ zerowy. Haskell zapewnia, że jako
Void
. Nie ma wartości, których typ wynosi zero, podobnie jak jedna wartość, której typ jest jeden.Wciąż brakuje tu jednej ważnej operacji, ale zaraz do niej wrócę.
Jak zapewne zauważyłeś, Haskell ma tendencję do zapożyczania koncepcji z teorii kategorii, a wszystkie powyższe mają bardzo prostą interpretację jako taką:
Biorąc pod uwagę obiekty A i B w Hask , ich iloczyn A × B jest unikalnym (aż do izomorfizmu) typem, który pozwala na dwie projekcje fst : A × B → A i snd : A × B → B, gdzie dany dowolny typ C i funkcje f : C → A, g : C → B można zdefiniować parowanie f &&& g : C → A × B tak, że fst ∘ (f&& g) = f i podobnie dla g . Parametryzacja gwarantuje automatyczne uniwersalne właściwości, a mój mniej subtelny wybór nazw powinien dać ci pomysł.
(&&&)
Operator definiuje sięControl.Arrow
przez sposób.Podwójnym z powyższych jest koprodukt A + B z zastrzykami inl : A → A + B i inr : B → A + B, gdzie biorąc pod uwagę dowolny typ C i funkcje f : A → C, g : B → C, możesz zdefiniuj copairing f ||| g : A + B → C tak, że zachowują się oczywiste równoważności. Ponownie, parametryczność gwarantuje większość trudnych części automatycznie. W tym przypadku są po prostu standardowych iniekcji
Left
iRight
i copairing jest funkcjąeither
.Wiele właściwości typów produktów i sum można wyprowadzić z powyższego. Zauważ, że każdy typ singletonu jest obiektem końcowym Hask, a każdy pusty typ jest obiektem początkowym.
Wracając do wyżej wspomnianej operacji brakującej, w kartezjańskiej zamkniętej kategorii masz obiekty wykładnicze odpowiadające strzałkom tej kategorii. Nasze strzały są funkcjami, nasze obiekty są rodzajami z rodzaju
*
, a rodzajA -> B
rzeczywiście zachowuje się jak B A w kontekście algebraicznej manipulacji typami. Jeśli nie jest oczywiste, dlaczego tak się dzieje, rozważ typBool -> A
. Przy tylko dwóch możliwych wejściach funkcja tego typu jest izomorficzna w stosunku do dwóch wartości typuA
, tj(A, A)
. PonieważMaybe Bool -> A
mamy trzy możliwe dane wejściowe i tak dalej. Zauważ też, że jeśli zmienimy sformułowanie powyższej definicji copairing w celu użycia notacji algebraicznej, otrzymamy tożsamość C A × C B = CA + B .Jeśli chodzi o to, dlaczego to wszystko ma sens - a w szczególności dlaczego użycie rozszerzenia mocy jest uzasadnione - zauważ, że wiele z powyższych odnosi się do „mieszkańców” danego typu (tj. Odrębnych wartości mających ten typ) w kolejności aby zademonstrować zachowanie algebraiczne. Aby wyraźnie przedstawić tę perspektywę:
Typ produktu
(A, B)
reprezentuje wartość dla każdegoA
iB
wzięty niezależnie. Tak więc dla każdej stałej wartościa :: A
istnieje jedna wartość typu(A, B)
dla każdego mieszkańcaB
. Jest to oczywiście produkt kartezjański, a liczba mieszkańców danego rodzaju produktu jest iloczynem liczby mieszkańców czynników.Typ sumy
Either A B
reprezentuje wartość z jednejA
lubB
z wyróżnieniem lewej i prawej gałęzi. Jak wspomniano wcześniej, jest to rozłączny związek, a liczba mieszkańców typu suma jest sumą liczby mieszkańców szczytów.Typ wykładniczy
B -> A
reprezentuje odwzorowanie wartości typuB
na wartości typuA
. Dla każdego ustalonego argumentu można mu przypisaćb :: B
dowolną wartośćA
; wartość typuB -> A
wybiera jedno takie mapowanie dla każdego wejścia, co jest równoważne iloczynowi tylu kopii,A
ileB
ma mieszkańców, stąd potęgowanie.Chociaż początkowo kuszące jest traktowanie typów jako zbiorów, to w rzeczywistości nie działa zbyt dobrze w tym kontekście - mamy rozłączne połączenie, a nie standardowe połączenie zbiorów, nie ma oczywistej interpretacji przecięcia ani wielu innych operacji na zestawach, a my zwykle nie przejmuję się ustawieniem członkostwa (pozostawiając to sprawdzaniu typów).
Z drugiej strony powyższe konstrukcje spędzają dużo czasu na rozmowach o liczeniu mieszkańców, a wyliczenie możliwych wartości danego typu jest tutaj użyteczną koncepcją. To szybko prowadzi nas do kombinatoryki wyliczeniowej , a jeśli zajrzysz do powiązanego artykułu w Wikipedii, zauważysz, że jedną z pierwszych rzeczy, które robi, jest zdefiniowanie „par” i „związków” w dokładnie takim samym sensie, jak typy produktów i sumy na podstawie generując funkcje , robi to samo dla „sekwencji” identycznych z listami Haskella przy użyciu dokładnie tej samej techniki, co ty.
Edycja: Aha, a oto szybki bonus, który moim zdaniem pokazuje uderzająco ten punkt. Wspomniałeś w komentarzu, że dla typu drzewa
T = 1 + T^2
możesz uzyskać tożsamośćT^6 = 1
, co jest oczywiście błędne. Tak jednak sięT^7 = T
dzieje , a biject między drzewami i siedmioma krotkami drzew można zbudować bezpośrednio, por. „Siedem drzew w jednym” Andreasa Blassa .Edycja × 2: Jeśli chodzi o konstrukcję „pochodną typu”, o której mowa w innych odpowiedziach, możesz także polubić ten artykuł tego samego autora, który dalej rozwija ten pomysł, w tym pojęcia podziału i inne ciekawe rzeczy.
źródło
Drzewa binarne są zdefiniowane przez równanie
T=1+XT^2
w semirowaniu typów. Przez konstrukcjęT=(1-sqrt(1-4X))/(2X)
jest zdefiniowane przez to samo równanie w semirowaniu liczb zespolonych. Biorąc pod uwagę, że rozwiązujemy to samo równanie w tej samej klasie struktury algebraicznej, nie powinno dziwić, że widzimy pewne podobieństwa.Problem polega na tym, że gdy rozumujemy wielomiany w semirowaniu liczb zespolonych, zwykle wykorzystujemy fakt, że liczby zespolone tworzą pierścień, a nawet pole, więc używamy operacji takich jak odejmowanie, które nie mają zastosowania do semirowania. Ale często możemy wyeliminować odejmowanie naszych argumentów, jeśli mamy regułę, która pozwala nam anulować z obu stron równania. Jest to coś, co udowodnili Fiore i Leinster, pokazując, że wiele argumentów dotyczących pierścieni można przenieść na półprzezroczystości.
Oznacza to, że wiele wiedzy matematycznej na temat pierścieni można niezawodnie przenieść na typy. W rezultacie niektóre argumenty dotyczące liczb zespolonych lub szeregów potęg (w pierścieniu formalnych szeregów potęg) mogą zostać przeniesione na typy w całkowicie rygorystyczny sposób.
Jednak w tej historii jest coś więcej. To jedno, aby udowodnić, że dwa typy są równe (powiedzmy), pokazując, że dwie serie mocy są równe. Ale możesz także wydedukować informacje o typach, sprawdzając warunki w serii mocy. Nie jestem pewien, jakie powinno być formalne oświadczenie. (Polecam Brent Yorgey za papier na gatunki kombinatorycznych dla niektórych prac, który jest ściśle związany ale gatunki są nie takie same jak typy).
Zdumiewa mnie, że to, co odkryłeś, można rozszerzyć na rachunek różniczkowy. Twierdzenia o rachunku różniczkowym i całkowym można przełożyć na semirowanie typów. W rzeczywistości nawet argumenty dotyczące różnic skończonych mogą zostać przeniesione i okazuje się, że klasyczne twierdzenia z analizy numerycznej mają interpretacje w teorii typów.
Baw się dobrze!
źródło
P = X^2
ma pochodnądP = X + X
, podobnieEither
jak kontekst pary z jednym otworem. To fajnie. Możemy również „zintegrować się”,Either
aby uzyskać parę. Ale jeśli spróbujemy „zintegrować”Maybe
(z typemM = 1 + X
), to musimy mieć coś,\int M = X + X^2 / 2
co jest nonsensowne (co to jest połowa typu?) Czy to oznacza, żeMaybe
nie jest to jeden otwór innego typu?(A,A)
Z dziurą w niej jestA
i trochę mówi, po której stronie jest dziura.A
Sam ma wyróżniającą dziurę wypełnić, dlatego nie można „integrować” go. Rodzaj brakujących informacji w tym przypadku to oczywiście2
.X^2/2
PisałemWydaje się, że wszystko, co robisz, to rozszerzanie relacji powtarzalności.
A ponieważ reguły operacji na typach działają podobnie jak reguły operacji arytmetycznych, możesz użyć środków algebraicznych, aby pomóc Ci dowiedzieć się, jak rozwinąć relację powtarzalności (ponieważ nie jest to oczywiste).
źródło
X
jest to element liczb rzeczywistych, do prawdziwego stwierdzenia o typach, a ponadto, gdzie odpowiada korespondencja (współczynnikn
wyrazu stopnia) <=> (liczba typówn
elementów trzymających ) pochodzą?T = 1 + T^2
) mogę wywnioskowaćT^6 = 1
(tzn. Rozwiązaniax^2 - x + 1 = 0
są szóstym rdzeniem jedności), ale wyraźnie nie jest prawdą, że typ produktu składający się z sześciu drzew dwójkowych jest równoważny jednostce()
.T^7
iT
. por. arxiv.org/abs/math/9405205L = 1 + X * L
to lepiej być ten sam, który pojawia się po serii poszerzyć poprzez konsystencji. W przeciwnym razie możesz uruchomić wynik wstecz, aby uzyskać coś fałszywego na temat reali.Nie mam pełnej odpowiedzi, ale te manipulacje zwykle „po prostu działają”. Odpowiednim referatem mogą być obiekty kategorii jako liczby zespolone według Fiore'a i Leinstera - natknąłem się na to podczas czytania bloga sigfpe na podobny temat ; reszta tego bloga to kopalnia złota dla podobnych pomysłów i warto to sprawdzić!
Nawiasem mówiąc, możesz także różnicować typy danych - dzięki temu otrzymasz odpowiedni zamek błyskawiczny dla typu danych!
źródło
Algebra procesów komunikacyjnych (ACP) dotyczy podobnych rodzajów wyrażeń dla procesów. Oferuje dodawanie i mnożenie jako operatorów wyboru i sekwencji, wraz z powiązanymi elementami neutralnymi. Na ich podstawie istnieją operatory dla innych konstrukcji, takich jak równoległość i zakłócenia. Zobacz http://en.wikipedia.org/wiki/Algebra_of_Communicating_Processes . Istnieje również artykuł online o nazwie „Krótka historia algebry procesów”.
Pracuję nad rozszerzeniem języków programowania za pomocą ACP. W kwietniu ubiegłego roku przedstawiłem artykuł badawczy na Scala Days 2012, dostępny pod adresem http://code.google.com/p/subscript/
Na konferencji zademonstrowałem debuger z równoległą rekursywną specyfikacją torby:
Torba = A; (Torba i a)
gdzie A i stanowisko dla działań wejściowych i wyjściowych; średnik i ampersand oznaczają sekwencję i równoległość. Zobacz wideo na SkillsMatter, dostępne z poprzedniego linku.
Specyfikacja torby bardziej porównywalna do
L = 1 + X • L
byłoby
B = 1 + X&B
ACP definiuje równoległość pod względem wyboru i sekwencji za pomocą aksjomatów; zobacz artykuł w Wikipedii. Zastanawiam się, po co byłaby analogia torby
L = 1 / (1-X)
Programowanie w stylu ACP jest przydatne dla parserów tekstu i kontrolerów GUI. Specyfikacje takie jak
searchCommand = kliknięty (searchButton) + klawisz (Enter)
cancelCommand = kliknięty (cancelButton) + klawisz (Escape)
można zapisać bardziej zwięźle, czyniąc dwa udoskonalenia „klikniętymi” i „kluczowymi” w sposób dorozumiany (jak to, co Scala zezwala na funkcje). Dlatego możemy napisać:
searchCommand = searchButton + Enter
cancelCommand = cancelButton + Escape
Prawa strona zawiera teraz operandy, które są danymi, a nie procesami. Na tym poziomie nie trzeba wiedzieć, jakie ukryte udoskonalenia przekształcą te operandy w procesy; niekoniecznie udoskonaliliby się w działania wejściowe; zastosowanie miałyby również działania wyjściowe, np. w specyfikacji robota testowego.
Procesy uzyskują w ten sposób dane jako elementy towarzyszące; dlatego kojarzę termin „algebra pozycji”.
źródło
Serie rachunku różniczkowego i całkowego z typami
Oto kolejny drobny dodatek - kombinatoryczny wgląd w to, dlaczego współczynniki w rozwinięciu szeregu powinny „działać”, w szczególności skupiając się na szeregach, które można uzyskać za pomocą podejścia Taylora-Maclaurina z rachunku różniczkowego. Uwaga: przykładowe rozszerzenie serii manipulowanego typu listy to seria Maclaurin.
Ponieważ inne odpowiedzi i komentarze dotyczą zachowania wyrażeń typu algebraicznego (sum, produktów i wykładników), odpowiedź ta ominie ten szczegół i skoncentruje się na rachunku typu.
W tej odpowiedzi możesz zauważyć odwrócone przecinki, które powodują ciężkie podnoszenie. Są dwa powody:
Definicja serii Maclaurin
Seria Maclaurin funkcji
f : ℝ → ℝ
jest zdefiniowana jakogdzie
f⁽ⁿ⁾
oznaczan
th pochodnąf
.Aby móc zrozumieć serię Maclaurin interpretowaną z typami, musimy zrozumieć, w jaki sposób możemy interpretować trzy rzeczy w kontekście typów:
0
(1/n!)
i okazuje się, że te koncepcje z analizy mają odpowiednie odpowiedniki w świecie czcionek.
Co rozumiem przez „odpowiedni odpowiednik”? Powinien mieć smak izomorfizmu - jeśli możemy zachować prawdę w obu kierunkach, fakty, które można wywnioskować w jednym kontekście, można przenieść do drugiego.
Rachunek z typami
Co więc oznacza pochodna wyrażenia typu? Okazuje się, że dla dużej i dobrze wychowanej („różnicowalnej”) klasy wyrażeń typu i funktorów istnieje naturalna operacja, która zachowuje się na tyle podobnie, aby być odpowiednią interpretacją!
Aby zepsuć punktację, operacja analogiczna do różnicowania polega na tworzeniu „kontekstów z jednym otworem”. Jest to doskonałe miejsce do dalszego rozwijania tego konkretnego punktu, ale podstawową koncepcją kontekstu z jednym otworem (
da/dx
) jest to, że reprezentuje on wynik wyodrębnienia pojedynczego podelementu określonego typu (x
) z terminu (typua
), zachowując wszystkie inne informacje, w tym niezbędne do ustalenia pierwotnej lokalizacji podelementu. Na przykład, jednym ze sposobów przedstawienia kontekstu z jednym otworem dla listy są dwie listy: jedna dla elementów, które pojawiły się przed wyodrębnioną, i jedna dla elementów, które pojawiły się później.Motywacja do identyfikacji tej operacji z różnicowaniem wynika z następujących obserwacji. Piszemy,
da/dx
aby oznaczać typ kontekstów z jednym otworem dla typua
z otworem typux
.Tu
1
i0
reprezentują typy z dokładnie jednym i dokładnie zerowy mieszkańców, odpowiednio, a+
i×
reprezentują typy sum i towarowych, jak zwykle.f
ig
są używane do reprezentowania funkcji typu lub[f(x)/a]
form wyrażeń typu, i oznaczają operację podstawieniaf(x)
każdegoa
w poprzednim wyrażeniu.Można to zapisać w stylu bez punktów, pisząc,
f'
że oznacza funkcję pochodną funkcji typuf
, a zatem:co może być lepsze.
Uwaga: równości mogą być rygorystyczne i dokładne, jeśli zdefiniujemy pochodne za pomocą klas typów i funktorów izomorfizmu.
Teraz zauważamy w szczególności, że reguły w rachunku dotyczące algebraicznych operacji dodawania, mnożenia i kompozycji (często nazywane regułami sumy, iloczynu i łańcucha) są odzwierciedlone właśnie przez operację „robienia dziury”. Ponadto, podstawowe przypadki „robienia dziury” w stałym wyrażeniu lub
x
sam termin zachowują się również jako różnicowanie, więc przez indukcję uzyskujemy zachowanie podobne do różnicowania dla wszystkich wyrażeń typu algebraicznego.Teraz możemy zinterpretować różnicowanie, co oznacza
n
„pochodna” wyrażenia typudⁿe/dxⁿ
? Jest to typ reprezentującyn
konteksty -place: terminy, które po „wypełnieniu”n
terminami typux
dają wynike
. Jest jeszcze jedna kluczowa obserwacja związana z(1/n!)
późniejszym.Niezmienna część funktora typu: zastosowanie funkcji do 0
W
0
świecie typów mamy już interpretację : pusty typ bez członków. Co to znaczy, z kombinatorycznego punktu widzenia, zastosować do niej funkcję typu? Mówiąc bardziej konkretnie, załóżmy, żef
jest funkcją typu, jak tof(0)
wygląda? Cóż, z pewnością nie mamy dostępu do niczego takiego0
, więc wszelkie konstrukcjef(x)
wymagające tegox
są niedostępne. Pozostały tylko te terminy, które są dostępne pod ich nieobecność, które możemy nazwać „niezmienną” lub „stałą” częścią typu.Dla wyraźnego przykładu weź
Maybe
funktor, który można przedstawić algebraicznie jakox ↦ 1 + x
. Kiedy to zastosujemy0
, otrzymamy1 + 0
- to jest tak1
: jedyną możliwą wartością jestNone
wartość. Podobnie dla listy otrzymujemy tylko termin odpowiadający pustej liście.Kiedy przywracamy go i interpretujemy typ
f(0)
jako liczbę, można go traktować jako liczbę, ile terminów typuf(x)
(dla dowolnegox
) można uzyskać bez dostępu dox
: to znaczy liczby terminów „pustych” .Podsumowując: pełna interpretacja serii Maclaurin
Obawiam się, że nie mogę wymyślić odpowiedniej bezpośredniej interpretacji
(1/n!)
jako typu.Jeśli weźmiemy pod uwagę typ
f⁽ⁿ⁾(0)
w świetle powyższego, widzimy, że można go interpretować jako typn
kontekstów -place dla terminu typu,f(x)
który jeszcze nie zawierax
- to znaczy, kiedy „integrujemy” jen
razy , wynikowy termin ma dokładnien
x
s, nie więcej, nie mniej. Zatem interpretacja typuf⁽ⁿ⁾(0)
jako liczby (jak we współczynnikach z serii Maclaurinf
) jest po prostu zliczeniem liczby takichn
kontekstów pustych miejsc. Jesteśmy już prawie na miejscu!Ale gdzie się
(1/n!)
kończy? Badanie procesu różnicowania typu pokazuje nam, że po wielokrotnym zastosowaniu zachowuje „porządek” wydobywania subtermów. Weźmy na przykład pojęcie(x₀, x₁)
typux × x
i operację „wykonania w nim dziury” dwa razy. Otrzymujemy obie sekwencjemimo że oba pochodzą z tego samego terminu, ponieważ istnieją
2! = 2
sposoby na pobranie dwóch elementów z dwóch, zachowując porządek. Ogólnie istniejąn!
sposoby na pobranien
elementówn
. Aby więc policzyć liczbę konfiguracji typu funktora, które mająn
elementy, musimy policzyć typf⁽ⁿ⁾(0)
i podzielićn!
, dokładnie tak , jak w przypadku współczynników szeregu Maclaurin.Tak więc dzielenie przez
n!
okazuje się być po prostu interpretowalne jak samo.Ostatnie przemyślenia: definicje „rekurencyjne” i analityczność
Po pierwsze, niektóre spostrzeżenia:
Ponieważ mamy regułę łańcucha, możemy zastosować niejawne różnicowanie , jeśli sformalizujemy pochodne typu jako klasy izomorficzne. Ale ukryte różnicowanie nie wymaga żadnych manewrów obcych, takich jak odejmowanie lub dzielenie! Możemy więc użyć go do analizy definicji typów rekurencyjnych. Oto przykład naszej listy
i wtedy możemy ocenić
aby uzyskać współczynnik z
X¹
serii Maclaurin.Ale ponieważ jesteśmy przekonani, że te wyrażenia są rzeczywiście ściśle „różnicowalne”, choćby pośrednio, i ponieważ mamy korespondencję z funkcjami ℝ → ℝ, gdzie pochodne są z pewnością wyjątkowe, możemy być pewni, że nawet jeśli otrzymamy wartości za pomocą „ nielegalne ”, wynik jest prawidłowy.
Podobnie, aby użyć drugiej obserwacji, ze względu na zgodność (czy jest to homomorfizm?) Z funkcjami ℝ → ℝ, wiemy, że pod warunkiem, że jesteśmy przekonani, że funkcja ma szereg Maclaurina, jeśli możemy znaleźć dowolną serię na wszystkie powyższe zasady można zastosować, aby były rygorystyczne.
Jeśli chodzi o twoje pytanie dotyczące kompozycji funkcji, przypuszczam, że reguła łańcucha zapewnia częściową odpowiedź.
Nie jestem pewien, do ilu ADT w stylu Haskella to dotyczy, ale podejrzewam, że jest ich wiele, jeśli nie wszystkie. Odkryłem naprawdę cudowny dowód na ten fakt, ale ten margines jest zbyt mały, aby go pomieścić ...
Z pewnością jest to tylko jeden sposób, aby dowiedzieć się, co się tu dzieje i prawdopodobnie istnieje wiele innych sposobów.
Podsumowanie: TL; DR
0
„puste” warunki dla tego funktora.źródło
Teoria typów zależnych i funkcje typu „dowolne”
Moja pierwsza odpowiedź na to pytanie była pełna pojęć, mało szczegółów i zastanawiała się nad pytaniem: „co się dzieje?”; ta odpowiedź będzie taka sama, ale skoncentrowana na pytaniu „czy możemy uzyskać funkcje dowolnego typu?”.
Jednym rozszerzeniem algebraicznych operacji sumy i iloczynu są tak zwane „duże operatory”, które reprezentują sumę i iloczyn sekwencji (lub bardziej ogólnie, sumę i iloczyn funkcji w domenie), zwykle zapisywane
Σ
iΠ
odpowiednio. Zobacz zapis Sigma .Więc suma
może być napisane
gdzie
a
jest na przykład sekwencja liczb rzeczywistych. Produkt byłby reprezentowany podobnie zΠ
zamiastΣ
.Kiedy patrzysz z dystansu, ten rodzaj wyrażenia przypomina bardzo „dowolną” funkcję
X
; jesteśmy oczywiście ograniczeni do wyrażalnych szeregów i związanych z nimi funkcji analitycznych. Czy jest to kandydat na reprezentację w teorii typów? Zdecydowanie!Klasą teorii typów, które mają bezpośrednie przedstawienie tych wyrażeń, jest klasa teorii typów „zależnych”: teorie z typami zależnymi. Oczywiście mamy terminy zależne od terminów, w językach takich jak Haskell z funkcjami typu i kwantyfikacją typów, terminy i typy zależne od typów. W ustawieniu zależnym dodatkowo mamy typy zależne od warunków. Haskell nie jest językiem zależnym od typu, chociaż wiele funkcji typów zależnych można symulować przez nieco torturowanie tego języka .
Curry-Howard i typy zależne
„Izomorfizm Curry'ego-Howarda” rozpoczął życie jako spostrzeżenie, że terminy i reguły oceniania typów rachunku lambda po prostu wpisanego dokładnie odpowiadają naturalnej dedukcji (sformułowanej przez Gentzena) zastosowanej do intuicyjnej logiki zdań, a typy zajmują miejsce zdań oraz warunki zastępujące dowody, mimo że oba zostały niezależnie wynalezione / odkryte. Od tego czasu jest to ogromne źródło inspiracji dla teoretyków typów. Jedną z najbardziej oczywistych rzeczy do rozważenia jest to, czy i jak tę korespondencję dla logiki zdań można rozszerzyć na logikę predykatu lub wyższego rzędu. Teorie typu zależnego początkowo powstały z tej drogi eksploracji.
Aby zapoznać się z wprowadzeniem do izomorfizmu Curry'ego-Howarda dla rachunku zwykłego rachunku lambda, zobacz tutaj . Na przykład, jeśli chcemy udowodnić
A ∧ B
, musimyA
udowodnićB
; dowód łączony to po prostu para dowodów: po jednym dla każdego spójnika.W odliczeniu naturalnym:
i w prostym typie rachunku lambda:
Podobne zależności istnieją dla
∨
typów sum i typów→
oraz typów funkcji i różnych reguł eliminacji.Twierdzenie nie do udowodnienia (intuicyjnie fałszywe) odpowiada typowi niezamieszkanemu.
Mając na uwadze analogię typów jako zdania logiczne, możemy zacząć zastanawiać się, jak modelować predykaty w świecie typów. Istnieje wiele sposobów sformalizowania tego (patrz wprowadzenie do Intuitionistycznej teorii typów Martina-Löfa dla powszechnie stosowanego standardu), ale abstrakcyjne podejście zwykle zauważa, że predykat jest jak zdanie z zmiennymi dowolnymi lub, alternatywnie, funkcja przyjmująca warunki do zdań. Jeśli pozwolimy, aby wyrażenia typu zawierały terminy, wówczas leczenie w stylu rachunku lambda natychmiast stanie się możliwe!
Biorąc pod uwagę tylko konstruktywne dowody, co stanowi dowód
∀x ∈ X.P(x)
? Możemy myśleć o tym jako o funkcji dowodowej, przyjmując warunki (x
) do dowodów odpowiadających im zdań (P(x)
). Tak Członkowie (dowodów) typu (propozycja)∀x : X.P(x)
są zależne od funkcji „”, który dla każdegox
wX
dają pojęcie typuP(x)
.Co
∃x ∈ X.P(x)
? Musimy każdy członekX
,x
wraz z dowodemP(x)
. Tak członków (dowodów) typu (propozycja)∃x : X.P(x)
są „pary utrzymaniu”: wybitnym określeniex
sięX
, wraz ze względu na ich rodzajP(x)
.Notacja: użyję
dla rzeczywistych wypowiedzi na temat członków klasy
X
, orazdla wyrażeń typu odpowiadających uniwersalnej kwantyfikacji nad typem
X
. Podobnie dla∃
.Uwagi kombinatoryczne: produkty i sumy
Oprócz korespondencji typów Curry'ego-Howarda z twierdzeniami, mamy kombinatoryczną zgodność typów algebraicznych z liczbami i funkcjami, co jest głównym punktem tego pytania. Na szczęście można to rozszerzyć na typy zależne przedstawione powyżej!
Użyję notacji modułu
reprezentowanie „rozmiaru” typu
A
, wyraźne powiązanie przedstawione w pytaniu między typami i liczbami. Zauważ, że jest to koncepcja poza teorią; Nie twierdzę, że w języku musi istnieć taki operator.Policzmy możliwe (całkowicie zredukowane, kanoniczne) elementy typu
który jest rodzajem funkcji zależnych uwzględniających warunki
x
typuX
do warunków typuP(x)
. Każda taka funkcja musi mieć dane wyjściowe dla każdego terminuX
, a dane wyjściowe muszą być określonego typu. Dla każdegox
INX
, to daje to|P(x)|
„wybory” na wyjściu.Punktem wyjścia jest
co oczywiście nie czyni ogromne wiele sensu, jeśli
X
jestIO ()
, ale ma zastosowanie do algebraicznych typów.Podobnie termin typu
Jest to typ par
(x, p)
zp : P(x)
, więc biorąc pod uwagę każdyx
wX
możemy skonstruować odpowiednią parę z jakiegokolwiek członkaP(x)
, dając|P(x)|
"wyborów.W związku z tym,
z tymi samymi zastrzeżeniami.
Uzasadnia to powszechną notację typów zależnych w teoriach za pomocą symboli
Π
iΣ
, i rzeczywiście, wiele teorii zaciera rozróżnienie między „dla wszystkich” i „produktem” oraz między „jest” i „sumą”, ze względu na wyżej wspomniane korespondencje.Zbliżamy się!
Wektory: reprezentujące krotki zależne
Czy możemy teraz zakodować wyrażenia numeryczne takie jak
jako wyrażenia typu?
Nie do końca. Chociaż możemy nieformalnie rozważyć znaczenie wyrażeń takich jak
Xⁿ
w Haskell, gdzieX
jest typ in
liczba naturalna, jest to nadużycie zapisu; Jest to wyrażenie typu zawierający numer: wyraźnie nie poprawny wyraz.Z drugiej strony, w przypadku typów zależnych na zdjęciu, typy zawierające liczby są właśnie tym celem; w rzeczywistości zależne krotki lub „wektory” są bardzo często cytowanym przykładem tego, w jaki sposób typy zależne mogą zapewnić pragmatyczne bezpieczeństwo na poziomie typu dla operacji takich jak dostęp do listy . Wektor jest tylko listą wraz z informacją na temat typu dotyczącą jego długości: dokładnie tym, czego szukamy dla wyrażeń typu
Xⁿ
.Na czas trwania tej odpowiedzi pozwól
być typem
n
wektorów długościX
wartości -type.Technicznie
n
jest to, zamiast rzeczywistej liczby naturalnej, reprezentacja w systemie liczby naturalnej. Możemy reprezentować liczby naturalne (Nat
) w stylu Peano jako zero (0
) lub następcę (S
) innej liczby naturalnej, in ∈ ℕ
piszę,˻n˼
aby oznaczać termin, wNat
którym reprezentujen
. Na przykład˻3˼
jestS (S (S 0))
.Następnie mamy
dla każdego
n ∈ ℕ
.Typy nat: promowanie ℕ haseł do typów
Teraz możemy zakodować wyrażenia takie jak
jako typy. To szczególne wyrażenie dałoby początek typowi, który jest oczywiście izomorficzny z typem list
X
, jak określono w pytaniu. (Nie tylko to, ale z teoretycznego punktu widzenia funkcja typu - która jest funktorem - biorącX
pod uwagę powyższy typ jest naturalnie izomorficzna w stosunku do funktora List.)Ostatnim elementem układanki dla „arbitralnych” funkcji jest sposób kodowania
wyrażenia jak
abyśmy mogli zastosować dowolne współczynniki do szeregu mocy.
Rozumiemy już zgodność typów algebraicznych z liczbami, co pozwala nam mapować typy na liczby i funkcje typów na funkcje numeryczne. Możemy też iść w drugą stronę! - biorąc liczbę naturalną, istnieje oczywiście możliwy do zdefiniowania typ algebraiczny z tak wieloma członami terminowymi, niezależnie od tego, czy mamy typy zależne, czy nie. Możemy to łatwo udowodnić poza teorią typów przez indukcję. Potrzebujemy sposobu mapowania liczb naturalnych na typy wewnątrz systemu.
Przyjemną realizacją jest to, że gdy mamy typy zależne, dowody indukcyjne i konstrukcyjne rekurencyjne stają się bardzo podobne - w rzeczywistości są one takie same w wielu teoriach. Skoro możemy przez indukcję udowodnić, że istnieją typy, które spełniają nasze potrzeby, czy nie powinniśmy być w stanie je zbudować?
Istnieje kilka sposobów reprezentowania typów na poziomie terminu. Posłużę się tutaj wyimaginowaną notacją haskalijską
*
dla wszechświata typów, który zwykle uważany jest za typ w zależności od niego. 1Podobnie, istnieje co najmniej tyle sposobów na zanotowanie „
ℕ
eliminacji”, ile jest zależnych teorii typów. Użyję notacji pasującej do wzoru Haskellisha.Musimy mapowanie,
α
odNat
celu*
, z właściwościąWystępuje następująca pseudodefinicja.
Widzimy więc, że działanie
α
zwierciadła odzwierciedla zachowanie następcyS
, czyniąc z niego rodzaj homomorfizmu.Successor
jest funkcją typu, która „dodaje jedną” do liczby elementów typu; to znaczy|Successor a| = 1 + |a|
dla każdegoa
o określonym rozmiarze.Na przykład
α ˻4˼
(który jestα (S (S (S (S 0))))
) jesta warunki tego typu to
daje nam dokładnie cztery elementy:
|α ˻4˼| = 4
.Podobnie dla każdego
n ∈ ℕ
mamyjako wymagane.
*
byli zwykłymi przedstawicielami typów, a operacja jest zapewniona jako jawne odwzorowanie terminów typów*
na powiązane z nimi typy. Inne teorie pozwalają, aby same dosłowne typy były jednostkami na poziomie terminowym.Funkcje „arbitralne”?
Teraz mamy aparat do wyrażenia w pełni ogólnej serii mocy jako typu!
Serie
staje się typem
gdzie
˻f˼ : Nat → Nat
jest odpowiednia reprezentacja w języku funkcjif
. Możemy to zobaczyć w następujący sposób.Jak to „arbitralne”? Metodą tą ograniczamy się nie tylko do współczynników całkowitych, ale także do liczb naturalnych. Poza tym,
f
może być cokolwiek, biorąc pod uwagę język Turing Complete z typami zależnymi, możemy reprezentować dowolną funkcję analityczną o współczynnikach liczb naturalnych.Nie badałem interakcji tego z, na przykład, przypadkiem przedstawionym w pytaniu
List X ≅ 1/(1 - X)
lub jaki możliwy sens takie negatywne i niecałkowate „typy” mogą mieć w tym kontekście.Mam nadzieję, że ta odpowiedź w jakiś sposób pozwoli zbadać, jak daleko możemy posunąć się z funkcjami dowolnego typu.
źródło