En saf fonksiyonel programlama dil (ler) i? [kapalı]


20

Fonksiyonel programlamayı daha iyi öğrenmek istiyorum. Bunu yapmak için, kendimi mümkün olan en saf fonksiyonel programlama dilini kullanmaya zorlamam gerektiği açıktır. Bu yüzden, burada, az ya da çok, işlevsel programlama dillerinin saflıklarına göre sıralanmasını istiyorum.

Bana öyle geliyor ki Lisp veya Clojure (ya da Scheme ya da Scala, vb.) Bundan henüz emin değilim, bu yüzden size soruyorum: en saf fonksiyonel programlama dili hangisidir? Birkaç kişi en saf fonksiyonel programlama dilinin muhteşem başlığı için yarışıyorsa, bir sıralama harika olurdu.


2
Öğrendiğim Miranda ben önyargılı değilim bu yüzden üniversitede, ama ben öneririm HASKEL isteyen herkese kendilerini batırmak dikkat dağıtıcı olmadan işlevsel bir dille safsızlık . * 8 ')
Mark Booth

2
Fonksiyonel programlamayı öğrendikten sonra, etkileyici bir tip sistemle statik olarak yazılmış programlamayı da öğrenmelisiniz. Kombine kategoride (hem işlevsel hem de daktilo) şunu öneririm: Coq> Haskell> OCaml> Scala> diğerleri. Coq ve Haskell (Epigram ve Agda gibi) arasında daha az popüler alternatifler var. Haskell, OCaml'ın etkileyici modül sistemini özlüyor.
lukstafi

Yanıtlar:


28

İşlevsel dillerin saflık derecesini değerlendirmek için bir ölçek yoktur. Dil yan etkilere izin veriyorsa saf değildir, aksi takdirde saftır. Bu tanım ile Haskell, Mercury, Clean vb. Saf işlevsel dillerdir; oysa Scala, Clojure, F #, OCaml vb.

EDIT: Belki de "dil türü sisteme izin vermeden yan etkilere izin vermiyorsa , bu saf. Aksi takdirde saf değil."


6
Pek değil: Haskell yan etkilere izin veriyor ( IOmonad). Sadece yan etkiye neden olan kod açıkça bu şekilde işaretlenmiştir. Saf / saf olmayan dillerden hiç bahsetmenin yararlı olduğunu düşünmüyorum (Haskell, zorla programlamanıza izin veriyor! / saf olmayan.
Frank Shearar

8
@Frank: Evet, Haskell yan etkilere izin veriyor, ancak yan etkiye neden olan kodu işaretlemekten daha fazlasını yapıyor. Ayrıca, yan etkiye neden olan kodu kullanırken bile referans şeffaflığını korur ve bunu en azından birçok kişinin saflık tanımı ile saflaştırır. Tabii ki, eksik faktor'un "yan etkilere izin verilmiyor" tanımıyla eşleşmiyor.
sepp2k

4
@Frank Shearar ama bunun sebebi bir şekilde konuşmak yararlıdır IOmonad olan saf. mainFonksiyonunuz temelde büyük bir durum trafosu olduğundan kodunuz değil, çalışma zamanı kütüphanesi . ( main :: World -> WorldPerde arkasındaki gibi bir şey )
alternatif

1
Dilimin de referans şeffaflığı var. Sadece yazıyorsunuz program = "some C code"ve çalışma zamanı ortamı C kodu ile ilgileniyor. :-)
Daniel Lubarov

3
Ekrana yazdırmak bir yan etki olduğu için gerçekten saf fonksiyonel programlar oldukça sıkıcıdır.

15

Öğrenme sizin hedefiniz olduğundan ve kendi başınıza program yazmamaktan dolayı Lambda Matematik'ten daha saf olamazsınız .

Lambda Calculus bilgisayarlar icat edilmeden önceydi. Çıkarmanın nasıl yapılacağını anlamak için üzerinde çalışan birkaç yetenekli mantıkçı aldı (bir süre için sadece toplama ve çarpmanın mümkün olduğu teorileşti).

Booleans ve sayıların ve ifgörünüşte hiçbir şeyden nasıl icat edilebileceğini öğrenmek, tankınıza daha fazla gaz koymaz, ancak tankınızı çok daha büyük hale getirir.


Verilmiş, muhtemelen bundan daha saf değil, ama matematik bariyerini biraz fazla aşıyoruz. İşlevsel ilkeleri benimserken programlama yapmak ve yeni bir dil öğrenmek istiyorum. Yine de, sadece fonksiyonel paradigmanın temellerini (ve daha büyük bir tanka sahip olmak) anlamak için lambda hesabını incelemenin ilginç olabileceğini kabul ediyorum.
Joanis

