Python neden işlevsel programlama için çok iyi değil? [kapalı]


324

Her zaman fonksiyonel programlamanın Python'da yapılabileceğini düşündüm. Bu nedenle, Python'un bu soruda çok fazla söz almamasına şaşırdım ve bahsedildiğinde, normalde çok olumlu değildi. Ancak, bunun için pek bir neden belirtilmedi (örüntü eşleşmesi eksikliği ve cebirsel veri türleri belirtildi). Benim sorum şu: Python işlevsel programlama için neden çok iyi değil? Örüntü eşleme ve cebirsel veri türlerinin eksikliğinden daha fazla neden var mı? Yoksa bu kavramlar fonksiyonel programlama için o kadar önemli midir, onları desteklemeyen bir dil sadece ikinci sınıf fonksiyonel programlama dili olarak sınıflandırılabilir mi? (İşlevsel programlama deneyimimin oldukça sınırlı olduğunu unutmayın.)


2
2018 - Hindistan Cevizi (Python'a derleyen işlevsel bir programlama dili) Python'da fonksiyonel programlamayı geliştirir. Ayrıca IBM, makalelerin bu diziyi bakın page1 page2 sayfa3
cssyphus

Yanıtlar:


393

Referans verdiğiniz soru, hangi dillerin hem OO hem de fonksiyonel programlamayı desteklediğini sorar. Python, oldukça iyi çalışmasına rağmen fonksiyonel programlamayı desteklemez .

Python'da fonksiyonel programlamaya karşı en iyi argüman , zorunlu / OO kullanım durumlarının Guido tarafından dikkatle ele alınırken, fonksiyonel programlama kullanım durumlarının dikkate alınmamasıdır. Zorunlu Python yazdığımda, bildiğim en güzel dillerden biri. İşlevsel Python yazdığımda , BDFL'ye sahip olmayan ortalama diliniz kadar çirkin ve tatsız hale geliyor .

Bu kötü olduğu anlamına gelmez, sadece fonksiyonel programlamayı destekleyen bir dile geçtiğinizde veya OO Python yazmaya geçtiğinizde olduğundan daha fazla çalışmanız gerekir.

İşte Python'da özlediğim fonksiyonel şeyler:


  • Desen eşleşmesi ve kuyruk özyineleme olmaması, temel algoritmalarınızın zorunlu olarak yazılması gerektiği anlamına gelir. Python'da özyineleme çirkin ve yavaştır.
  • Küçük bir liste kütüphanesi ve işlevsel sözlükler yok, birçok şeyi kendiniz yazmanız gerektiği anlamına gelir.
  • Körelme veya kompozisyon için sözdizimi olmaması, noktasız stilin, açıkça geçen argümanlar kadar noktalama işareti ile dolu olduğu anlamına gelir.
  • Tembel listeler yerine yineleyiciler, verimlilik mi yoksa kalıcılık mı istediğinizi bilmeniz ve kalıcılık istiyorsanız aramaları dağıtmanız gerektiği anlamına gelir list. (Yineleyiciler bir kez kullanılır)
  • Python'un basit zorunlu sözdizimi, basit LL1 ayrıştırıcısı ile birlikte if-ifadeleri ve lambda ifadeleri için daha iyi bir sözdiziminin temel olarak imkansız olduğu anlamına gelir. Guido bunu bu şekilde seviyor ve bence haklı.

5
Kuyruk özyineleme eksik +1 için - döngü yapıları yerini almış olsa da, hala Python ve Scheme arasında kaymaya değer bir şey.
yeni123456

5
Bütünlük ve kompozisyon için mükemmel cevap. Ne yazık ki, güçlü bir işlevsel arka plana sahip birçok cevapta olduğu gibi, IMO'nun kötüye kullanım terminolojisine sahiptir. Bir cevapta her kavramı ayrıntılı olarak anlayamayacağınızı anlasam da, "kalıp eşleme", "işlevsel sözlükler", "currying" veya " tembel listeler ".
ThomasH

4
İyi bir nokta; Bence çözüm link eklemek. Cevabımı düzenlemek için yeterli temsilciniz var mı? Eğer öyleyse çeşitli kavramlara bağlantılar eklemek için çekinmeyin. Daha sonra zamanım olduğunda başlayacağım.
Nathan Shively-Sanders

5
Bunun 5 yaşında olduğunun farkındayım, ama… sanki işlevsel dillerden değil, Haskell'den özlediğiniz şeylerle ilgili . Örneğin, çoğu ML ve Lisp lehçeleri ve torunları otomatik kıvrılmaya sahip değildir, noktasal tarzı aşırı ayrıntılı hale getirir, tembel listelere sahip değildir, vb. ikisi de CaML'yi korkunç bir işlevsel dil yapmamalıdır ?
abarnert

4
@abarnert: Caml, kütüphane olarak kullanılabilen tembel listeler hariç her mermi noktasına sahiptir. Bu yanıtı yazdığım sırada Caml kullandım ve şu anda F # kullanıyorum. Her ikisi de çok güzel fonksiyonel dillerdir.
Nathan Shively-Sanders

102

Guido'nun burada iyi bir açıklaması var . İşte en alakalı kısım:

İnsanların ne söylediklerine ya da düşünmelerine bakılmaksızın, Python'un işlevsel dillerden çok fazla etkilendiğini hiç düşünmedim. C ve Algol 68 gibi zorunlu dillere çok aşinaydım ve birinci sınıf nesneler işlevlerini yerine getirmeme rağmen, Python'u işlevsel bir programlama dili olarak görmedim. Ancak, daha önce, kullanıcıların listeler ve işlevlerle daha fazlasını yapmak istediği açıktı.

...

Python'u işlevsel bir dil olarak görmeme rağmen, kapanışların tanıtımının diğer birçok gelişmiş programlama özelliğinin geliştirilmesinde yararlı olduğunu da belirtmek gerekir. Örneğin, yeni stil sınıflarının, dekoratörlerin ve diğer modern özelliklerin belirli yönleri bu yeteneğe dayanır.

Son olarak, yıllar boyunca bir dizi işlevsel programlama özelliği kullanılmasına rağmen, Python hala “gerçek” fonksiyonel programlama dillerinde bulunan bazı özelliklerden yoksundur. Örneğin, Python belirli türde optimizasyonlar gerçekleştirmez (örn. Kuyruk özyineleme). Genel olarak, Python'un son derece dinamik doğası nedeniyle Haskell veya ML gibi fonksiyonel dillerden bilinen derleme zamanı optimizasyonunu yapmak imkansızdır. Ve bu iyi.

Bundan iki şey çıkarıyorum:

  1. Dilin yaratıcısı Python'u işlevsel bir dil olarak görmüyor. Bu nedenle, "işlevsel-esque" özelliklerini görmek mümkündür, ancak kesin olarak işlevsel olan herhangi bir şey görmeniz olası değildir.
  2. Python'un dinamik yapısı, diğer işlevsel dillerde gördüğünüz optimizasyonların bazılarını engeller. Verilen Lisp, Python kadar dinamik (daha dinamik değilse), bu yüzden bu sadece kısmi bir açıklama.

8
Sadece Python kuyruk çağrı optimizasyonu yapabilirsiniz. Guido bunu anlamadı / anlamadı.
Jules

26
Guido van Rossum'un işlevsel tarzı sevmediğine bağlı gibi görünüyor .
Svante

59
Sanırım Guido van Rossum'un işlevsel stili anlamadığını ve Python'un neden onlara ihtiyacı olduğunu anlamadığını söylemek daha doğru. İki şeyi anlamalısınız: 1) programlama dilleri bir teknoloji yığınının altındadır ve üzerine inşa edilen her şeyi etkiler ve 2) diğer herhangi bir yazılım parçası gibi, özellikleri eklemek, onları kaldırmaktan daha kolaydır. Bu yüzden bir dil tasarımcısının bu tür istekleri eleştirmesi iyi bir kalite.
Jason Baker

