Haskell, Lisp ve ayrıntı [kapalı]


104

Hem Haskell'de hem de Lisp'in bazı lezzetlerinde deneyimli olanlar için, Haskell'e karşı Lisp kod yazmanın (korkunç bir terim kullanmak için) ne kadar "hoş" olduğunu merak ediyorum.

Bazı arka plan bilgileri: Şimdiye kadar Scheme ve CL ile çalıştığım için Haskell'i öğreniyorum (ve Clojure'e biraz giriyorum). Geleneksel olarak, sağladıkları kısa ve özlük ve hızlılık nedeniyle beni dinamik dillerin hayranı olarak düşünebilirsiniz. Lisp makrolarına hızla aşık oldum, çünkü bu bana ayrıntılardan ve standart metinden kaçınmanın başka bir yolunu sağladı.

Var olduğunu bilmediğim kodlama yöntemlerini bana tanıttığı için Haskell'i inanılmaz derecede ilginç buluyorum . Kısmi işlevler yazma kolaylığı gibi, çevikliğe ulaşmaya yardımcı olacak gibi görünen bazı yönleri kesinlikle vardır. Bununla birlikte, Lisp makrolarını (onları kaybettiğimi varsayıyorum; doğruyu söylemek gerekirse, onlar hakkında henüz bir şey öğrenmemiş olabilirim?) Ve statik yazım sistemini kaybetme konusunda biraz endişeliyim.

Her iki dünyada da makul miktarda kodlama yapmış olan biri, deneyimlerin nasıl farklılaştığını, hangisini tercih ettiğinizi ve eğer söz konusu tercih durumsal ise, yorumlamayı akıl eder mi?

Yanıtlar:


69

Kısa cevap:

  • makrolarla yapabileceğiniz neredeyse her şey, üst düzey bir işlevle yapabileceğiniz (ve ben monadlar, oklar vb. dahil), ancak daha fazla düşünmeyi gerektirebilir (ancak yalnızca ilk seferde ve eğlencelidir ve bir bunun için daha iyi programcı) ve
  • Statik sistem yeterince geneldir ve hiçbir zaman yolunuza çıkmaz ve biraz şaşırtıcı bir şekilde aslında "çevikliğe ulaşmaya yardımcı olur" (dediğiniz gibi) çünkü programınız derlendiğinde bunun doğru olduğundan neredeyse emin olabilirsiniz, bu nedenle bu kesinlik denemenizi sağlar başka türlü denemekten korkabileceğiniz şeyleri öğrenin - Lisp ile aynı olmasa da programlamanın "dinamik" bir hissi vardır.

