Pracuję nad kompilatorem dla języka konkatenatywnego i chciałbym dodać obsługę wnioskowania typu. Rozumiem Hindleya-Milnera, ale nauczyłem się teorii typów, więc nie jestem pewien, jak ją dostosować. Czy następujący system jest dźwiękowy i można go w sposób zdecydowanie wywnioskować?
Termin jest literałem, kompozycją terminów, cytatem terminu lub prymitywem.
Wszystkie terminy oznaczają funkcje. Dla dwóch funkcji i e 2 , e 1 , to znaczy zestawienie oznacza skład odwrotny. Literały oznaczają funkcje niladyczne.
Terminy inne niż skład mają podstawowe zasady dotyczące typów:
Szczególnie nie ma zasad stosowania, ponieważ brakuje im języków konkatenatywnych.
Typ jest literałem, zmienną typu lub funkcją od stosów do stosów, gdzie stos jest zdefiniowany jako krotka zagnieżdżona z prawej strony. Wszystkie funkcje są domyślnie polimorficzne w odniesieniu do „reszty stosu”.
To pierwsza rzecz, która wydaje się podejrzana, ale nie wiem dokładnie, co jest z nią nie tak.
Aby pomóc czytelności i obniżyć nawiasach, będę zakładać, że w schematach typów. Użyję również dużej litery do zmiennej oznaczającej stos, a nie do pojedynczej wartości.
Istnieje sześć prymitywów. Pierwsze pięć jest dość nieszkodliwe. dup
przyjmuje najwyższą wartość i tworzy dwie jej kopie. swap
zmienia kolejność dwóch najwyższych wartości. pop
odrzuca najwyższą wartość. quote
przyjmuje wartość i tworzy cytat (funkcję), który ją zwraca. apply
stosuje ofertę do stosu.
Ostatni kombinator compose
powinien wziąć dwa cytaty i zwrócić rodzaj ich konkatenacji, czyli . W statycznie typowanym języku konkatenatywnymCattypjest bardzo prosty.compose
Jednak ten typ jest zbyt restrykcyjny: wymaga, aby produkcja pierwszej funkcji dokładnie odpowiadała zużyciu drugiej. W rzeczywistości musisz założyć różne typy, a następnie je zunifikować. Ale jak byś napisał ten typ?
Jeśli pozwolisz oznaczać różnicę dwóch typów, to myślę, że możesz napisać typ poprawnie.compose
Jest wciąż stosunkowo prosta: compose
wykonuje funkcję i jeden f 2 : D → E . Jego wynik zużywa B na szczycie zużycia f 2 niewyprodukowanego przez f 1 , i daje D na szczycie produkcji f 1 niewykorzystanego przez f 2 . Daje to regułę dla zwykłego składu.
Jednak nie wiem, czy ta hipotetyczna rzeczywistości coś odpowiada, i gonię ją w kółko na tyle długo, że myślę, że źle skręciłem. Czy może to być zwykła różnica krotek?
Is there something horribly broken about this that I’m not seeing, or am I on something like the right track? (I’ve probably quantified some of this stuff wrongly and would appreciate fixes in that area as well.)
compose
is too restrictive? I have the impression that this is fine like this. (e.g. the restriction could be handled by unification like for application in like in the λ-calculus)
twice
defined as dup compose apply
, which takes a quotation and applies it twice. [1 +] twice
is fine: you’re composing two functions of type . But [pop] twice
is not: if , the problem is that , so the expression is disallowed even though it ought to be valid and have type . The solution is of course to put the qualifier in the right place, but I’m mainly wondering how to actually write the type of compose
without some circular definition.