Haskell'de bir Haskell tercümanı yazın


90

Klasik bir programlama alıştırması, Lisp / Scheme'de bir Lisp / Scheme yorumlayıcısı yazmaktır. Tam dilin gücü, dilin bir alt kümesi için bir tercüman üretmek için kullanılabilir.

Haskell için benzer bir egzersiz var mı? Motor olarak Haskell'i kullanarak Haskell'in bir alt kümesini uygulamak istiyorum. Tabii ki olabilir yapılır, ancak herhangi bir çevrimiçi kaynaklar bakmak için kullanılabilir bir hale gelmesine?


İşte arka plan.

Öğrettiğim Kesikli Yapılar dersindeki bazı kavramları keşfetmek için Haskell'i bir dil olarak kullanma fikrini araştırıyorum . Bu dönem için Haskell'e ilham veren daha küçük bir dil olan Miranda'ya karar verdim . Miranda, benim yapmasını istediğim şeyin yaklaşık% 90'ını yapıyor, ancak Haskell yaklaşık% 2000 yapıyor. :)

Benim fikrim, tam olarak Haskell'in istediğim ve diğer her şeye izin vermediğim özelliklerine sahip bir dil yaratmak. Öğrenciler ilerledikçe, temel konularda ustalaştıklarında çeşitli özellikleri seçerek "açabiliyorum".

Pedagojik "dil seviyeleri" Java ve Şema öğretmek için başarıyla kullanılmıştır . Yapabileceklerini sınırlayarak, öğretmeye çalıştığınız sözdizimi ve kavramlarda ustalaşırken, kendilerini ayağından vurmalarını engelleyebilirsiniz. Ve daha iyi hata mesajları sunabilirsiniz.


Haskell'de Haskell yazarak temel olarak uygulanan bir WIP Haskell lehçesine sahibim. Burada bunun bir demosu var chrisdone.com/toys/duet-delta Halka açık açık kaynak sürümüne hazır değil, ancak ilgilenirseniz kaynağı sizinle paylaşabilirim.
Christopher Done

Yanıtlar:


76

Amacınızı seviyorum ama bu büyük bir iş. Birkaç ipucu:

  • GHC üzerinde çalıştım ve kaynakların herhangi bir bölümünü istemezsin. Hugs çok daha basit, daha temiz bir uygulama ama maalesef C.

  • Bu, bulmacanın küçük bir parçası, ancak Mark Jones , Haskell'de Yazma Haskell adlı güzel bir makale yazdı ve bu, ön ucunuz için harika bir başlangıç ​​noktası olabilir.

İyi şanslar! Haskell için dil seviyelerini sınıftan gelen destekleyici kanıtlarla belirlemek, topluluğa büyük fayda sağlayacak ve kesinlikle yayınlanabilir bir sonuç olacaktır!


2
GHC hakkındaki yorumun hala doğru olup olmadığını merak ediyorum. GHC karmaşıktır, ancak oldukça iyi belgelenmiştir. Özellikle, dahili Notesbilgiler düşük seviyeli ayrıntıları anlamada yardımcı olur ve Açık Kaynak Uygulamalarının Mimarisi'ndeki GHC ile ilgili bölüm mükemmel bir üst düzey genel bakış sağlar.
sjy

37

Tam bir Haskell ayrıştırıcısı var: http://hackage.haskell.org/package/haskell-src-exts

Bir kez ayrıştırdıktan sonra, belirli şeyleri çıkarmak veya izin vermemek kolaydır. Bunu tryhaskell.org için ithalat ifadelerine izin vermemek, üst düzey tanımları desteklemek vb. İçin yaptım.

Sadece modülü ayrıştırın:

parseModule :: String -> ParseResult Module

O zaman bir modül için AST'ye sahipsiniz:

Module SrcLoc ModuleName [ModulePragma] (Maybe WarningText) (Maybe [ExportSpec]) [ImportDecl] [Decl]    

Decl türü kapsamlıdır: http://hackage.haskell.org/packages/archive/haskell-src-exts/1.9.0/doc/html/Language-Haskell-Exts-Syntax.html#t%3ADecl

Yapmanız gereken tek şey bir beyaz liste tanımlamaktır - hangi bildirimlerin, ithallerin, sembollerin, sözdiziminin mevcut olduğuna dair, ardından AST'ye gidin ve henüz farkında olmalarını istemediğiniz herhangi bir şeye bir "ayrıştırma hatası" atın. AST'deki her düğüme eklenmiş SrcLoc değerini kullanabilirsiniz:

data SrcLoc = SrcLoc
     { srcFilename :: String
     , srcLine :: Int
     , srcColumn :: Int
     }

