Я працюю над невеликим компілятором обчислення лямбда, який має працюючу систему виводу типу Хіндлі-Мілнера, і тепер також підтримує рекурсивну, давайте (не у зв'язаному коді), що, на мою думку, повинно бути достатньо, щоб зробити Тьюрінг завершеним .
Проблема зараз полягає в тому, що я не маю уявлення, як скласти списки його підтримки чи вони вже підтримують їх, і мені просто потрібно знайти спосіб їх кодування. Я хотів би мати можливість їх визначити без необхідності додавати нові правила до системи типів.
Найпростіший спосіб я уявити список x
- це щось, що є null
(або порожній список), або пара, що містить і an, x
і список x
. Але для цього мені потрібно вміти визначати пари та / або, які, на мою думку, є типом продуктів та сумою.
Здається, я можу так визначити пари:
pair = λabf.fab
first = λp.p(λab.a)
second = λp.p(λab.b)
Оскільки pair
мав би тип a -> (b -> ((a -> (b -> x)) -> x))
, після передачі, скажімо, a int
і a string
, він дасть щось із типом (int -> (string -> x)) -> x
, що було б представленням пари int
та string
. Що мене тут турбує, це те, що якщо це являє собою пару, то чому це логічно не рівнозначно і не передбачає пропозицію int and string
?. Однак це рівнозначно (((int and string) -> x) -> x)
, як ніби я можу мати лише типи продуктів як параметри функцій. Ця відповідьначебто вирішують цю проблему, але я поняття не маю на увазі, що означають символи, які він використовує. Крім того, якщо це дійсно не кодує тип продукту, чи є щось, що я можу зробити з типами продуктів, які я не міг би зробити зі своїм визначенням пар вище (враховуючи, що я також можу визначити n-кортежі однаково)? Якщо ні, чи не суперечить це тому, що ви не можете висловити сполучення (AFAIK), використовуючи лише імплікацію?
А як щодо типу суми? Чи можу я якось кодувати його, використовуючи лише тип функції? Якщо так, то цього буде достатньо для визначення списків? Або, чи є інший спосіб визначення списків, не потребуючи розширення системи мого типу? А якщо ні, то які зміни мені потрібно було б внести, якщо я хочу зробити це максимально просто?
Будь ласка, майте на увазі, що я комп'ютерний програміст, але не інформатик, ні математик і дуже погано читаю математичні позначення.
Редагувати: Я не впевнений, що таке технічне ім'я того, що я реалізував до цього часу, але все, що я маю, - це в основному код, який я зв'язав вище, що є алгоритмом генерації обмежень, який використовує правила для застосувань, абстракцій та змінних. від алгоритму Гінлі-Мілнера, а потім алгоритму об'єднання, який отримує основний тип. Наприклад, вираз \a.a
дасть тип a -> a
, а вираз \a.(a a)
буде видавати помилку перевірки, що виникає. Крім цього, існує не зовсім let
правило, а функція, яка, здається, має той самий ефект, що дозволяє визначати рекурсивні глобальні функції, як цей псевдо-код:
GetTypeOfGlobalFunction(term, globalScope, nameOfFunction)
{
// Here 'globalScope' contains a list of name-value pair where every value is of class 'ClosedType',
// meaning their type will be cloned before unified in the unification algorithm so that they can be used polymorphically
tempType = new TypeVariable() // Assign a dummy type to `tempType`, say, type 'x'.
// The next line creates an scope with everything in 'globalScope' plus the 'nameOfFunction = tempType' name-value pair
tempScope = new Scope(globalScope, nameOfFunction, tempType)
type = TypeOfTerm(term, tempScope) // Calculate the type of the term
Unify(tempType, type)
return type
// After returning, the code outside will create a 'ClosedType' using the returned type and add it to the global scope.
}
Код в основному отримує тип терміна, як зазвичай, але перед об'єднанням він додає назву функції, що визначається з манекеновим типом, у область типу, щоб вона могла використовуватися всередині себе рекурсивно.
Редагувати 2: Я щойно зрозумів, що мені також потрібні рекурсивні типи, яких у мене немає, щоб визначити список, як я хочу.
let func = \x -> (func x)
), ви отримаєте те, що у мене є.