Neden çoğu programlama dili, işlevleri bildirmek için özel bir anahtar kelimeye veya sözdizimine sahiptir? [kapalı]


39

Çoğu programlama dili (hem dinamik hem de statik olarak yazılmış diller), işlevleri bildirmek için değişken bildirmekten çok farklı görünen özel anahtar kelime ve / veya sözdizimine sahiptir. İşlevleri tıpkı adlandırılmış başka bir varlık bildirmek gibi görüyorum:

Örneğin Python'da:

x = 2
y = addOne(x)
def addOne(number): 
  return number + 1

Neden olmasın:

x = 2
y = addOne(x)
addOne = (number) => 
  return number + 1

Benzer şekilde, Java gibi bir dilde:

int x = 2;
int y = addOne(x);

int addOne(int x) {
  return x + 1;
}

Neden olmasın:

int x = 2;
int y = addOne(x);
(int => int) addOne = (x) => {
  return x + 1;
}

Bu sözdizimi, bir şeyi (bir işlev veya değişken olabilir) ve bazı dillerde defveya daha az anahtar kelimeyi tanımlamanın daha doğal bir yoludur function. Ve IMO, daha tutarlıdır (değişken veya fonksiyonun tipini anlamak için aynı yere bakarım) ve muhtemelen ayrıştırıcı / gramer yazmayı biraz daha basitleştirir.