Haskell'i yeniden uygulamaya gerek yoktur. Daha kolay derleme hataları sağlamak istiyorsanız, sadece kodu ayrıştırın, filtreleyin, derleyiciye gönderin ve derleyici çıktısını ayrıştırın. Eğer bir "beklenen tip a ile çıkarsanan eşleşemez" ise, a -> bmuhtemelen bir fonksiyon için çok az argüman olduğunu bilirsiniz.

Gerçekten Haskell'i sıfırdan uygulamak veya Hugs'ın içindekilerle uğraşmak veya bazı aptalca uygulamalarla uğraşmak için gerçekten zaman harcamak istemiyorsanız, bence GHC'ye geçirilenleri filtrelemelisiniz. Bu şekilde, öğrencileriniz kod tabanlarını alıp bir sonraki adıma geçmek ve gerçek anlamda tam teşekküllü bir Haskell kodu yazmak isterse, geçiş şeffaftır.


24

Tercümanınızı sıfırdan mı oluşturmak istiyorsunuz? Lambda hesabı veya bir lisp varyantı gibi daha kolay işlevsel bir dil uygulamakla başlayın. İkincisi için, 48 saatte Kendine Bir Şema Yaz adında oldukça güzel bir wikibook var .

Haskell'i elle yorumlamak çok daha karmaşık olacaktır çünkü tip sınıfları, son derece güçlü bir tip sistemi (tür çıkarımı!) Ve tembel değerlendirme (azaltma teknikleri) gibi oldukça karmaşık özelliklerle uğraşmanız gerekecek.

Dolayısıyla, çalışmak için Haskell'in oldukça küçük bir alt kümesini tanımlamalı ve sonra belki Şema örneğini adım adım genişleterek başlamalısınız.

İlave:

Haskell'de, ayrıştırıcılar, derleyiciler ve tabii ki tercümanlar dahil olmak üzere yorumlayıcı API'sine (en azından GHC altında) tam erişiminiz olduğunu unutmayın.

Kullanılacak paket ipucudur (Language.Haskell. *) . Ne yazık ki ne bununla ilgili çevrimiçi eğitimler buldum ne de kendi başıma denedim ama oldukça umut verici görünüyor.


12
Tür çıkarımının aslında çok kolay, 20-30 satırlık bir algoritma olduğunu unutmayın. sadeliği içinde güzel. Tembel değerlendirme de kodlamak o kadar zor değildir. Zorluğun çılgın sözdiziminde, kalıp eşleştirmesinde ve dildeki büyük miktarda şeyde yattığını söyleyebilirim.
Claudiu

İlginç - Tür çıkarım algoritmaları için bağlantılar gönderebilir misiniz?
Dario

5
Evet, bu ücretsiz kitaba bir göz atın - cs.brown.edu/~sk/Publications/Books/ProgLangs/2007-04-26 -, sayfa 273'te ( pdf'nin 289'u ). Alg sözde kodu P296 üzerindedir.
Claudiu

1
" Fonksiyonel Programlama Dillerinin Uygulanması " nda bir (?) Tip çıkarım / kontrol algoritmasının bir uygulaması da vardır .
Phil Armstrong

1
Yine de, tür sınıflarıyla tür çıkarımı basit değildir.
Christopher Done

20

Tam olarak Haskell'in benim istediğim ve diğer her şeye izin vermeyen özelliklerine sahip bir dil oluşturun. Öğrenciler ilerledikçe, temel konularda ustalaştıklarında çeşitli özellikleri seçerek "açabiliyorum".

Bu soruna daha basit (daha az iş içeren) bir çözüm öneriyorum. Özellikleri kapatabileceğiniz bir Haskell uygulaması oluşturmak yerine, bir Haskell derleyicisini önce kodun izin vermediğiniz herhangi bir özelliği kullanıp kullanmadığını kontrol eden ve ardından onu derlemek için hazır derleyiciyi kullanan bir programla sarın.

Bu HLint'e benzer (ve aynı zamanda tam tersi):

HLint (eski adıyla Dr. Haskell), Haskell programlarını okur ve bunların okunmasını kolaylaştırmayı umduğumuz değişiklikler önerir. HLint ayrıca istenmeyen önerileri devre dışı bırakmayı ve kendi özel önerilerinizi eklemeyi kolaylaştırır.

  • İzin vermediğiniz özellikleri kullanmamak için kendi HLint "önerilerinizi" uygulayın
  • Tüm standart HLint önerilerini devre dışı bırakın.
  • İlk adım olarak sarmalayıcınızın değiştirilmiş HLint'inizi çalıştırmasını sağlayın
  • HLint önerilerini hata olarak ele alın. Yani, HLint "şikayet ederse" program derleme aşamasına geçmez