8
"Verilmiş, Lisp aynı derecede dinamik" -> ve aynı derecede zorunlu!
pyon

6
@Jules, Python'da kuyruk çağrı optimizasyonu kullanımı için bir rehber paylaşmayı düşünür müsünüz? Bazı kaynaklara yönelik bir işaretçi yararlı olacaktır.
David

52

Şemada cebirsel veri türleri veya kalıp eşleşmesi yoktur ancak kesinlikle işlevsel bir dildir. İşlevsel bir programlama perspektifinden Python hakkında can sıkıcı şeyler:

  1. Sakat Lambdas. Lambdas sadece bir ifade içerebildiğinden ve her şeyi bir ifade bağlamında bu kadar kolay yapamayacağınız için, "anında" tanımlayabileceğiniz işlevlerin sınırlı olduğu anlamına gelir.

  2. Ifs ifadeler değil, ifadelerdir. Bu, diğer şeylerin yanı sıra, içinde bir If olan bir lambdaya sahip olamayacağınız anlamına gelir. (Bu Python 2.5'teki üçlüler tarafından düzeltildi, ancak çirkin görünüyor.)

  3. Guido tehdit harita, filtreyi kaldırmak ve azaltmak Arada bir her

Öte yandan, python'un sözcüksel kapanışları, Lambdasları ve liste kavrayışları vardır (Guido'nun kabul edip etmediğini gerçekten "işlevsel" bir kavramdır). Python'da bol miktarda "işlevsel tarzda" programlama yapıyorum, ama bunun ideal olduğunu söyleyemem.


