Statik olarak yazılmış tam bir Lisp varyantı mümkün müdür?


107

Statik olarak yazılmış tam bir Lisp varyantı mümkün müdür? Böyle bir şeyin var olması mantıklı mı? Bir Lisp dilinin erdemlerinden birinin, tanımının basitliği olduğuna inanıyorum. Statik yazım bu temel prensibi tehlikeye atar mı?


10
Lisp'in serbest biçimli makrolarını seviyorum, ancak Haskell'in tür sisteminin sağlamlığını seviyorum. Statik olarak yazılmış bir Lisp'in neye benzediğini görmek isterim.
mcandre

4
İyi soru! Shenlanguage.org'un bunu yaptığına inanıyorum . Daha yaygın olmasını dilerdim.
Hamish Grubijan


Haskell ile sembolik hesaplamayı nasıl yaparsınız? ('x' (= (+ xy) (* xy))) çöz. Eğer onu bir dizgeye koyarsanız, kontrol yoktur (kontrol eklemek için makroları kullanabilen Lisp'in aksine). Cebirsel veri türleri veya listeleri kullanırsanız ... Çok ayrıntılı olacaktır: çözüm (Sym "x") (Eq (Artı (Sym "x") (Sym "y")) (Mult (Sym "x") (Sym "y")))
aoeu256

Yanıtlar:


57

Evet, çok olasıdır, ancak standart HM tarzı bir sistem genellikle çoğu deyimsel Lisp / Scheme kodu için yanlış seçimdir. Statik yazımla "Tam Lisp" (aslında Scheme gibi) olan yeni bir dil için Typed Racket'e bakın .


1
Buradaki sorun, yazılmış bir raket programının tüm kaynak kodunu oluşturan listenin türü nedir?
Zorf

18
Bu genellikle olur Sexpr.
Eli Barzilay

Ama sonra coerce :: a->beval açısından yazabilirim . Tip güvenliği nerede?
ssice

2
@ssice: Tiplenmemiş bir işlevi kullandığınızda eval, ortaya çıkan şeyi görmek için sonucu test etmeniz gerekir, bu da Typed Racked'de yeni bir şey değildir ( Stringve birleşim türünü alan bir işlevle aynı anlaşma Number). Örtülü bir yolu bu olduğunu görmek için olabilir yapılabilir o gerçektir olabilir yazıp bir HM-statik-daktilo dilde bir dinamik olarak yazılmış bir dil kullanırlar.
Eli Barzilay

37

İstediğiniz tek şey, Lisp'e benzeyen statik olarak yazılmış bir dil olsaydı , dilinizi temsil eden soyut bir sözdizimi ağacı tanımlayarak ve ardından bu AST'yi S-ifadelerine eşleyerek bunu oldukça kolay bir şekilde yapabilirsiniz. Ancak sonuca Lisp diyeceğimi sanmıyorum.

Sözdiziminin yanı sıra aslında Lisp-y özelliklerine sahip bir şey istiyorsanız, bunu statik olarak yazılmış bir dille yapmak mümkündür. Bununla birlikte, Lisp'in çok kullanışlı statik yazmayı çıkarması zor olan birçok özelliği vardır. Göstermek için , Lisp'in birincil yapı taşını oluşturan eksiler adı verilen liste yapısının kendisine bir göz atalım .

Eksileri bir liste olarak adlandırmak, bir liste (1 2 3)gibi görünse de, biraz yanlış bir isim. Örneğin, C ++ 'ın std::listveya Haskell'in listesi gibi statik olarak yazılmış bir listeyle hiç karşılaştırılamaz . Bunlar, tüm hücrelerin aynı türden olduğu tek boyutlu bağlantılı listelerdir. Lisp mutlu bir şekilde izin verir (1 "abc" #\d 'foo). Ayrıca, statik tipli listelerinizi liste listelerini kapsayacak şekilde genişletseniz bile, bu nesnelerin türü listedeki her öğenin bir alt liste olmasını gerektirir . Nasıl temsil edersin((1 2) 3 4)Onlarda ?

Lisp, yaprakları (atomları) ve dalları (eksileri) olan ikili bir ağaç oluşturur. Dahası, böyle bir ağacın yaprakları herhangi bir atomik (eksersiz) Lisp türü içerebilir! Bu yapının esnekliği, Lisp'i sembolik hesaplamayı, AST'leri işlemede ve Lisp kodunu dönüştürmede bu kadar iyi yapan şeydir!

Öyleyse, statik olarak yazılmış bir dilde böyle bir yapıyı nasıl modellersiniz? Son derece güçlü ve hassas bir statik tip sistemine sahip olan Haskell'de deneyelim:

type Symbol = String
data Atom = ASymbol Symbol | AInt Int | AString String | Nil
data Cons = CCons Cons Cons 
            | CAtom Atom

İlk probleminiz Atom tipinin kapsamı olacak. Açıkçası, etrafta dolanmak istediğimiz tüm nesne türlerini kapsayacak yeterli esnekliğe sahip bir Atom türü seçmedik. Yukarıda listelendiği gibi Atom veri yapısını genişletmeye çalışmak yerine (ki bu kırılgandır), diyelim ki Atomicatomik yapmak istediğimiz tüm türleri ayırt eden sihirli bir tip sınıfımız var. Sonra deneyebiliriz:

class Atomic a where ?????
data Atomic a => Cons a = CCons Cons Cons 
                          | CAtom a

Ancak bu işe yaramayacak çünkü ağaçtaki tüm atomların aynı türde olmasını gerektiriyor . Yapraktan yaprağa farklılık gösterebilmelerini istiyoruz. Daha iyi bir yaklaşım, Haskell'in varoluşsal niceleyicilerinin kullanılmasını gerektirir :

class Atomic a where ?????
data Cons = CCons Cons Cons 
            | forall a. Atomic a => CAtom a 

Ama şimdi meselenin özüne geldiniz. Bu tür bir yapıdaki atomlarla ne yapabilirsiniz? Modellenebilecek ortak yapıları nelerdir Atomic a? Böyle bir türle hangi seviyede güvenlik garanti ediliyor? Tür sınıfımıza herhangi bir işlev eklemediğimizi ve bunun iyi bir nedeni olduğunu unutmayın: Atomlar Lisp'te ortak hiçbir şeyi paylaşmaz. Lisp'teki süper türleri basitçe t(yani üst) olarak adlandırılır .

Bunları kullanmak için, bir atomun değerini gerçekten kullanabileceğiniz bir şeye dinamik olarak zorlamak için mekanizmalar bulmanız gerekir. Ve bu noktada, statik olarak yazılmış dilinizde temelde dinamik olarak yazılmış bir alt sistem uyguladınız! (Biri yardım edemez, ancak Greenspun'un Onuncu Programlama Kuralı'nın olası bir sonucuna dikkat edin .)

Haskell böyle bir destek sağladığını Not dinamik alt sistem bir ile Objbir birlikte kullanılan türü, Dynamictipi ve bir tiplenemeyen sınıfa yerine bizimAtomic , keyfi değerlerin türleriyle birlikte depolanmasına ve bu türlerden açık zorlamaya izin verir. Bu, Lisp eksper yapılarıyla tam genel olarak çalışmak için kullanmanız gereken türden bir sistemdir.

Ayrıca yapabileceğiniz şey, diğer tarafa gitmek ve statik olarak yazılmış bir alt sistemi temelde dinamik olarak yazılmış bir dil içine yerleştirmektir. Bu, programınızın daha katı tür gereksinimlerinden yararlanabilecek bölümleri için statik tür denetimi avantajına olanak tanır. Bu , örneğin CMUCL'nin sınırlı hassas tip denetimi biçiminde alınan yaklaşım gibi görünüyor .

Son olarak, ikisi arasındaki geçişte gezinmeye yardımcı olmak için sözleşme tarzı programlama kullanan, dinamik ve statik olarak yazılmış iki ayrı alt sisteme sahip olma olasılığı vardır. Bu şekilde, dil, statik tip kontrolünün bir yardımdan çok bir engel teşkil edeceği Lisp kullanımlarının yanı sıra statik tip kontrolünün avantajlı olacağı kullanımları da barındırabilir. Aşağıdaki yorumlardan da göreceğiniz gibi, Typed Racket tarafından alınan yaklaşım budur.


16
Bu cevap temel bir sorundan muzdariptir: statik tip sistemlerin HM tarzı olması gerektiğini varsayıyorsunuz . Burada ifade edilemeyen ve Lisp kodunun önemli bir özelliği olan temel kavram alt tiplemedir. Daktilo edilmiş rakete bakacak olursanız, her türlü listeyi kolayca ifade edebileceğini göreceksiniz - (Listof Integer)ve gibi şeyler dahil (Listof Any). Açıkçası, tür hakkında hiçbir şey bilmediğiniz için ikincisinin yararsız olduğundan şüphelenirsiniz, ancak TR'de daha sonra kullanabilirsiniz (if (integer? x) ...)ve sistem xbunun 1. dalda bir Tamsayı olduğunu bilecektir .
Eli Barzilay

5
Oh, ve bu tiplenmiş raketin kötü bir karakterizasyonu (bazı yerlerde bulabileceğiniz sağlam olmayan tip sistemlerden farklıdır). Yazılan Raket olan bir statik olarak yazılan yazılan kodu için hiç çalışma zamanı yükü ile, dil. Racket hala TR'de bazı kodların yazılmasına izin veriyor ve bazılarının normal tiplenmemiş dilde yazılmasına izin veriyor - ve bu durumlarda, yazılan kodu potansiyel olarak yanlış çalışan türsüz koddan korumak için sözleşmeler (dinamik kontroller) kullanılır.
Eli Barzilay

1
@Eli Barzilay: Yalan söyledim, dört bölüm var: 4. Sektör tarafından kabul edilen C ++ kodlama stilinin, alt tiplemeden jeneriklere doğru kademeli olarak uzaklaşması ilginç. Zayıflık, dilin genel bir işlevin kullanacağı arabirimi bildirmek için yardım sağlamamasıdır, tür sınıflarının kesinlikle yardımcı olabileceği bir şey. Ayrıca, C ++ 0x tür çıkarımı ekliyor olabilir. Sanırım HM değil, ama o yöne doğru sürünen?
Owen S.

1
Owen: (1) Asıl nokta şu ki , yazılan kodların türünü ifade etmek için alt türlere ihtiyacınız var - ve bunu HM sistemlerinde elde edemezsiniz, bu nedenle her kullanım için özel türlere ve kuruculara zorlanırsınız. her şeyi çok daha garip hale getiriyor. Alt tipleri ile bir sistem kullanılarak yazılan raket olarak kasıtlı bir tasarım kararının bir neticesi oldu: sonuç böyle kod türlerini ifade etmek mümkün olmalıdır olmadan kod değiştirme veya özel türleri oluşturarak.
Eli Barzilay

1
(2) Evet, dynamicstatik dillerde türler, dinamik olarak yazılmış dillerin bazı faydalarını elde etmek için bir tür geçici çözüm olarak popüler hale geliyor ve bu değerlerin olağan değiş tokuşu, türleri tanımlanabilir hale getirecek şekilde sarılıyor. Ancak burada da tiplenmiş raket, onu dil içinde uygun hale getirmede çok iyi bir iş çıkarıyor - tür denetleyicisi, türler hakkında daha fazla bilgi edinmek için yüklemlerin oluşumlarını kullanır. Örneğin, raket sayfasındaki yazılı örneğe bakın ve string?bir dizi ve sayı listesini bir dizi dizisine nasıl "indirgediğini" görün.
Eli Barzilay

10

Cevabım, yüksek derecede güven olmadan muhtemelen . Örneğin SML gibi bir dile bakarsanız ve onu Lisp ile karşılaştırırsanız, her birinin işlevsel çekirdeği neredeyse aynıdır. Sonuç olarak, Lisp'in çekirdeğine (işlev uygulaması ve ilkel değerler) bir tür statik yazım uygularken çok fazla sorun yaşamayacaksınız.

Sorunuz yine de tam olarak söylüyor ve bazı problemlerin geldiğini gördüğüm yer veri olarak kod yaklaşımı. Türler, ifadelerden daha soyut bir düzeyde bulunur. Lisp'in bu ayrımı yoktur - her şeyin yapısı "düzdür". E: T'nin bir ifadesini (burada T, türünün bir temsilidir) düşünürsek ve bu ifadeyi düz veri olarak düşünürsek, o zaman burada T türü tam olarak nedir? Bu bir tür! Bir tür daha yüksek, sipariş türüdür, bu yüzden devam edip kodumuzda bununla ilgili bir şeyler söyleyelim:

E : T :: K

Bununla nereye gittiğimi görebilirsiniz. Eminim tür bilgisini koddan ayırarak, türlerin bu tür kendi kendine referanslarından kaçınmak mümkün olabilirdi, ancak bu türlerin lezzetlerinde çok "lisp" olmamasına neden olur. Muhtemelen bunun üstesinden gelmenin birçok yolu var, ancak hangisinin en iyisi olacağı bana açık değil.

DÜZENLEME: Oh, biraz googling ile, statik olarak yazılması dışında Lisp'e çok benzeyen Qi'yi buldum . Belki de, oraya statik yazmayı sağlamak için nerede değişiklik yaptıklarını görmeye başlamak için iyi bir yerdir.


Görünüşe göre Qi'den sonraki bir sonraki yineleme aynı kişi tarafından geliştirilen Shen'dir .
Diagon

4

Bağlantı kesildi. Ancak her durumda, Dylan statik olarak yazılmamıştır.
Björn Lindqvist

@ BjörnLindqvist: bu bağlantı Dylan'a kademeli yazım eklemekle ilgili bir tezdi.
Rainer Joswig

1
@ BjörnLindqvist: Bir genel bakış makalesine bağlandım.
Rainer Joswig

Ancak aşamalı yazma, statik yazma olarak sayılmaz. Eğer öyleyse, Pypy, aşamalı yazmayı da kullandığı için statik olarak Python olarak yazılırdı.
Björn Lindqvist

2
@ BjörnLindqvist: Kademeli yazım yoluyla statik türler eklersek ve bunlar derleme sırasında kontrol edilirse, bu statik yazmadır. Sadece tüm program statik olarak yazılmış değil, parçalar / bölgeler. Homes.sice.indiana.edu/jsiek/what-is-gradual-typing 'Kademeli yazma, 2006 yılında Walid Taha ile geliştirdiğim, bir programın bölümlerinin dinamik olarak yazılmasına ve diğer bölümlerin statik olarak yazılmasına izin veren bir tür sistemidir.'
Rainer Joswig
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.