2
Bir ispat yazmak bir program yazmak ve bir program yazmak bir ispat yazmaktır. Curry-Howard izomorfizmi hakkında bilgi sahibi olduğunuzda, bu matematik bariyerini on bin satır önce geçtiğinizi fark edeceksiniz.
Macneil

1
Basit bir temsili yoktur -1.
Daniel Lubarov

2
@Mason Wheeler: λ-hesabında sadece rakamlar veya lambda soyutlamalarının yanı sıra herhangi bir veri yoktur. Aksi belirtilmedikçe, λ-hesabındaki sayılar hakkında konuşan herkes muhtemelen Kilisenin doğal sayıları kodlaması anlamına gelir , burada n sayısı n-katlama fonksiyonu bileşimi ile temsil edilir. Bununla birlikte, birileri gerçekten denedikten sonra çıkarma çıkarmanın çok büyük bir mücadelesi olduğu konusunda şüpheliyim ; Bir öğleden sonra, sadece çıkarma işleminin mümkün olduğu bilgisini toplayıp tanımlayarak, kendi başıma hallettim.
CA McCann

1
Vakalarla ayrıştıktan sonra Kilise rakamlarını kullanarak çıkarma kolaydır. Negatif sayıları desteklemek için tüm (türetilmiş) hesabı oluşturmak, daha fazla çalışma.
Donal Fellows

6

Saf olmayan diller, prensip olarak, bilindik zorunlu dillerden gerçekten farklı değildir, özellikle şimdi birçok işlevsel numara kopyalanmıştır. Farklı olan stil - sorunları nasıl çözdüğünüz.

Haskell'i saf olarak veya IO monadını safsızlık olarak sayın, Haskell stili bu tarzın aşırı bir biçimidir ve öğrenmeye değer.

Haskell IO monad (tabii ki) monad'ların matematiksel teorisinden türetilmiştir. Ancak, zorunlu programcılar için, monad'lara varmanın geriye doğru bir yolunun daha anlamlı olduğunu düşünüyorum.

Birinci aşama - saf işlevsel bir dil, sonuç olarak kolayca büyük bir dize değeri döndürebilir. Bu büyük dize, bazı gereksinim belirleyici parametrelerden saf bir işlevsel yolla türetilen zorunlu bir programın kaynak kodu olabilir. Daha sonra, kod üretecinizi çalıştıran bir "daha yüksek seviye" derleyicisi oluşturabilir, ardından oluşturulan kodu otomatik olarak zorunlu dil derleyicisine besleyebilirsiniz.

İkinci aşama - metinsel kaynak kodu oluşturmak yerine, güçlü bir şekilde yazılan soyut bir sözdizimi ağacı oluşturursunuz. Zorunlu dil derleyiciniz "üst düzey" derleyicinize alınır ve AST'yi doğrudan kaynak kodu olarak kabul eder. Bu Haskell'in yaptıklarına çok daha yakın.

Yine de bu garip. Örneğin, kod oluşturma aşamasında değerlendirilen ve oluşturulan program çalıştırıldığında yürütülen iki farklı işlev türünüz vardır. Biraz C ++ fonksiyonlar ve şablonlar arasındaki ayrım gibi.

Dolayısıyla, 3. aşama için, ikisini aynı yapın - aynı sözdizimine sahip aynı işlev "kod üretimi" sırasında kısmen değerlendirilebilir veya tamamen değerlendirilebilir veya hiç değerlendirilmeyebilir. Ayrıca, tüm ilmek yapı AST düğümlerini özyineleme lehine atın. Aslında, AST düğümleri fikrini tamamen özel bir veri türü olarak atın - "gerçek değere" sahip olmayan AST düğümleri, sadece değerler vb.

Bu, IO monadının yaptığı şeydir - bind operatörü, programlar oluşturmak için "eylemler" oluşturmanın bir yoludur. Bu özel bir şey değil - sadece bir işlev. Birçok kod ve işlev "kod üretimi" sırasında değerlendirilebilir, ancak G / Ç yan etkilerine bağlı olanlar, herhangi bir özel kural tarafından değil, veri bağımlılıklarının doğal bir sonucu olarak, çalışma zamanına kadar değerlendirmeyi geciktirmelidir. ifade.