6

EHC serisi derleyiciler muhtemelen en iyi seçenektir: Aktif olarak geliştirildi ve tam da istediğiniz gibi görünüyor - Haskell '98 ile sonuçlanan bir dizi küçük lambda calculi derleyici / yorumlayıcı.

Ancak, Pierce'ın Türleri ve Programlama Dillerinde geliştirilen çeşitli dillere veya Helyum tercümanına da bakabilirsiniz (öğrenciler için tasarlanmış sakat bir Haskell http://en.wikipedia.org/wiki/Helium_(Haskell) ).


6

Haskell'in uygulanması kolay bir alt kümesi arıyorsanız, tür sınıfları ve tür denetimini ortadan kaldırabilirsiniz. Tür sınıfları olmadan, Haskell kodunu değerlendirmek için tür çıkarımına ihtiyacınız yoktur.

Code Golf yarışması için kendi kendini derleyen bir Haskell alt küme derleyicisi yazdım . Haskell alt küme kodunu girişte alır ve çıktıda C kodu üretir. Maalesef daha okunabilir bir sürüm yok; Kendi kendini derleme sürecinde iç içe geçmiş tanımları elle kaldırdım.

Haskell'in bir alt kümesi için bir tercüman uygulamakla ilgilenen bir öğrenci için, aşağıdaki özelliklerle başlamanızı tavsiye ederim:

  • Tembel değerlendirme. Tercüman Haskell'de ise, bunun için hiçbir şey yapmanız gerekmeyebilir.

  • Kalıp uyumlu bağımsız değişkenler ve korumalarla işlev tanımları. Yalnızca değişkenler, eksiler, sıfırlar ve _örüntüler hakkında endişelen .

  • Basit ifade sözdizimi:

    • Tamsayı değişmez değerleri

    • Karakter değişmez değerleri

    • [] (sıfır)

    • İşlev uygulaması (sol ilişkisel)

    • Infix :(eksiler, doğru ilişkisel)

    • Parantez

    • Değişken isimler

    • Fonksiyon isimleri

Daha somut olarak, bunu çalıştırabilecek bir yorumlayıcı yazın:

-- tail :: [a] -> [a]
tail (_:xs) = xs

-- append :: [a] -> [a] -> [a]
append []     ys = ys
append (x:xs) ys = x : append xs ys

-- zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWith f (a:as) (b:bs) = f a b : zipWith f as bs
zipWith _ _      _      = []

-- showList :: (a -> String) -> [a] -> String
showList _    []     = '[' : ']' : []
showList show (x:xs) = '[' : append (show x) (showItems show xs)

-- showItems :: (a -> String) -> [a] -> String
showItems show []     = ']' : []
showItems show (x:xs) = ',' : append (show x) (showItems show xs)

-- fibs :: [Int]
fibs = 0 : 1 : zipWith add fibs (tail fibs)

-- main :: String
main = showList showInt (take 40 fibs)

Tür denetimi, Haskell'in önemli bir özelliğidir. Ancak, yoktan bir tür denetimli Haskell derleyicisine geçmek çok zordur. Yukarıdakiler için bir yorumlayıcı yazarak başlarsanız, buna tür denetimi eklemek daha az göz korkutucu olacaktır.


"Tembel değerlendirme. Tercüman Haskell'de ise, bunun için hiçbir şey yapmanız gerekmeyebilir." Bu doğru olmayabilir. Haskell'de tembel bir tercüman uygulama hakkında daha fazla bilgi için Naylor'un haskell.org/wikiupload/0/0a/TMR-Issue10.pdf'deki makalesine bakın .
Jared Updike


3

Bu iyi bir fikir olabilir - Haskell'de NetLogo'nun küçük bir sürümünü yapın. İşte minik tercüman.


Bağlantılar kesildi. Bu içeriğin hala başka bir yerde var olma ihtimali var mı? Merak ediyorum ...
Nicolas Payette

hmm bu bir blog yazısıydı ve onu aramak için hangi anahtar kelimeleri kullanacağım konusunda hiçbir fikrim yok. Bir bağlantı sağlarken daha önemli bilgiler eklemek için iyi bir ders ...
Claudiu

1
"Netlogo haskell" için bir Google araması çıkıyor ... bu soru. Neyse, önemli değil. Teşekkürler!
Nicolas Payette



2

İdris'in oldukça kompakt bir ayrıştırıcıya sahip olduğu söylendi, değişiklik için gerçekten uygun olup olmadığından emin değilim, ancak Haskell'de yazılmış.