[Not: Tıpkı Lisp'te olduğu gibi makro yazmanıza izin veren bir " Şablon Haskell " vardır, ancak kesinlikle konuşursak, ona asla ihtiyacınız olmamalıdır .]


15
Don Stewart'ın alıntıladığı Conor McBride'dan: "Türleri, yerçekimimizi çarpıtmak olarak düşünmeyi seviyorum, böylece [doğru programları yazmak için] gitmemiz gereken yön" yokuş aşağı "olur." Yazı sistemi, doğru programları yazmayı şaşırtıcı derecede kolaylaştırır… bu gönderiye ve yeniden paylaşımlarına bakın.
ShreevatsaR

3
Yüksek sıralı işlevler makroların yerini alamaz ve aslında CL her ikisine birden neden olur. CL'deki makroların gerçek gücü, geliştiricinin Haskell veya Java'da olduğu gibi dilin yeni bir sürümünü beklemek zorunda kalmadan, bir soruna çözümün daha iyi ifade edilmesine yardımcı olan yeni dil özelliklerini sunmalarına izin vermeleridir. Örneğin, Haskell bu güce sahip olsaydı, Haskell yazarlarının GHC uzantıları yazmasına gerek kalmazdı, bunlar geliştiricilerin kendileri tarafından herhangi bir zamanda makro olarak uygulanabilirdi.
mljrg

@mljrg Somut bir örneğiniz var mı? Hibou57'nin cevabıyla ilgili, iddia edilen bir örneğin şüpheli olduğu aşağıdaki yorumlara bakın. Ne tür bir şeyi kastettiğinizi bilmek isterim (örneğin, makro içeren ve içermeyen Haskell kodu).
ShreevatsaR

4
Haskell'den körili çıkar. Haskell'de kalanla uygulayabilir misin? Başka bir örnek: Haskell'in kalıp eşleştirmeyi desteklemediğini varsayalım, GHC geliştiricilerinin desteklemesi gerekmeden bunu kendiniz ekleyebilir misiniz? CL'de, dili istediğiniz zaman genişletmek için makroları kullanabilirsiniz. Sanırım bu yüzden CL, 90'lardaki standartlarından bu yana değişmedi, oysa Haskell GHC'de hiç bitmeyen uzantı akışına sahip gibi görünüyor.
mljrg

64

Her şeyden önce, dinamik yazma gibi belirli özellikleri kaybetme konusunda endişelenmeyin. Oldukça iyi tasarlanmış bir dil olan Common Lisp'e aşina olduğunuz için, bir dilin özellik setine indirgenemeyeceğinin farkında olduğunuzu varsayıyorum. Her şey tutarlı bir bütünle ilgili, değil mi?

Bu bağlamda Haskell, Common Lisp'in yaptığı gibi parlıyor. Özellikleri, size kodu son derece kısa ve zarif kılan bir programlama yolu sağlamak için bir araya gelir. Makro eksikliği, monadlar ve oklar gibi daha ayrıntılı (ancak aynı şekilde anlaşılması ve kullanılması daha zor) kavramlarla bir şekilde azaltılır. Statik tip sistemi, çoğu nesne yönelimli dilde olduğu gibi, yolunuza çıkmak yerine gücünüze katkıda bulunur.

Öte yandan, Haskell'deki programlama Lisp'ten çok daha az etkileşimlidir ve Lisp gibi dillerde bulunan muazzam miktarda yansıma, Haskell'in öngördüğü dünyanın statik görüşüne uymuyor. Kullanabileceğiniz araç setleri bu nedenle iki dil arasında oldukça farklıdır, ancak birbiriyle karşılaştırılması zordur.

Kişisel olarak genel olarak Lisp programlama yöntemini tercih ediyorum, çünkü daha iyi çalışma şeklimle uyumlu olduğunu düşünüyorum. Ancak bu, sizin de yapmak zorunda olduğunuz anlamına gelmez.


4
"Haskell'de programlama çok daha az etkileşimli" hakkında biraz daha detaylandırır mısınız? GHCi gerçekten ihtiyacınız olan her şeyi sağlamıyor mu?
Johannes Gerer

3
@JohannesGerer: Henüz denemedim, ancak okuduğum kadarıyla GHCi, çalışırken tüm programın rastgele bölümlerini yeniden tanımlayabileceğiniz ve genişletebileceğiniz bir çalışan görüntünün kabuğu değil. Ayrıca Haskell sözdizimi, program parçalarını repl ve düzenleyici arasında programlı olarak kopyalamayı çok daha zor hale getirir.
Svante

13

Haskell'de metaprogramlamaya Common Lisp'e göre daha az ihtiyaç vardır, çünkü monadlar etrafında çok şey yapılandırılabilir ve eklenen sözdizimi gömülü DSL'leri daha az ağaç benzeri gösterir, ancak ShreevatsaR tarafından belirtildiği gibi her zaman Şablon Haskell ve hatta Liskell (Haskell semantiği + Lisp sözdizimi) parantezleri beğendiyseniz.


1
Liskell bağlantısı kesildi , ancak bu günlerde Hackett var .
Will Ness

10

Makrolarla ilgili olarak, işte bundan bahseden bir sayfa: Merhaba Haskell, Hoşçakal Lisp . Haskell'de makrolara ihtiyaç duyulmayan bir bakış açısını açıklıyor. Karşılaştırma için kısa bir örnekle birlikte gelir.

Her iki bağımsız değişkenin değerlendirilmesini önlemek için bir LISP makrosunun gerekli olduğu örnek durum:

(defmacro doif (x y) `(if ,x ,y))

Haskell'in makro tanımı gibi herhangi bir şeye ihtiyaç duymadan her iki argümanı da sistematik olarak değerlendirmediği örnek durum:

doif x y = if x then (Just y) else Nothing

Ve voilà


17
Bu yaygın bir yanılgıdır. Evet, Haskell'de tembellik, bir ifadenin bazı kısımlarını değerlendirmekten kaçınmak istediğinizde makrolara ihtiyacınız olmadığı anlamına gelir, ancak bunlar tüm makro kullanımların yalnızca en önemsiz alt kümesidir. Tembellikle yapılamayacak bir makroyu gösteren konuşma için "Perl'den Önce Domuz" için Google. Eğer Ayrıca, do bazı biraz katı olmak istiyorum, o zaman bir fonksiyonu olarak bunu yapamaz - Şema en gerçeğini yansıtma delaybir işlev olamaz.
Eli Barzilay

8
@Eli Barzilay: Bu örneği pek inandırıcı bulmuyorum. 40. slaydın eksiksiz ve basit bir Haskell çevirisi: pastebin.com/8rFYwTrE
Reid Barton

5
@Eli Barzilay: Cevabınızı hiç anlamıyorum. accept olan (E) DSL. acceptFonksiyonu, önceki sayfalarda belirtilen makro analogudur ve tanımı vtam tanımı paralel olan vsürgü 40. Şema, The Haskell ve Şema fonksiyonları aynı değerlendirme stratejisi ile aynı şeyi hesaplamak. En iyi durumda, makro, programınızın yapısının daha fazlasını optimize ediciye göstermenize olanak tanır. Bunu, makroların tembel bir değerlendirmeyle kopyalanmayacak şekilde dilin ifade gücünü artırdığı bir örnek olarak iddia edemezsiniz.
Reid Barton

5
@Eli Barzilay: Varsayımsal bir tembel Şemada şunu yazabilirsiniz: pastebin.com/TN3F8VVE Genel iddiam , bu makronun size çok az şey kazandırdığı: biraz farklı sözdizimi ve optimize edici için daha kolay bir zaman (ama önemli değil "yeterince akıllı bir derleyici"). Karşılığında kendini ifade etmeyen bir dile hapsettin; Hepsini listelemeden herhangi bir harfle eşleşen bir otomatı nasıl tanımlarsınız? Ayrıca, "tüm alt listelerde kullanmak" veya "kendi kapsamı ile nerede kullanılması gerekli" ile ne demek istediğini bilmiyorum.
Reid Barton

15
Tamam pes ediyorum. Görünüşe göre DSL tanımınız "bir makro için argümanlar" ve bu yüzden benim tembel Şema örneğim, sözdizimsel olarak orijinalle eşbiçimli olmasına rağmen ( bu sürümde automatonolma letrec, :olma accept, ->hiçbir şey olma) bir DSL değil . Her neyse.
Reid Barton

9

Ben bir Common Lisp programcısıyım.

Haskell'i bir süre önce denedikten sonra kişisel karım CL'e bağlı kalmaktı.

Sebepler:

  • dinamik yazım ( Dinamik ve Statik Yazma - Pascal Costanza'nın Desen Tabanlı Analizine bakın )
  • isteğe bağlı ve anahtar kelime argümanları
  • makrolarla tekdüze homoiconic liste sözdizimi
  • önek sözdizimi (öncelik kurallarını hatırlamaya gerek yoktur)
  • saf değildir ve bu nedenle hızlı prototipleme için daha uygundur
  • meta-nesne protokollü güçlü nesne sistemi
  • olgun standart
  • geniş derleyici yelpazesi

Haskell'in elbette kendine has değerleri var ve bazı şeyleri temelde farklı bir şekilde yapıyor, ancak bu benim için uzun vadede onu kesmiyor.


Bağlandığın Costanza gazetesinin başlığına sahip misin? Görünüşe göre o dosya taşınmış.
michiakig

2
Haskell'in de önek sözdizimini desteklediğine dikkat edin, ancak monad >> = kullanmanın çok çirkin olacağını söyleyebilirim. Ayrıca safsızlığın bir lütuf olduğuna katılmıyorum: P
alternatif

2
Şu yan notu beğendim: Bu sorunun gerçek dünya programlarında ciddi sorunlara yol açıp açmayacağı konusunda henüz deneysel veri toplamadık.
Jerome Baum

22
Bu makaledeki örneklerin hiçbiri (Pascal Costanza, Dinamik ve Statik Yazma - Desen Tabanlı Bir Analiz ) Haskell için geçerli değildir. Hepsi Java'ya özgü (veya daha doğrusu "nesne yönelimli programlamaya" özgü ) ve bu sorunların hiçbirinin Haskell'de ortaya çıktığını göremiyorum. Benzer şekilde, diğer tüm argümanlarınız tartışmaya açıktır: Haskell'in "saf ve bu nedenle hızlı prototipleme için daha uygun" olduğunu, önek sözdiziminin zorunlu olmadığını, farklı şeyler yapan geniş bir derleyici yelpazesine sahip olmadığını söyleyebiliriz. , vb.
ShreevatsaR

11
Bu makale gerçekten Haskell ile neredeyse tamamen alakasız. " dilbert = dogbert.hire(dilbert);" ?? Pek çok Haskell programcısının bunu biraz seğirmeden okuyabileceğinden bile şüpheliyim.
leftaroundabout

6

Haskell'de, LISP'de imkansız olan bir if işlevi tanımlayabilirsiniz. Bu, programlarda daha fazla modülerliğe izin veren tembellik nedeniyle mümkündür. Bu klasik makale: FP neden önemlidir John Hughes, tembelliğin birleştirilebilirliği nasıl geliştirdiğini açıklar.


5
Şema (iki ana LISP lehçesinden biri) aslında tembel bir değerlendirmeye sahiptir, ancak Haskell'deki gibi varsayılan değildir.
Randy Voet

7
(defmacro doif (xy) `(if, x, y))
Joshua Cheek

4
Bir makro, bir işlevle aynı değildir - makrolar fold, örneğin katı olmayan işlevler yaptığı gibi , üst düzey işlevlerle iyi çalışmaz .
Tikhon Jelvis

5

Haskell'de (mümkünse) hantal olan makrolarla Lisp'te elde edebileceğiniz gerçekten harika şeyler var. Örneğin, `memoize 'makrosunu ele alalım (Peter Norvig'in PAIP'sinin 9. Bölümüne bakın). Bununla birlikte, bir işlev tanımlayabilir, foo diyebilir ve sonra basitçe değerlendirebilirsiniz (memoize 'foo), bu da foo'nun genel tanımını hatırlanmış bir sürümle değiştirir. Haskell'de aynı etkiyi üst düzey işlevlerle elde edebilir misiniz?


3
Tam olarak değil (AFAIK), ancak işlevi değiştirerek (özyinelemeli olduğu varsayılarak) işlevi basitçe adıyla çağırmak yerine bir parametre (!) Olarak özyinelemeli olarak çağırmak için benzer bir şey yapabilirsiniz: haskell.org/haskellwiki/Memoization
j_random_hacker

6
Değerin hesaplandıktan sonra depolanacağı tembel bir veri yapısına foo ekleyebilirsiniz. Bu etkili bir şekilde aynı olacaktır.
Theo Belaire

Haskell'deki her şey hafızaya alınır ve gerektiğinde Haskell derleyicisi tarafından varsayılan olarak satır içi olarak gösterilir.
aoeu256

4

Haskell öğrenme yolculuğuma devam ederken, makroları "değiştirmeye" yardımcı olan bir şey, kendi infix operatörlerinizi tanımlama ve bunların önceliklerini ve ilişkilendirilebilirliklerini özelleştirme yeteneği gibi görünüyor. Biraz karmaşık, ama ilginç bir sistem!

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.