Monadlar genel olarak sadece genellemedir - aynı arayüze sahiptirler, ancak soyut işlemleri farklı şekilde uygularlar, bu yüzden zorunlu kodun bir tanımını değerlendirmek yerine başka bir şeye değerlendirirler. Aynı arayüze sahip olmak, hangi monad'ı umursamadan monadlara yapabileceğiniz bazı şeyler olduğu anlamına gelir, bu da faydalı olduğu ortaya çıkar.

Bu açıklama kuşkusuz safların kafalarını patlatacak, ama bana göre Haskell'in ilginç olmasının gerçek nedenlerinden bazılarını açıklıyor. Programlama ve metaprogramlama arasındaki sınırı bulanıklaştırır ve özel sözdizimine gerek kalmadan zorunlu programlamayı yeniden icat etmek için fonksiyonel programlama araçlarını kullanır.

C ++ şablonlarına sahip olduğum bir eleştiri, zorunlu bir dilde bir tür kırık saf fonksiyonel alt dil olduklarıdır - aynı temel işlevi derleme zamanında değerlendirmek için tamamen farklı bir stil kullanarak yeniden uygulamak zorundasınız kodlama. Haskell'de, safsızlık türünde etiketlenmekle birlikte, aynı fonksiyon hem meta-programlama anlamda hem de aynı programda çalışma zamanı meta-programlama dışı anlamda değerlendirilebilir - kesin bir çizgi yoktur programlama ve meta programlama arasında.

Bununla birlikte, standart Haskell'in yapamayacağı bazı metaprogramlama şeyleri vardır, çünkü temel olarak türler (ve belki de birkaç şey) birinci sınıf değerler değildir. Bununla birlikte, bunu ele almaya çalışan dil varyantları vardır.

Haskell hakkında söylediğim birçok şey saf fonksiyonel dillerde ve hatta bazen zorunlu dillerde uygulanabilir. Haskell farklıdır, çünkü bu yaklaşımı benimsemekten başka seçeneğiniz yoktur - temel olarak sizi bu tarz bir çalışma öğrenmeye zorlar. "ML'de C" yazabilirsiniz, ancak "Haskell'de C yazamazsınız" - en azından başlık altında neler olduğunu öğrenmeden.


Teşekkür ederim! C ++ şablonlarının jenerikliğinin işlevlerin kendisinde birleştirilip birleştirilemeyeceğini merak ediyordum. Haskell bunu yapıyor gibi görünüyor, ancak önemli kısmı bunun derlenmiş bir dilde uygulanıp uygulanamayacağıdır , böylece derleme sırasında şablonlardan genel işlevler yaratan aynı motor, çalışma zamanı sırasında da bunları değerlendirebilir ...
Milind R

5

Dilleri fonksiyonel saflığın üç katmanında kişisel olarak kategorilere ayırıyorum:

  • Saf işlevsel diller - yani tüm programınıza saf bir işlev olarak davranan ve yalnızca çalışma zamanı ile etkileşim yoluyla değişebilirliği ele alan diller - Haskell muhtemelen kanonik örnektir

  • Saf olmayan fonksiyonel diller - yani işlevsel bir stili vurgulayan ancak yan etkilere izin veren diller . Clojure açıkça bu kategoridedir (STM çerçevesinin bir parçası olarak kontrollü bir şekilde mutasyona izin verir), ayrıca OCaml veya F #

  • Çok paradigma dilleri - bunlar ilk ve en önemlisi fonksiyonel diller değildir, ancak birinci sınıf işlevlerin vb. Kullanılmasıyla fonksiyonel bir stili destekleyebilir. Scala burada iyi bir örnektir, bu kategoride Common Lisp'i de koyabilirim ve hatta JavaScript gibi diller .

Sizin durumunuzda, önce Haskell'i sonra Clojure öğrenmenizi öneririm. Yaptığım buydu ve benim için çok iyi çalıştı! Haskell güzeldir ve size en saf fonksiyonel ilkeleri öğretir, Clojure çok daha pragmatiktir ve hala çok fonksiyonel olsa da çok şey yapmanıza yardımcı olur.

