Bazı işlevsel programlama dilleri neden fonksiyon uygulaması için bir boşluk kullanıyor?


34

İşlevsel programlama için bazı dillere baktığımda, bazı fp dillerinin neden işlev uygulaması (ve tanımı) için bir veya daha fazla boşluk karakteri kullandığını merak ettim, oysa çoğu (tümü?) Zorunlu / nesne yönelimli diller parantez kullanıyor; daha matematiksel yol ol. Ayrıca son modelin parens olmadan çok daha net ve okunabilir olduğunu düşünüyorum.

Yani, eğer f (x) = x² fonksiyonumuz varsa, onu çağırmanın iki alternatifi vardır:

  • FP: f x

    Örnekler:

    • ML, Ocaml, F #
    • Haskell
    • LISP, Şema (bir şekilde)
  • Sigara FP: f(x)

    Örnekler:

    • Hemen hemen tüm zorunlu diller (biliyorum, yorum / cevaplara bakınız)
    • Erlang
    • Scala (ayrıca tek değişkenler için "operatör notasyonuna" izin verir)

Parantezleri "dışlamak" için sebepler nelerdir?


9
Kafamı karıştırmak için, kısa , özlü demek istedim .
Den

11
@ Haskell'i öğrenirseniz, sözdizimi en az kafa karıştırıcı şeylerden biri olacaktır: p
Simon Bergot

5
Parantez kullanmanın daha matematiksel olacağını söyleyip, üstelleştirme işlevini örnek olarak kullanmanın ironisinin farkında mısın?
Jörg W Mittag

12
@Den sözdizimi nedeniyle bir dili reddederek kendinize zarar veriyorsunuz. Elbette xml veya sql'yi öğrenmekte hiç zorlanmadınız (bunlar genel amaçlı diller değil, ancak kendi sözdizimlerini tanımlarlar).
Simon Bergot

7
Kabuk komut dosyalarının (örneğin bash) komutları çağırmak için genellikle parametreleri kullanmadıklarını belirtmek isterim. Her iki dünyanın da en kötüsüne sahip olan PowerShell, işlevlerin parantez içinde bildirildiği ve onsuz olarak adlandırıldığını gösterir.
Kris Harper

Yanıtlar:


59

bu daha matematiksel yol gibi görünüyor

fonksiyonel diller, lambda matematiğinden ilham almaktadır . Bu alanda, parantez, işlev uygulaması için kullanılmaz.

Ayrıca son modelin parens olmadan çok daha net ve okunabilir olduğunu düşünüyorum.

Okunabilirlik, sahibinin gözündedir. Okumaya alışkın değilsin. Matematiksel operatörler gibi biraz. İlişkilendirmeyi anlarsanız, ifadenizin yapısını netleştirmek için sadece birkaç ebeveyne ihtiyacınız vardır. Genellikle onlara ihtiyacınız olmaz.

Köriler de bu sözleşmeyi kullanmak için iyi bir nedendir. Haskell'de, aşağıdakileri tanımlayabilirsiniz:

add :: Int -> Int -> Int
add x y = x + y

x = add 5 6 -- x == 11
f = add 5
y = f 6 -- y == 11
z = ((add 5) 6) -- explicit parentheses; z == 11

Parens ile iki adet kongre kullanabilirsiniz: f(5, 6)(kurutulmuş) veya f(5)(6)(kurutulmuş). Haskell sözdizimi, körleme konseptine alışmaya yardımcı olur. Körili olmayan bir sürümü hala kullanabilirsiniz, ancak kombüratörlerle kullanmak daha acı vericidir.