2

Andrej Bauer'in Programlama Dili Hayvanat Bahçesi , biraz arsızca "minihaskell" olarak adlandırılan, tamamen işlevsel bir programlama dilinin küçük bir uygulamasına sahiptir. Yaklaşık 700 satır OCaml'dir, bu yüzden sindirimi çok kolaydır.

Site ayrıca ML tarzı, Prolog stili ve OO programlama dillerinin oyuncak sürümlerini de içerir.


1

Kendi Haskell tercümanınızı sıfırdan yazmaktan GHC kaynaklarını alıp istemediklerinizi çıkarmanın daha kolay olacağını düşünmüyor musunuz ? Genel olarak konuşursak, özelliklerin oluşturulması / eklenmesi yerine, özelliklerin kaldırılması için çok daha az çaba sarf edilmelidir .

GHC zaten Haskell'de yazılmıştır, bu nedenle teknik olarak Haskell'de yazılmış bir Haskell tercümanı ile ilgili sorunuzda kalır.

Muhtemelen her şeyi statik olarak bağlantılı hale getirmek ve sonra sadece özelleştirilmiş GHCi'nizi dağıtmak çok zor olmazdı, böylece öğrenciler diğer Haskell kaynak modüllerini yükleyemezler. Diğer Haskell nesne dosyalarını yüklemelerini önlemek için ne kadar çalışma gerekeceğine gelince, hiçbir fikrim yok. Sınıflarınızda bir sürü dolandırıcı varsa, FFI'yi de devre dışı bırakmak isteyebilirsiniz :)


1
Birçok özellik diğerlerine bağlı olduğundan, bu göründüğü kadar kolay değildir. Ama belki de OP sadece Prelude'u ithal etmek istemiyor ve bunun yerine kendisininkini sağlamak istiyor. Gördüğünüz Haskell'in çoğu normal işlevlerdir, çalışma zamanının belirli özellikleri değildir. (Ama elbette, çoğu var .)
jrockway

0

Bu kadar çok LISP yorumlayıcısının olmasının nedeni, LISP'nin temelde JSON'un öncülü olmasıdır: verileri kodlamak için basit bir format. Bu, ön uç kısmının kullanımını oldukça kolaylaştırır. Buna kıyasla Haskell, özellikle Dil Uzantıları ile ayrıştırılması en kolay dil değil. Bunlar, doğru yapmak için kulağa zor gelen bazı sözdizimsel yapılardır:

  • yapılandırılabilir öncelik, ilişkilendirilebilirlik ve sabitliğe sahip operatörler,
  • iç içe geçmiş yorumlar
  • düzen kuralı
  • desen sözdizimi
  • do- monadik koda engelleme ve çözümleme

Belki operatörler hariç bunların her biri, Derleyici İnşaat Kursundan sonra öğrenciler tarafından ele alınabilir, ancak bu, Haskell'in gerçekte nasıl çalıştığından odaklanmayı uzaklaştıracaktır. Buna ek olarak, Haskell'in tüm sözdizimsel yapılarını doğrudan uygulamak istemeyebilir, bunun yerine onlardan kurtulmak için geçişleri uygulamak isteyebilirsiniz. Bu da bizi konunun gerçek özüne getiriyor, tam olarak kasıtlı.

Benim önerim Coretam Haskell yerine typechecking ve bir yorumlayıcı uygulamaktır . Bu görevlerin her ikisi de kendi başlarına oldukça karmaşıktır. Bu dil, güçlü bir şekilde yazılmış işlevsel bir dil olmasına rağmen, optimizasyon ve kod üretimi açısından uğraşmak için çok daha az karmaşıktır. Ancak yine de temeldeki makineden bağımsızdır. Bu nedenle, GHC onu bir aracı dil olarak kullanır ve Haskell'in çoğu sözdizimi yapısını ona çevirir.

Ek olarak, GHC'lerin (veya başka bir derleyicinin) ön ucunu kullanmaktan çekinmemelisiniz. Özel LISP'ler ana bilgisayar LISP sisteminin ayrıştırıcısını kullandığından (en azından önyükleme sırasında) bunu hile olarak kabul etmem. CoreParçacıkları temizlemek ve bunları öğrencilere orijinal kodla birlikte sunmak, ön ucun ne yaptığına ve neden yeniden uygulanmamasının tercih edildiğine dair bir genel bakış sunmanıza olanak sağlamalıdır.

CoreGHC'de kullanıldığı şekliyle belgelerine birkaç bağlantı aşağıda verilmiştir :

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.