Üçüncü kategoriyi işlevsel diller olarak saymıyorum (Haskell ve Clojure'u öğrendikten sonra genellikle kendimi bunları kullanırken fonksiyonel tekniklerden yararlandığımı görüyorum!)


Çok katı sınırlamalar dahilinde , C bile işlevsel yeteneklere sahiptir. (Temel sınırlama, C'de gerçekten korkunç olan işlevlerin çalışma zamanı sentezidir, o kadar ki çoğu insan yapılamayacağını iddia eder.)
Donal Fellows

2
@Donal Fellows: Sınırsızlık sınırsızlığa ulaştıkça, her Turing-complete dili işlevseldir: kişinin sadece bir Lisp yorumlayıcısını dilde kullanması ve sonra kullanması gerekir. :]
CA McCann

Paradigmalar, her şeyin Turing'in tamamlandığına ve dolayısıyla diğer her şeye benzeyebileceği görüşüne bakarsanız anlamsızdır. Paradigmaları düşündüğünüzde, dilin deyimsel kıldığı ve neyi caydırdığı / engellediği üzerine odaklanmanız gerekir. Benim görüşüme göre işlevsel bir dil olarak saymak için mutasyon ve yan etkiler unidiomatik (saf olmayan FP için) veya yasaklanmış (saf FP için) olmalıdır. Bu, C'nin işlevsel olmadığı anlamına gelir. Her ikisi de Scala gibi çoklu paradigma dilleri değildir.
mikera

@mikera: Cevabınızı çok ilginç buluyorum: Scala işlevsel değil, sadece çoklu paradigma ise, C ++ 11, C # ve hatta Java'daki (lambdasların planlanan tanıtımı) fonksiyonel programlama özelliklerini nasıl değerlendiriyorsunuz?
Giorgio

@Giorgio: Sanırım bahsettiğiniz tüm dillerdeki işlevsel özellikler muhtemelen iyi bir fikirdir, sadece onları "işlevsel diller" yapmazlar. Ya da karşıt yönden bakmak için, emir tarzı monadik IO yapabileceğiniz gerçeği Haskell'i zorunlu bir dil yapmaz :-). Çok paradigma dilleri, temel olarak birçok farklı paradigmadan gelen özellikleri bir araya getirdiğinizde ve belirli bir stili her şeyden önce koymadığınızda ortaya çıkan sonuçtur. IMHO C ++, C # ve Java'nın hepsi çoklu paradigma olmaya doğru ilerliyor, ancak sınıf tabanlı OOP hâkim olduğu için henüz tam olarak orada değil.
mikera

3

Eğer saf bir işlevsel dil böyle ise, sadece saf fonksiyonlara (yan etkileri olmayan rutinler) sahipse, giriş veya yazma çıktısını okuyamadığı için biraz anlamsızdır;)

Bu gerçekten öğrenme olduğundan, ben izolasyon mutlaka olmadığını düşünüyorum gitmek için yol. Fonksiyonel programlama bir paradigmadır. Hangi paradigmaların hangi problemler için uygun olduğunu ve daha da önemlisi, bunların en iyi nasıl birleştirilebileceğini anlamak önemlidir.

Şimdi söyleyeceğim: programlama modaları aptalca ve üretken. Önemli olan tek şey programınızın kısa, yazması kolay, bakımı kolay ve doğru çalışmasıdır. Bunu nasıl başardığınızı programlama fads ile ilgisi yoktur. - Richard Jones

Eğer "saflık" arıyorsanız Bunun dışında size bir göz isteyebilirsiniz Saf . Bununla birlikte, C rutinlerini çağırmanın son derece kolay olması onu işlevsel olarak saflaştırmaz (aynı zamanda çok güçlü).


3

Tamamen ciddi bir cevap değil, ama Unlambda bir yarışmacı olmak zorunda. SKI birleştiricilerinden daha fazla "saf işlevsel" elde edemezsiniz.


4
Delilik! Sapkınlık! Yan etkileri olan birleştiriciler gibi saçmalıklar ne tür bir saf dile sahiptir? Hayır hayır. Burada asıl istediğiniz olduğu Lazy K .
CA McCann

2

Erlang, Haskell, Şema, Scala, Clojure ve F #

Bu soru muhtemelen en iyi Aramanızda size yardımcı olacaktır iyi .


Teşekkürler, gerçekten ilginç bir soru. PLT-Scheme / Racket ile başladım, ancak henüz SICP'ye bakmadım ... Gerçek Dünya Haskell de benim için oldukça ilginç görünüyor.
Joanis

Şeması fonksiyonel bir tarzı teşvik eder, ancak set!(diğer şeylerin yanı sıra) vardır ...
Daniel Lubarov

OCaml'ı öneririm, çünkü bu benim favorim. Ve Haskell ve F # özledim bir modül sistemi vardır.
lukstafi

@lukstafi belki son 3 yıl içinde haskell değişti (çılgın gibi büyüdüğünü biliyorum), ama kesinlikle haskell'de modüller var.
sara

@kai Bir modül sistemi ile, diğer modüller tarafından parametreleştirilmiş modülleri kastediyorum (modüllerin "lambda hesabı").
lukstafi
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.