add' :: (Int, Int) -> Int
add' (x, y) = x + y
u = add'(5, 6) -- just like other languages
l = [1, 2, 3]
l1 = map (add 5) l -- [6, 7, 8]
l2 = map (\x -> add'(5, x)) l -- like other languages

İkinci versiyonun x'i bir değişken olarak kaydetmeye nasıl zorladığına ve alt ifadenin bir tamsayı alan ve ona 5 ekleyen bir fonksiyon olduğuna dikkat edin. Kurutulmuş versiyonu daha hafiftir, fakat aynı zamanda daha okunaklı olduğu düşünülmektedir.

Haskell programları, kısmi uygulama ve birleştiricilerin, soyutlamaları tanımlamak ve birleştirmek için yoğun bir şekilde kullanılmasını sağlar, bu nedenle bu bir oyuncak örneği değildir. İyi bir fonksiyon arayüzü, parametrelerin sırasının kolay bir şekilde kızartılmış kullanım sağladığı alan olacaktır.

Başka bir nokta: Parametresiz bir fonksiyon ile çağrılmalıdır f(). Haskell'de, yalnızca değişmez tembel olarak değerlendirilmiş değerleri manipüle ettiğiniz için, sadece yazarsınız fve gerektiğinde bazı hesaplamaları gerçekleştirmesi gereken bir değer olarak düşünürsünüz. Değerlendirmesinin herhangi bir yan etkisi olmayacağından, parametresiz işlev ve döndürülen değeri için farklı bir gösterime sahip olmanın anlamı yoktur.

İşlev uygulaması için başka kurallar da vardır:

  • Lisp: (fx) - Dış parantez içinde önek
  • İleri: xf - postfix

7
Küçük nitpick: terimler "currification" ve "currified" değil "currying" ve "curried" dir.
Doval

"curried" haskell'de curried olmayan bir fonksiyon nedir?
Ven,

3
@ user1737909 Bir argüman olarak bir tuple alan bir işlev.
Doval,

1
@Doval Aslında “schönfinkeling” ve “schönfinkeled” olmalıdır. Ama ah, peki, tarih her zaman kazananı geriye dönük olarak tanımlar.
Profpatsch

Bir Parantez tımar sözdizimi, bir şey gibi düşünmek f(a, ,b)ya add(a, )ya add(, b)varsayılan olarak daha esnek görünüyor.
phresnel

25

Temel fikir, en önemli işlemi (işlev uygulaması) okumayı ve yazmayı en kolay hale getirmektir. Bir boşluk okumak için çok müdahaleci ve yazması çok kolaydır.

Bunun işlevsel dillere özgü olmadığını, örneğin Smalltalk'ta , ilk OO dillerinden ve ondan ilham alan dillerden ( Öz , Newspeak , Objective-C) değil, aynı zamanda Io ve ondan ilham alan dillerde (Ioke, Seph), boşluk, yöntem çağrıları için kullanılır.

Smalltalk tarzı:

anArray sort
anArray add: 2
aString replace: "a" with: "b"

(İkinci durumda, yöntemin adı replace:with:.)

Io tarzı:

anArray sort
anArray add(2)
aString replace("a", "b")

Scala ayrıca yöntem çağrıları için boşluk bırakıyor:

foo bar(baz)

Ve sadece bir argüman varsa parantezleri bırakmak:

foo bar baz

Ruby ayrıca parantezleri atmanıza izin verir:

an_array.sort
an_array.add 2
a_string.replace "a", "b"

Parantez kullanmak, ki bu daha matematiksel yol gibi görünüyor.

Pek sayılmaz:

f(x)
sin x
x²
|x|
x!
x + y
xy
½

Matematik gösterimi uzun zamandır korkunç derecede tutarsız bir şekilde gelişmiştir.

Eğer hiç değilse, fonksiyonel diller ilhamlarını fonksiyon uygulamasının beyaz boşluk kullanarak yazıldığı λ hesaplarından alır.


3
Ayrıca düzenleme ekonomisi için bir argüman var. Özellikle, fonksiyonel diller tipik olarak bileşimi doğrudan destekler. Parantezler işlevinin etrafına argüman yerine koymak anlamlıdır. Bunu yalnızca "bir kez" yapmanız gerekir: (e (f (g (x))) yerine (e. F. G) x). Ayrıca, Haskell, en azından birinin, f x yerine f (x) yapmasını durduramazdı. Bu sadece aptalca değil.
nomen,

18

Fonksiyon uygulaması için parantez, Euler'in bize bıraktığı birçok eyerden sadece biri. Başka bir şey gibi, bir şeyi yapmanın birkaç yolu olduğunda matematiğin sözleşmelere ihtiyacı vardır. Eğer matematik eğitiminiz sadece üniversitedeki bir matematik dersine kadar uzanmıyorsa, o zaman muhtemelen fonksiyon uygulamasının bu saçma parantezlerin hiçbiri olmadan (örneğin Diferansiyel Geometri, Soyut Cebir) mutlu olduğu birçok alana aşina değilsinizdir. Ve bir ek alma (hemen hemen tüm diller), bir norm alma gibi ya da diyagramatik ("Befunge, Cebirsel Topoloji" gibi "dışa doğru" uygulanan işlevlerden bile bahsetmiyorsunuz.

Bu yüzden cevabım bunun geniş bir matematik eğitimine sahip fonksiyonel programcıların ve dil tasarımcılarının çok daha yüksek bir oranından kaynaklandığını söyleyebilirim. Von Neumann “Genç adam, matematikte bir şeyleri anlamıyorsun. Sadece onlara alış.” Diyor, kesinlikle bu gösterimde doğru.


7
Beni f(x)vs. sin xkarşı karşıya getirme bile - |x|vs. x!vs. x + yvs. xyvs. ½vs. - bir integral vs. toplamı vs…
Jörg W Mittag

2
Von Neuman alıntı için +1. Cevabın geri kalanında + 1, ancak + 2 veremem. :(
pvorb

2
Burada bir elitizm ipucu yakaladım; "İşlevsel programlama dili tasarımcıları daha iyi eğitimliler" in tarafsızlığına itiraz ediyorum .
CaptainCodeman

7
@ CaptainCodeman Matematik konusunda daha eğitimli olduğunu söylüyor, katılıyorum. En azından Haskell'e gelince, hem kavramların hem doğada daha matematiksel olduğunu hem de toplumun matematiksel olarak daha eğimli olduğunu fark edebilirsiniz. Daha zeki değiller, sadece matematikte daha iyi eğitilmişler.
Paul

5
@CaptainCodeman Hayır, hiçbir zaman ima etmediği için genel olarak daha eğitimli, sadece matematikte daha eğitimlidir. Aynen öyle dedi: "kapsamlı matematik eğitimi". :)
Paul,

8

Simon'ın cevabında çok fazla doğruluk olmasına rağmen, bence çok daha pratik bir sebep de var. Fonksiyonel programlamanın doğası, fonksiyon zincirlemesi ve kompozisyonu nedeniyle zorunlu programlamaya göre çok daha fazla parantez üretme eğilimindedir. Bu zincirleme ve kompozisyon kalıpları da genellikle parantez olmadan açıkça gösterilebiliyor.

Alt satırda, tüm bu parantezler okumak ve izlemek için can sıkıcı olur. Muhtemelen LISP'nin daha popüler olmamasının bir numaralı nedeni budur. Bu nedenle, fazla parantezden rahatsızlık duymadan işlevsel programlama gücüne sahip olursanız, dil tasarımcılarının bu yoldan gitme eğiliminde olacağını düşünüyorum. Ne de olsa, dil tasarımcıları da dil kullanıcısıdır.

Scala bile, programcının işlevsel bir şekilde programlama yaparken oldukça sık görülen bazı durumlarda parantezleri atlamasına izin verir, böylece her iki dünyanın da en iyisini elde edersiniz. Örneğin:

val message = line split "," map (_.toByte)

Sonundaki parenler ilişkilendirme için gereklidir ve diğerleri bırakılır (noktaların yanı sıra). Bu şekilde yazmak, yaptığınız işlemlerin zincirleme yapısını vurgular. Zorunlu bir programlayıcıya tanıdık gelmeyebilir, ancak işlevsel bir programcıya bu yolla yazmak için çok doğal ve akıcı bir his vardır, programa anlam katan sözdizimi bırakmak ve eklemek zorunda kalmadan, sadece derleyiciyi mutlu etmek için oradadır. .


2
“Sonuç olarak, tüm bu parantezler okumak ve izlemek için can sıkıcı oluyor. LISP'nin daha popüler olmasının bir numaralı nedeni bu.”: Parantezlerin Lisp'in popüler olmamasının bir nedeni olduğunu sanmıyorum. özellikle okumak zor, ve diğer dillerin çok daha garip bir sözdizimine sahip olduğunu biliyorum.
Giorgio

2
LISP sözdizimi, süper-yüksek diklik derecesiyle sinir bozucu parantezleri oluşturur. Bu sadece, ebeveynlerin can sıkıcı olmadığından değil, onu hala kullanılabilir kılan diğer özelliklere sahip olduğu anlamına gelir. Anladığım kadarıyla herkes böyle hissetmiyor, ancak tanıştığım programcıların büyük çoğunluğu bunu yapıyor.
Karl Bielefeldt

"Kayıp Aptal Parantezler" en sevdiğim LISP backronym. Bilgisayarlar ayrıca kod bloklarını belirlemek ve Wisp gibi dillerde olduğu gibi artıklığı azaltmak için insancıl yolu kullanabilir .
Cees Timmerman

4

Her iki binada yanlış.

  • Bu fonksiyonel diller yok fonksiyon uygulaması için boşluk kullanın. Yaptıkları şey, sadece bir fonksiyondan sonra gelen herhangi bir ifadeyi argüman olarak ayrıştırmaktır.

    GHCi> f 3
    4
    GHCi> f (3)
    4
    GHCi> (f) 3
    4

    Tabii eğer ne boşluk ne de parens kullanırsanız , normalde işe yaramaz, çünkü ifade uygun şekilde belirtilmemiş

    GHCi> f3

    <etkileşimli>: 7: 1:
        Kapsamda değil: 'f3'
        Belki de 'f' demek istediniz (satır 2)

    Fakat eğer bu diller 1 karakterlik değişken isimleri ile sınırlıysa, o zaman da işe yarayabilirdi.

  • Matematik sözleşmeler normalde işlev uygulaması için parantez gerektirmez. Sadece matematikçiler sık ​​sık sin x yazmazlar - lineer fonksiyonlar için (genellikle o zaman lineer operatörler olarak adlandırılırlar), argümanı parens olmadan yazmak çok olağandır, çünkü (belki de fonksiyonel programlamadaki herhangi bir fonksiyonda olduğu gibi) lineer fonksiyonlar genellikle doğrudan sağlamadan kullanılır. tartışma.

Bu yüzden gerçekten, sorunuz aşağı yukarı: neden bazı dillere fonksiyon uygulaması için parantez gerekir? Görünüşe göre bazı insanlar, senin gibi, bunu daha okunaklı olarak görüyorlar. Buna kesinlikle katılmıyorum: bir çift parens iyidir, ancak ikisinden daha fazla iç içe geçtiğinizde kafa karıştırıcı olmaya başlar. Lisp kodu bunu en iyi şekilde gösterir ve hemen hemen her yerde paren gerektiğinde tüm işlevsel diller benzer şekilde karışık görünüyordu. Bu zorunluluk dillerinde çok fazla olmuyor, fakat esas olarak bu diller özlü yazacak kadar açık ifade edemediklerinden, ilk başta tek gömlekleri temizleyebiliyorlar.


Anladım, soru mükemmel değil. :) Bu yüzden, çizmek için sonuç: “Parantez ölçeklenmiyor”.
pvorb