3
Python'da harita, filtre ve azaltma gerçekten gerekli değildir. Henüz onları kullanarak çok basitleştirilmiş bir kod parçası görmek zorunda. Ayrıca, Python'daki çağrı işlevleri pahalı olabilir, bu yüzden bir liste / jeneratör kavrama veya zaten bir for döngüsü kullanmak genellikle daha iyidir.
Jason Baker

2
Nathan Sanders tam olarak şunları söylüyor: "Python, oldukça iyi çalışmasına rağmen fonksiyonel programlamayı desteklemiyor." Guido, Python'un işlevsel bir dil olmasını isterse, uygulamanın atma işlevlerini kullanacak kadar iyi çalışmasını sağlar ve Lambdas'ı gerçekten harita / filtre / azaltma gibi faydalı biçimlerde kullanabileceğiniz ölçüde çözer. Öte yandan, işlevsel insanlar liste kavrayışının şaşkınlığına uyanmaya başlıyor. Umarım birini ya da diğerini seçmek zorunda kalmayacağız.
Jacob B

7
harita ve filtre önemsiz bir şekilde bir liste kavrayışı ile değiştirilir. azaltma - neredeyse her zaman - bir jeneratör fonksiyonu ile değiştirilmesi gerektiği kadar verimsiz.
S.Lott

13
@ S.Lott bir jeneratör ile azaltmayı nasıl değiştirirsiniz?
Antimon

17
@JacobB Liste anlaşmaları, Python'un icat edilmesinden yaklaşık 15 yıl önce ve Python bu özelliğin uygulanmasından 25 yıl önce işlevsel dillerde mevcuttu. Python'un yayılmalarını etkilediği ya da fp'nin Python'dan öğrendiği ya da fp dünyasının Python uygulamasından sonraki tarihlerdeki popülaritesinin basitçe yanlış olduğu fikri. Python'un uygulaması doğrudan Haskell'den alındı. Belki seni yanlış anladım ve demek istediğin bu değil, ama ben "işlevsel insanlar liste kavrayışının kötülüğüne uyanmaya başlıyor " diye şaşkınım.
itsbruce

23

Python'u asla “işlevsel” olarak adlandırmam ama Python'da her programladığımda kod her zaman neredeyse tamamen işlevsel oluyor.

Kuşkusuz, bu esas olarak çok iyi bir liste kavrayışı nedeniyle. Bu yüzden mutlaka Python'u işlevsel bir programlama dili olarak önermem ama Python'u kullanan herkes için işlevsel programlama önerebilirim.


17

SO'daki "işlevsel" bir Python sorusuna verilen yanıttan alınan bir kod parçasıyla göstereyim

