Çalışan bir Hindley-Milner türü çıkarım sistemine sahip küçük bir lambda kalkülüs derleyicisi üzerinde çalışıyorum ve şimdi aynı zamanda Turing'i tamamlamak için yeterli olması gerektiğini anladığım özyinelemeli izinleri de (bağlantılı kodda değil) destekliyorum .
Sorun şu ki, destek listelerini nasıl oluşturacağımı veya bunları destekleyip desteklemediğini bilmiyorum ve bunları kodlamanın bir yolunu bulmam gerekiyor. Yazı sistemine yeni kurallar eklemek zorunda kalmadan bunları tanımlayabilmek istiyorum.
Bir listeyi düşünebilmemin en kolay yolu x
ya null
(ya da boş liste) ya da hem bir hem de bir x
listesini içeren bir çift olarak düşünmektir x
. Ancak bunu yapmak için, ürün ve toplam türleri olduğuna inandığım çiftleri ve / veya tanımları yapabilmem gerekiyor.
Çiftleri şu şekilde tanımlayabilirim:
pair = λabf.fab
first = λp.p(λab.a)
second = λp.p(λab.b)
Yana pair
türünü olurdu a -> (b -> ((a -> (b -> x)) -> x))
, geçtikten sonra, bir, demek int
ve bir string
bu tip bir şey verim ediyorum (int -> (string -> x)) -> x
bir çift gösterimi olacağını, int
ve string
. Burada beni rahatsız eden şey, eğer bu bir çifti temsil ediyorsa, neden mantıklı olarak önermeye eşdeğer değildir ya da öneriyi ima etmez int and string
? Ancak, (((int and string) -> x) -> x)
işlevlere parametre olarak yalnızca ürün türlerine sahip olabileceğim gibi. Bu cevapBu sorunu ele alıyor gibi görünüyor, ancak kullandığı sembollerin ne anlama geldiğini bilmiyorum. Ayrıca, bu bir ürün türünü gerçekten kodlamazsa, yukarıdaki çiftler tanımımla yapamadığım ürün türleriyle yapabileceğim bir şey var mı (n-tuples'ı aynı şekilde tanımlayabileceğimi düşünerek)? Değilse, bu (AFAIK) kavuşumunu sadece ima kullanarak ifade edemeyeceğinizle çelişmez miydi?
Ayrıca, toplam türü ne olacak? Bir şekilde sadece fonksiyon tipini kullanarak kodlayabilir miyim? Öyleyse, bu listeleri tanımlamak için yeterli olur mu? Yoksa tür sistemimi genişletmek zorunda kalmadan listeleri tanımlamanın başka bir yolu var mı? Değilse, mümkün olduğunca basit tutmak istersem ne gibi değişiklikler yapmam gerekir?
Lütfen bir bilgisayar programcısı olduğumu, ancak bir bilgisayar bilimcisi ya da bir matematikçi olmadığımı ve matematik notasyonunu okurken oldukça kötü olduğunu unutmayın.
Düzenleme: Şimdiye kadar uyguladıklarımın teknik adının ne olduğundan emin değilim, ama tüm sahip olduğum temelde yukarıda bağladığım kod, uygulamalar, soyutlamalar ve alınan değişkenler için kuralları kullanan bir kısıtlama oluşturma algoritması Hinley-Milner algoritmasından ve ardından ana türü alan bir birleştirme algoritmasından. Örneğin, ifade \a.a
türü verir a -> a
ve ifade \a.(a a)
gerçekleşen bir kontrol hatası atar. Bunun da ötesinde, tam olarak bir let
kural değil, bu sözde kod gibi özyinelemeli genel işlevleri tanımlamanızı sağlayan aynı etkiye sahip gibi görünen bir işlev vardır:
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.
}
Kod temelde terimin türünü her zamanki gibi alır, ancak birleştirmeden önce, kukla bir türle tanımlanmış işlevin adını tür kapsamına ekler, böylece kendi içinden özyinelemeli olarak kullanılabilir.
Edit 2: İstediğim gibi bir liste tanımlamak için sahip olmadığım özyinelemeli türlere de ihtiyacım olduğunu fark ettim.
let func = \x -> (func x)
) sahip olduğum şeyi alırsanız eminim.