2
Ayrıca parantez gerektirmeyen oybirliği bulunan dilleri de değildir ; Birkaç örnek için, Smalltalk object method: args, Objective C'nin sahip [object method: args]olduğu ve Ruby ve Perl'in her ikisi de, yalnızca belirsizliği çözmelerini gerektiren, işlev ve yöntem çağrılarında parantezlerin çıkarılmasını sağlar.
hobbs

1

Küçük bir tarihsel açıklama: Matematiğin orijinal notasyonu parantezsizdi !

X'in keyfi bir işlevi için kullanılan fx notasyonu , Leibniz'in fonksiyonlardan bahsetmeye başlamasından kısa bir süre sonra, 1700 civarında Johan Bernoulli tarafından tanıtıldı (aslında Bernoulli ϕ x yazdı ). Ama zaten günah gibi açıklamalar kullanılarak birçok kişiye önce x veya lx (logaritması x için) belirli işlevleri x parantez olmadan. Bugün birçok insanın hala günah (x) yerine günah x yazmasının nedeni budur .

Bernoulli öğrenciyken Euler, Bernoulli evlatlık φ x ve yazma, bir latin harfi içine bir Yunan değişti fx . Daha sonra f'yi "miktar" için karıştırmanın kolay olabileceğini fark etti ve fx'in bir ürün olduğuna inandı , bu yüzden f: x yazmaya başladı . Dolayısıyla f (x) notasyonu Euler'den kaynaklanmamaktadır. Tabii Euler biz hala işlevsel programlama dillerinde parantez gerek aynı nedenle parantez gerekli: örneğin ayırt etmek + (fx) y den f (x + y) . Euler'den sonra parantezi varsayılan olarak benimsemiş olduklarından şüpheleniyorum çünkü çoğunlukla Euler'in f (ax + b) gibi bileşik ifadeler yazdığını gördüler.. Nadiren sadece fx yazdı .

Bu konuda daha fazla bilgi için: Euler hiç parantez ile f (x) yazdı mı? .

Fonksiyonel programlama dillerinin tasarımcılarının mı yoksa lambda hesabının mucitlerinin notasyonlarının tarihsel köklerinin farkında olup olmadığını bilmiyorum. Şahsen ben parantezsiz gösterimi daha doğal buluyorum.

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.