Python:

def grandKids(generation, kidsFunc, val):
  layer = [val]
  for i in xrange(generation):
    layer = itertools.chain.from_iterable(itertools.imap(kidsFunc, layer))
  return layer

Haskell:

grandKids generation kidsFunc val =
  iterate (concatMap kidsFunc) [val] !! generation

Burada temel fark Haskell'ın standart kütüphane fonksiyonel programlama için kullanışlı fonksiyonlar olmasıdır: bu durumda iterate, concatve(!!)


7
İşte için tek satırlık yer değişikliği grandKids()jeneratör ifadelerle vücuda: return reduce(lambda a, v: concat((x for x in kidsFunc(v)) for v in a), xrange(generation), [val]).
Lloeki

6
Ve işte bunlardan birine gerek concatyok:return reduce(lambda a, v: (x for v in a for x in kidsFunc(v)), xrange(generation), [val])
Lloeki

9
@Lloeki: yineleme bu kodu önemli ölçüde basitleştirir ve (kidsFunc (v) içindeki x için x için x için x) concatMap (kidsFunc) olarak çok daha açıktır. Python'un güzel üst düzey yapıların eksikliği Haskell'e kıyasla eşdeğer kod şifreleme ve ayrıntılı hale getirir.
Phob

2
concat değiştirilebiliritertools.chain.from_iterable
Antimon

@Antimony: bilmek güzel. thx
yairchu

14

Bu soru (ve cevaplar) için gerçekten önemli olan bir şey şudur: Cehennem fonksiyonel programlama ve bunun en önemli özellikleri nelerdir. Görüşümü vermeye çalışacağım:

Fonksiyonel programlama, beyaz tahtaya matematik yazmak gibidir. Bir beyaz tahtaya denklemler yazdığınızda, bir yürütme emri düşünmezsiniz. Mutasyon yoktur (tipik olarak). Ertesi gün geri dönüp ona bakmazsınız ve hesaplamaları tekrar yaptığınızda farklı bir sonuç elde edersiniz (ya da taze kahveniz varsa :)). Temel olarak, tahtada olan şey orada ve bir şeyler yazmaya başladığınızda cevap zaten oradaydı, henüz ne olduğunu henüz anlamadınız.

Fonksiyonel programlama buna çok benzer; bir şeyleri değiştirmezsiniz, sadece denklemi değerlendirirsiniz (veya bu durumda, "program") ve cevabın ne olduğunu anlarsınız. Program hala orada, değiştirilmemiş. Verilerle aynı.

Fonksiyonel programlamanın en önemli özellikleri olarak aşağıdakileri sıralarım: a) referans şeffaflığı - aynı ifadeyi başka bir zaman ve yerde değerlendirirseniz, ancak aynı değişken değerlerle, yine de aynı anlama gelir. b) yan etki yok - beyaz tahtaya ne kadar süre bakarsanız bakın, başka bir adamın başka bir beyaz tahtaya baktığı denklem yanlışlıkla değişmez. c) fonksiyonlar da değerlerdir. diğer değişkenlerle veya bu değişkenlere iletilebilir. d) fonksiyon kompozisyonu, h = g · f yapabilir ve böylece g (f (..)) çağrısına eşdeğer olan yeni bir fonksiyon h (..) tanımlayabilirsiniz.

Bu liste benim öncelikli sıralamamdadır, bu nedenle referans şeffaflığı en önemlisidir, ardından yan etki yoktur.

Şimdi, python üzerinden giderseniz ve dil ve kütüphanelerin bu yönleri ne kadar iyi desteklediğini ve garanti ettiğini kontrol ederseniz - o zaman kendi sorunuza cevap verme yolundasınız.


2
İşlevler Python'da birinci sınıftır.
Carl Smith

@CarlSmith Bu, Python'un sahip olmadığı 3/4 bırakır. : - \
arya

1
Python'un fonksiyonel programlama için iyi bir dil olduğunu düşünmüyorum. Dürüst olmak gerekirse bu yorumdan kastettiğimden bile emin değilim. Cevapla alakalı görünmüyor. Silebilirdim, ama sonra yorumunuz bağlam dışı olurdu.
Carl Smith