Çok az dilde bu fikri kullandığını biliyorum (CoffeeScript, Haskell) ancak çoğu dilde işlevler için özel sözdizimi vardır (Java, C ++, Python, JavaScript, C #, PHP, Ruby).

Her iki yolu da destekleyen (ve tür çıkarımı olan) Scala'da bile yazmak daha yaygındır:

def addOne(x: Int) = x + 1

Ziyade:

val addOne = (x: Int) => x + 1

IMO, Scala'da en az bu olanı, muhtemelen en kolay anlaşılabilir versiyonudur, ancak bu deyim nadiren izlenir:

val x: Int = 1
val y: Int = addOne(x)
val addOne: (Int => Int) = x => x + 1

Kendi oyuncak dilim üzerinde çalışıyorum ve dilimi bu şekilde tasarlarsam herhangi bir tuzak olup olmadığını ve herhangi bir tarihsel veya teknik sebep olup olmadığını merak ediyorum.


9
Sebep muhtemelen tarihi. İlk kim yaptıysa, o şekilde yaptı ve diğerleri kopyaladı. Ama kesin olarak bildiğimizden şüpheliyim.

29
Bunun nedeni, bir işlev veya yöntemin yalnızca başka bir adlandırılmış varlık olmadığıdır . İşlevsel dillerde, onlar (onları etrafa geçirebilirsin vb.) Ama diğer dillerde (Java gibi) bir işlev veya yöntem basit bir değişkenden tamamen farklı bir şeydir ve bu şekilde değerlendirilemez (Java 8'in bunu zayıflattığını kabul ediyorum). deyim), dolayısıyla farklı davrandıklarından , işlevleri / yöntemleri farklı tanımlamak mantıklıdır .
11684

15
Önerinizin, işlevleri bildirmenin daha doğal bir yolu olduğunu kabul etmiyorum. Coffeescript'in sözdizimini gerçekten beğenmedim ve bunun bir kısmı işlev bildirimi sözdizimi ile ilgili. Gerçek şu ki, eğer kırılmadıysa düzeltmeyin. 'Def' ya da 'function' yazmak çok önemli değildir ve düşünülmeyen ya da yorgun gözlerle kolayca başka bir şeyle karıştırılabilecek olan bazı süslü Perl benzeri sembollere kıyasla bir bakış daha açıktır. Tamamen kişisel bir notta, örneklerdeki önerilen söz diziminizin mevcut sözdiziminden daha çirkin göründüğünü de düşünüyorum.
Roy

22
'=>' Nasıl " işlev bildirmek için özel bir anahtar kelime veya sözdizimi " değil?
TML

11
Seni bilmiyorum, ama benim (int => int) addOne = (x) => {için çok daha "özel" ve "karmaşık" int addOne(int) {...
Bogdan Alexandru

Yanıtlar:


48

Bunun nedeni, en popüler dillerin, C dilleri ailesinden, fonksiyonel dillerin ve onların kökleri olan lambda matematiğinden geldiği ya da etkilendiğidir.

Ve bu dillerde, işlevler yalnızca başka bir değer değildir :

  • C ++, C # ve Java ile işlevleri aşırı yükleyebilirsiniz: aynı ada sahip iki işleviniz olabilir ancak farklı imzalar olabilir.
  • C, C ++, C # ve Java'da, işlevleri temsil eden değerlere sahip olabilirsiniz, ancak işlev işaretçilerine, işlevlere, delegelere ve işlevsel arabirimlere hepsi işlevlerden farklıdır. Sebeplerin bir kısmı, çoğu aslında sadece fonksiyonlar değil, bazı (değişken) durumlarla birlikte bir fonksiyondur.
  • Değişkenler varsayılan (Eğer kullanıma zorunda tarafından kesilebilir const, readonlyya da finalmutasyon yasaklamaya), ancak işlevleri yeniden edilemez.
  • Daha teknik bir bakış açısıyla, kod (işlevlerden oluşur) ve veriler ayrıdır. Tipik olarak belleğin farklı kısımlarını işgal ederler ve farklı şekilde erişilirler: kod bir kere yüklenir ve sonra sadece yürütülür (ancak okunmaz veya yazılmaz), ancak veriler genellikle sürekli olarak tahsis edilir ve tahsis edilir ve yazılmaz ve okunmaz, ancak asla çalıştırılmaz.

    C'nin "metale yakın" olması gerektiği için, bu ayrımı dilin sözdiziminde de yansıtmak mantıklıdır.

  • İşlevsel programlamanın temelini oluşturan "işlev sadece bir değerdir" yaklaşımı, C ++, C # ve Java'daki lambdaların geç tanıtılmasıyla kanıtlandığı gibi, yalnızca nispeten yakın zamanlarda ortak dillerde çekiş kazanmıştır (2011, 2007, 2014).


12
C #, anonim işlevlere sahipti - bunlar sadece türden çıkarım olmadan lambdalar ve tıknaz bir sözdizimi - 2005'ten beri.
Eric Lippert

2
"Daha teknik bir bakış açısıyla, kod (işlevlerden oluşur) ve veriler ayrıdır" - bazı diller, en iyi bilerek LISP'ler bu ayrımı yapmaz ve kod ve verilere gerçekten çok farklı davranmaz. (LISP'ler en iyi bilinen örnektir, ancak bunu yapan REBOL gibi başka diller de vardır)
Benjamin Gruenbaum

1
@ BenjaminGruenbaum Dil düzeyinde değil, derlenmiş koddan bahsediyordum.
svick

C, en azından hafifçe başka bir değer olarak kabul edilebilecek fonksiyon işaretçilerine sahiptir. Emin olmak için uğraşmak için tehlikeli bir değer, ancak garip şeyler oldu.
Patrick Hughes,

@PatrickHughes Evet, onlardan ikinci noktama değiniyorum. Ancak işlev işaretçileri işlevlerden oldukça farklıdır.
svick

59

Bunun nedeni, insanların işlevlerin sadece “bir başka adlandırılmış varlık” olmadığını fark etmeleridir. Bazen onları bu şekilde manipüle etmek mantıklı geliyor, ancak yine de bir bakışta tanınabiliyorlar.

Bilgisayarın sözdizimi hakkında ne düşündüğü önemli değildir, çünkü anlaşılmaz bir karakter bloğu, bir makinenin yorumlaması için iyidir, ancak insanların anlaması ve sürdürmesi imkansızdır.

Bu gerçekten neden ve ne zaman döngüler, geçiş ve başka bir şey, vb sonuçta hepsi bir aa karşılaştırmak ve atlama talimatı için kaynamaya rağmen neden aynıdır. Sebebi, kodu koruyan ve anlayan insanların yararına orada bulunmasıdır.

İşlevlerinizi "başka bir adlandırılmış varlık" olarak teklif ettiğiniz şekilde kullanmak, kodunuzun görülmesini zorlaştıracak ve dolayısıyla anlaşılmasını zorlaştıracaktır.


12
Ben sayılan öğelerin gibi işlevleri tedavi olduğunu katılmıyorum mutlaka kod zor anlamak için yapar. Bu, prosedürel bir paradigmayı izleyen herhangi bir kod için neredeyse kesinlikle doğrudur, ancak işlevsel bir paradigmayı izleyen kod için doğru olmayabilir.
Kyle Strand

29
“Bu gerçekten neden döngüler için ve niçin sahip olduğumuzla aynı sebepten ötürü, hepsi sonunda sonuçta bir kıyaslama ve atlama talimatı ile kaynaşmış olsa bile , geçiş ve diğer durumlarda vb . ” +1 buna. Tüm programcılar makine dilinde rahat olsaydı, tüm bu fantezi programlama dillerine (yüksek veya düşük seviye) ihtiyacımız olmazdı. Ancak gerçek şu ki: Herkes makineye kodlarını yazmak istedikleri yere göre ne kadar farklı bir konfor seviyesine sahiptir. Seviyenizi bulduktan sonra, size verilen sözdizimine bağlı kalmanız (ya da gerçekten rahatsızsanız kendi dilinizi ve derleyicinizi yazmanız) yeterlidir.
Hoki

12
+1. Daha kısa ve öz bir versiyon "Doğal diller neden isimleri fiillerden ayırıyor?" Olabilir.
msw

2
“bir makinenin yorumlayabilmesi için anlaşılmaz bir karakter bloğu iyidir, ancak bu, insanların anlaması ve sürdürmesi için imkansızdır.” Soruda önerildiği gibi mütevazi bir sözdizimsel değişim için ne kadar kızarık bir nitelik. Biri hızlı bir şekilde sözdizime adapte olur. Bu öneri, OO yönteminin çağrı sözdizimi object.method (args) zamanında olduğundan, konvansiyondan çok daha az radikal bir ayrılmadır , ancak ikincisi insanların anlaması ve sürdürmesi için neredeyse imkânsız değildir. Çoğu OO dilinde yöntemlerin sınıf örneklerinde saklandığı gibi düşünülmemesi gerektiğine rağmen.
Marc van Leeuwen

4
@MarcvanLeeuwen. Yorumunuz doğrudur ve mantıklıdır, ancak orijinal gönderinin yeniden düzenlenmesi nedeniyle bazı karışıklıklar tetiklenir. Aslında 2 soru var: (i) Neden bu şekilde? ve (ii) Neden bu şekilde değil? . Cevabınız whatsisnamedaha çok ilk soruya değindi (ve bu güvenliğin kaldırılması tehlikesini biraz uyardı), yorumunuz ise sorunun ikinci kısmıyla daha alakalıydı. O (size anlatıldığı gibi ve bu ... zaten birçok kez yapılmıştır) bu sözdizimini değiştirmek gerçekten mümkün ama olacak değil takım elbise herkesin (aynı oop değil ya takım herkesin.
Hoki

10

Tarih öncesi dönemlerde, ALGOL 68 adında bir dilin önerdiğiniz şeye yakın bir sözdizimi kullandığını öğrenmek ilginizi çekebilir. İşlev tanımlayıcıların tıpkı diğer tanımlayıcılar gibi değerlere bağlı olduğunu kabul ederek, bu dilde sözdizimini kullanarak bir işlev (sabit) tanımlayabilirsiniz.

İşlev türü adı = ( parametre listesi ) sonuç türü : vücut ;

Somut olarak örneğiniz okuyacak

PROC (INT)INT add one = (INT n) INT: n+1;

İlk tipin beyannamenin RHS'sinden okunabileceği ve bir fonksiyon tipi olan her zaman ile başlayan bir fazlalık olduğunu kabul ederek, PROCbuna (ve genellikle)

PROC add one = (INT n) INT: n+1;

ancak =yine de parametre listesinden önce geldiğine dikkat edin . Ayrıca bir işlev isteseydi unutmayın değişkeni (ki aynı işlevi türde başka değeri sonradan atanabilir), =değiştirilmesi gerektiğini :=, ya birini vererek

PROC (INT)INT func var := (INT n) INT: n+1;
PROC func var := (INT n) INT: n+1;

Ancak bu durumda her iki form da aslında kısaltmalardır; tanımlayıcı func varyerel olarak oluşturulmuş bir işleve bir başvuru belirttiğinden, tamamen genişletilmiş biçim

REF PROC (INT)INT func var = LOC PROC (INT)INT := (INT n) INT: n+1;

Bu özel sözdizimsel formun alışması kolaydır, ancak diğer programlama dillerinde açıkça büyük bir takip edemedi. Haskell gibi bile işlevsel programlama dilleri tarzı tercih f n = n+1ile = aşağıdaki parametre listesi. Sanırım sebebi esas olarak psikolojik; Sonuçta matematikçiler bile, benim yaptığım gibi, f = nn + 1'i f ( n ) = n + 1 yerine sıklıkla tercih etmiyorlar .

Bu arada, yukarıdaki tartışma değişkenler ve fonksiyonlar arasındaki önemli bir farkı vurgulamaktadır: fonksiyon tanımları genellikle daha sonra değiştirilemeyen belirli bir fonksiyon değerine bir isim verirken, değişken tanımları genellikle başlangıç değeri olan bir tanımlayıcı sunar , ancak sonra değiştirebilir. (Mutlak bir kural değildir; işlev değişkenleri ve işlev olmayan sabitler çoğu dilde gerçekleşir.) Ayrıca, derlenmiş dillerde işlev tanımına bağlı değer genellikle derleme zamanı sabitidir, böylece işlev çağrıları olabilir. kodda sabit bir adres kullanarak derlendi. C / C ++ 'da bu bir gerekliliktir; ALGOL 68'in eşdeğeri

PROC (REAL) REAL f = IF mood=sunny THEN sin ELSE cos FI;

Bir işlev işaretçisi getirmeden C ++ dilinde yazılamaz. Bu tür belirli sınırlamalar, fonksiyon tanımları için farklı bir sözdizimi kullanılmasını haklı kılar. Ancak bunlar dil anlambilimine bağlıdır ve gerekçeler tüm diller için geçerli değildir.


1
"Matematikçiler tercih etmez f = nn + üzerinde 1 f ( n ) = n sadece yazmak ister fizikçileri, söz değil ... + 1" f = n + 1 ...
leftaroundabout

1
@leftaroundabout çünkü ⟼ yazmak bir acı. Dürüst.
Pierre Arlaud

8

Java ve Scala'dan örnek olarak bahsettiniz. Ancak, önemli bir gerçeği göz ardı ettiniz: bunlar fonksiyon değil, bunlar yöntem. Yöntem ve fonksiyonlar temelde farklıdır. İşlevler nesnedir, yöntem nesnelere aittir.

Hem işlevleri hem de yöntemleri olan Scala'da, yöntemler ve işlevler arasında aşağıdaki farklılıklar vardır:

  • yöntemler genel olabilir, işlevler olamaz
  • yöntemlerde hiç, bir veya daha fazla parametre listesi olmayabilir, işlevler her zaman tam olarak bir parametre listesine sahiptir
  • yöntemleri örtük bir parametre listesine sahip olabilir, işlevler
  • Yöntemler varsayılan değişkenlerle isteğe bağlı parametrelere sahip olabilir, işlevler olamaz
  • yöntemler tekrarlanan parametrelere sahip olabilir, fonksiyonlar olamaz
  • yöntemlerin ad parametreleri olabilir, işlevler olamaz
  • yöntemler adlandırılmış argümanlarla çağrılabilir, fonksiyonlar olamaz
  • fonksiyonlar nesnelerdir, yöntemler değildir

Dolayısıyla, önerilen değişiklik yalnızca basitçe işe yaramaz, en azından bu durumlar için.


2
"İşlevler nesnedir, yöntem nesnelere aittir." Bunun tüm dillere uygulanması gerekiyor mu (C ++ gibi)?
svick

9
"yöntemlerin ad parametreleri olabilir, işlevler olamaz" - bu, yöntem ve işlevler arasındaki temel fark değil, yalnızca bir Scala tuhaflığıdır. Diğerlerinin çoğu (hepsi?) İle aynı.
user253751

1
Metotlar temel olarak sadece özel bir fonksiyon türüdür. -1. Java’nın (ve Scala uzantısına göre) başka bir işlevi olmadığını unutmayın. Bu "işlevler" tek bir yönteme sahip nesnelerdir (genel olarak işlevler nesneler olmayabilir veya hatta birinci sınıf değerler olabilir; dile bağlı olup olmadıkları).
Jan Hudec

@JanHudec: Anlamsal olarak, Java'nın hem işlevleri hem de yöntemleri vardır; fonksiyonlara atıfta bulunurken "statik yöntemler" terminolojisini kullanır, ancak bu terminoloji anlamsal ayrımı silmez.
supercat

3

Düşünebildiğim sebepler:

  • Derleyicinin ne ilan ettiğimizi bilmesi daha kolaydır.
  • Bunun bir işlev veya değişken olup olmadığını (önemsiz bir şekilde) bilmek bizim için önemlidir. İşlevler genellikle kara kutulardır ve iç uygulamalarını umursamıyoruz. Scala'da dönüş türlerine ilişkin tür çıkarımını beğenmedim, çünkü dönüş türüne sahip bir işlevi kullanmanın daha kolay olduğuna inanıyorum: genellikle sağlanan tek belgedir.
  • Ve en önemlisi, programlama dillerinin tasarımında kullanılan kalabalık stratejiyi izlemektir. C ++, C programcılarını çalmak için yaratıldı ve Java, C ++ programcılarını korkutacak şekilde tasarlandı ve C #, Java programcılarını çekmek için tasarlandı. Arkasında harika bir ekip olan çok modern bir dil olduğunu düşündüğüm C # bile Java'dan ve hatta C'den bazı hatalar kopyaladı.

2
"… Ve C #, Java programcılarını çekmek için" - bu şüpheli, C #, C ++ 'dan, Java'dan çok daha fazla benzer. ve bazen Java ile bilerek uyumsuz hale getirilmiş gibi görünüyor (joker karakterler yok, iç sınıflar yok, geri dönüş tipi kovaryans yok…)
Sarge Borsch

1
@SargeBorsch Kasıtlı olarak Java ile uyumlu hale getirildiğini sanmıyorum, C # ekibinin doğru yapmaya çalıştığına ya da daha iyisini yapmaya çalıştığına eminim, ancak bakmak istiyorsunuz. Microsoft kendi Java ve JVM'lerini zaten yazdı ve dava edildi. Bu yüzden C # ekibi, Java tutulması için çok motive oldu. Kesinlikle uyumsuz ve bunun için daha iyi. Java bazı temel sınırlamalarla başladı ve C # ekibinin örneğin jenerik ürünleri farklı şekilde seçtiğine sevindim (tip sistemde görülebilir ve sadece şeker değil).
codenheim

2

Bir kişi kaynak kodunu aşırı derecede RAM kısıtlı olan bir makinede düzenlemeye çalışmakla ilgilenmiyorsa veya disketten okumak için gereken zamanı en aza indirmeye çalışmak istemiyorsa, anahtar kelimeleri kullanmanın nesi yanlış?

Kesinlikle okumaktan x=y+zdaha hoş bir şey store the value of y plus z into x, ancak bu noktalama karakterlerinin anahtar kelimelerden doğal olarak "daha iyi" olduğu anlamına gelmez. Değişkenler ise i, jve kvardır Integerve xolup Real, Pascal aşağıdaki satırları göz önünde bulundurun:

k := i div j;
x := i/j;

İlk satır, bir tam sayıdaki bölünmeyi gerçekleştirirken, ikincisi gerçek sayıdaki bir bölünmeyi gerçekleştirir. Farklılık yapılabilir, çünkü Pascal divzaten başka bir amacı olan (gerçek sayı bölümü) noktalama işaretini kullanmak yerine, tamsayı-tamsayı bölme işleci olarak kullanır.

Bir işlev tanımı özlü yapmanın yararlı olabileceği birkaç bağlam olmasına rağmen (örneğin, başka bir ifadenin parçası olarak kullanılan bir lambda), işlevlerin genellikle öne çıkması ve işlevler olarak kolayca görsel olarak tanınması beklenir. Ayrımı daha ince yapmak ve noktalama karakterlerinden başka bir şey kullanmamak mümkün olsa da, nokta ne olurdu? Söylemek Function Foo(A,B: Integer; C: Real): String, fonksiyonun adının ne olduğunu, hangi parametreleri beklediğini ve ne döndürdüğünü açıkça belirtir. Belki biri Functionnoktalama işaretleriyle değiştirilerek altı veya yedi karakter kısaltılabilir , ancak ne elde edilebilir?

Unutulmaması gereken bir başka şey, bir adı her zaman belirli bir yöntemle veya belirli bir sanal ciltleme ile ilişkilendirecek olan ve başlangıçta belirli bir yöntemi veya ciltlemeyi tanımlayan bir değişken oluşturan bir bildirim arasında temel bir fark olduğu en çok çerçevenin var olmasıdır. başka bir tanımlamak için çalışma zamanında değiştirilebilir . Bunların çoğu işlemsel çerçevelerde anlamsal olarak çok farklı kavramlar olduğu için farklı sözdizimlerine sahip olmaları gerekir.


3
Bu sorunun özlülük ile ilgili olduğunu sanmıyorum. Özellikle örneğin void f() {}C ++ ( auto f = [](){};), C # ( Action f = () => {};) ve Java ( Runnable f = () -> {};) ' daki eşdeğer lambdadan daha kısa olduğundan . Lambdaların özlü olması türden çıkarsama ve ihmal etmekten kaynaklanmaktadır return, ancak bunun ne dediği ile ilgili olduğunu sanmıyorum.
svick

2

Sebebi şu ki, bu diller yeterince işlevsel değil, demek ki. Başka bir deyişle, nadiren işlevleri tanımlamaktasınız. Bu nedenle, ilave bir anahtar kelimenin kullanılması kabul edilebilir.

ML veya Miranda mirasının dillerinde OTOH, çoğu zaman işlevleri tanımlarsınız. Örneğin bazı Haskell kodlarına bakın. Kelimenin tam anlamıyla çoğunlukla bir işlev tanımları dizisidir, bunların çoğu yerel işlevlere ve bu yerel işlevlerin yerel işlevlerine sahiptir. Dolayısıyla, bir eğlence Haskell anahtar kelime ile başlamak için şart dilde bir Ödev deyimi gerektiren kadar büyük bir hata olacağını assign . Neden atama muhtemelen bugüne kadar en sık yapılan tek ifadedir.


1

Şahsen, fikrinizde ölümcül bir kusur görmüyorum; yeni sözdiziminizi kullanarak bazı şeyleri ifade etmekten beklenenden daha zor olduğunu farkedebilirsiniz ve / veya gözden geçirmeniz gerekebilir (çeşitli özel durumlar ve diğer özellikler ekleyerek). fikri tamamen terk etmek gerekiyordu.

Önerdiğiniz sözdizimi, bazen matematikteki işlevleri veya işlev türlerini ifade etmek için kullanılan bazı gösterim stillerinin bir türevi gibi görünmektedir. Bu, tüm gramerler gibi, bazı programcılara diğerlerinden daha fazla hitap edeceği anlamına gelir. (Bir matematikçi olarak hoşuma giderdi.)

Ancak, çoğu dilde, belirtmeliyiz deftarzı sözdizimi (yani geleneksel sözdizimi) gelmez bir standart değişken atama dan farklı davranır.

  • Gelen Cve C++ailesi, fonksiyonlar genellikle yani "nesneler", daktilo verilerin parçalar kopyalanabilir ve yığın ve etajer koymak üzere olarak ele alınmayacaktır. (Evet, işlev işaretçilerine sahip olabilirsiniz, ancak bunlar tipik anlamda "veri" yi değil, hala yürütülebilir kodları gösterir.)
  • Çoğu OO dilinde, yöntemler için özel işlem vardır (yani üye işlevler); yani, sadece sınıf tanımı kapsamında bildirilen işlevler değillerdir. En önemli fark, yöntemin çağrıldığı nesnenin genellikle yönteme örtülü bir ilk parametre olarak geçirilmesidir. Python bunu açıkça selfbelirtir (bu arada, aslında bir anahtar kelime değildir; herhangi bir geçerli tanımlayıcıyı bir yöntemin ilk argümanı yapabilirsiniz).

Yeni söz diziminizin derleyicinin veya tercümanın gerçekte ne yaptığını doğru şekilde (ve umarım sezgisel olarak) temsil edip etmediğini düşünmeniz gerekir. Ruby'deki lambdalarla yöntemler arasındaki farkı okumak; Bu size, fonksiyonlar-sadece veri paradigmasının tipik OO / prosedürel paradigmadan nasıl farklılaştığı hakkında bir fikir verecektir.


1

Bazı diller için fonksiyonlar değer değildir. Bunu söylemek için böyle bir dilde

val f = << i : int  ... >> ;

bir fonksiyon tanımı ise

val a = 1 ;

sabit ilan ediyor, kafa karıştırıcı çünkü iki şey demek için bir sözdizimi kullanıyorsunuz.

ML, Haskell ve Scheme gibi diğer diller, fonksiyonlara 1. sınıf değerler gibi davranırlar, ancak kullanıcıya fonksiyon değerli sabitleri bildirmek için özel bir sözdizimi sağlarlar. Yani bir yapı hem ortak hem de ayrıntılı ise, kullanıcıya bir kısa yol vermelisiniz. Kullanıcıya tamamen aynı anlama gelen iki farklı sözdizimi vermek inelegant; bazen zerafet işe yarar olmak için feda edilmeli.

Eğer kendi dilinizde, fonksiyonlar birinci sınıfsa, neden sözdizimsel bir şeker bulma konusunda istekli olmayacağınız özlü bir sözdizimi bulmaya çalışmıyorsunuz?

-- Düzenle --

Henüz kimsenin gündeme getirmediği bir başka konu ise özyinelemedir. Müsade edersen

{ 
    val f = << i : int ... g(i-1) ... >> ;
    val g = << j : int ... f(i-1) ... >> ;
    f(x)
}

ve izin veriyorsun

{
    val a = 42 ;
    val b = a + 1 ;
    a
} ,

izin vermen gerektiğini mi takip ediyor

{
    val a = b + 1 ; 
    val b = a - 1 ;
    a
} ?

Tembel bir dilde (Haskell gibi) burada sorun yok. Esasen statik kontrolü olmayan bir dilde (LISP gibi) burada bir sorun yoktur. Ancak, statik olarak kontrol edilen istekli bir dilde, ilk ikisine izin vermek ve sonuncuyu yasaklamak istiyorsanız, statik kontrol kurallarının nasıl tanımlandığına dikkat etmeniz gerekir.

- Düzenleme Sonu -

* Haskell'in bu listeye ait olmadığı iddia edilebilir. Bir işlevi bildirmek için iki yol sağlar, ancak her ikisi de bir anlamda diğer türlerin sabitlerini bildirmek için sözdiziminin genelleştirilmesidir.


0

Bu, türün o kadar önemli olmadığı dinamik dillerde faydalı olabilir, ancak değişkeninizin türünü her zaman bilmek istediğiniz statik yazılan dillerde okunabilir değildir. Ayrıca, nesne yönelimli dillerde, hangi işlemleri desteklediğini bilmek için değişkeninizin türünü bilmek oldukça önemlidir.

Senin durumunda, 4 değişkenli bir fonksiyon şöyle olacaktır:

(int, long, double, String => int) addOne = (x, y, z, s) => {
  return x + 1;
}

İşlev başlığına bakıp (x, y, z, s) gördüğümde ama bu değişkenlerin türlerini bilmiyorum. zHangi türün üçüncü parametre olduğunu bilmek istersem , işlevin başlangıcına bakıp 1, 2, 3 saymaya başlamalıyım ve sonra türün olduğunu görmem gerekecek double. Eski şekilde doğrudan bakar ve görürüm double z.


3
Elbette, tür çıkarımı adı verilen var addOne = (int x, long y, double z, String s) => { x + 1 }ve seçtiğiniz moronik olmayan statik bir dilde yazılmış bir şey yazmanıza izin veren harika bir şey var (örnekler: C #, C ++, Scala). C # tarafından kullanılan aksi takdirde çok sınırlı olan yerel tip çıkarımı bile bunun için yeterlidir. Dolayısıyla, bu cevap sadece ilk başta şüpheli olan ve aslında herhangi bir yerde kullanılmayan belirli bir sözdizimini eleştirmektedir (Haskell'in sözdiziminin çok benzer bir sorunu olmasına rağmen).
amon

4
@ amon Cevabı sözdizimini eleştiriyor olabilir, ancak aynı zamanda sorudaki amaçlanan sözdiziminin herkes için "doğal" olamayacağına da işaret ediyor.

1
@ amon Yazı tipi çıkarımının yararı herkes için harika bir şey değil. Kod yazdığınızdan daha sık kod okursanız, o zaman tür çıkarımı kötüdür, çünkü kodu okurken kafanızı çıkarmanız gerekir; ve türü okumak, gerçekte hangi türün kullanıldığını düşünmekten daha hızlıdır.
m3th0dman

1
Bu eleştiri benim için geçerli görünüyor. Java için OP, [giriş, çıkış, ad, giriş] 'in basitçe [çıkış, ad, giriş]' den daha basit / daha net bir fonksiyon tanımı olduğunu düşünüyor gibi görünüyor. @ M3th0dman'ın belirttiği gibi, daha uzun imzalarla, OP'nin 'temizleyici' yaklaşımı çok uzun solmaz hale gelir.
Michael,

0

Çoğu dilde böyle bir ayrım yapmak için çok basit bir neden var: değerlendirme ve beyanı ayırt etmek gerekiyor . Örneğin iyi: neden değişkenleri sevmiyorsun? Eh, değişken ifadeleri hemen değerlendirilir.

Haskell, değerlendirme ve beyan arasında bir ayrım bulunmadığı özel bir modele sahiptir, bu yüzden özel bir anahtar kelimeye gerek yoktur.


2
Ancak lambda işlevlerinin bazı sözdizimleri de bunu çözer, peki neden kullanmıyorsunuz?
svick

0

İşlevler, çoğu dilde değişmezlerden, nesnelerden vb. Farklı olarak bildirilir, çünkü bunlar farklı şekilde kullanılır, farklı hata ayıklanır ve farklı potansiyel hata kaynakları oluşturur.

Dinamik nesne referansı veya değişken bir nesne bir fonksiyona geçirilirse, fonksiyon nesnenin çalıştığı değeri değiştirebilir. Bu tür bir yan etki, bir işlevin karmaşık bir ifade içine yerleştirilmiş olması durumunda ne yapacağını takip etmeyi zorlaştırabilir ve bu, C ++ ve Java gibi dillerde yaygın bir sorundur.

Her nesnenin bir toString () işlemi yaptığı Java'da bir tür çekirdek modülünde hata ayıklamayı düşünün. ToString () yönteminin nesneyi geri yüklemesi beklense de, değerini bir String nesnesine çevirmek için nesneyi söküp yeniden takması gerekebilir. Eğer işini yapmak için toString () 'in çağıracağı yöntemleri (kanca ve şablon senaryosunda) hata ayıklamaya çalışıyorsanız ve yanlışlıkla çoğu IDE'nin değişken penceresindeki nesneyi vurgulayın, hata ayıklayıcıyı çökertebilir. Bunun nedeni, IDE'nin hata ayıklama sürecinde olduğunuz kodu çağıran nesneyi toString () 'e yapmaya çalışacağıdır. İlkel değerlerin hiçbiri böyle önemsemez, çünkü ilkel değerlerin semantik anlamı programcı tarafından değil, dil tarafından tanımlanır.

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.