1
Referans şeffaflığı ve değişmezliği gerçekte dil özellikleri değildir. Evet, bazı diller (Haskell) onları vurgular ve sahip olmamalarını zorlaştırır, ancak aslında herhangi bir dilde referans olarak saydam bir işlev veya değişmez bir nesne yapabilirsiniz. Sadece, genellikle onları ihlal edecek olan standart kütüphane etrafında çalışmanız gerekir.
Kevin

Ayrıca, Python'un hem körleme hem de kompozisyon için desteği var, ancak dil düzeyinde değil, bunun yerine standart kütüphanede.
Kevin

10

Python neredeyse işlevsel bir dildir. "İşlevsel lite".

Ekstra özelliklere sahiptir, bu yüzden bazıları için yeterince saf değildir.

Ayrıca bazı özelliklerden yoksundur, bu yüzden bazıları için yeterince eksiksiz değildir.

Eksik özelliklerin yazılması nispeten kolaydır. Python'da FP'de bunun gibi yayınlara göz atın .


2
Çoğunlukla, bu gönderiye katılıyorum. Ama Python'un işlevsel bir dil olduğunu söyleyemem. Zorunlu programlamayı çok teşvik eder ve bahsettiğiniz "ekstra özellikler" ile yapmamak zordur. Sanırım diğer yazıdaki gibi Python'u "fonksiyonel lite" olarak adlandırmak en iyisidir. :-)
Jason Baker

8
-1 Üzgünüm, hayır. Yani, sadece, hayır. İşlevsel diller biçimsel akıl yürütmeyi kolaylaştıran yapılar sağlar: tümevarım (ML), denklem (Haskell). Kapanışlar ve anonim işlevler tek başına strateji modeli için sözdizimsel şekerdir.
pyon

8

Yukarıda belirtilmeyen bir başka neden, birçok yerleşik işlev ve yerleşik tür yönteminin bir nesneyi değiştirmesi, ancak değiştirilen nesneyi döndürmemesidir. Bu değiştirilmiş nesneler döndürülürse, bu, işlevsel kodu daha temiz ve daha özlü hale getirir. Örneğin, some_list.append (some_object), some_object eklenmiş halde some_list döndürdüyse.


4

Diğer cevaplara ek olarak, Python ve diğer birçok paradigma dillerinin gerçek fonksiyonel programlama için uygun olmamalarının bir nedeni, derleyicilerinin / sanal makinelerinin / çalışma sürelerinin fonksiyonel optimizasyonu desteklememesidir. Bu tür bir optimizasyon, derleyicinin matematiksel kuralları anlamasıyla elde edilir. Örneğin, birçok programlama dili bir mapişlevi veya yöntemi destekler . Bu, bir işlevi bir argüman olarak alan oldukça standart bir işlevdir ve ikinci argüman olarak yinelenebilir, bu işlevi yinelenebilir her öğeye uygular.

Neyse o çıkıyor map( foo() , x ) * map( foo(), y )aynıdır map( foo(), x * y ). Sonuncusu aslında öncekinden daha hızlıdır, çünkü ikincisi ikincisini bir tane gerçekleştirdiği yerde iki kopya yapar.

Daha iyi fonksiyonel diller bu matematiksel temelli ilişkileri tanır ve optimizasyonu otomatik olarak gerçekleştirir. İşlevsel paradigmaya adanmamış diller büyük olasılıkla optimize edilmeyecektir.


map( foo() , x ) * map( foo(), y ) == map( foo(), x * y )tüm işlevler için geçerli değildir. Örneğin, foobir türevi hesaplarken durumu düşünün .
Eli Korvigo

1
Sanırım onun +yerine demek istiyordu *.
user1747134

Foo () 'un doğrusal olduğunu mu düşünüyorsunuz?
juan Isaza

bu özellik foo (x) = x + 1 için doğru DEĞİLDİR. Olarak (x + 1) * (y + 1)! = X * y + 1.
juan Isaza
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.