İşlevlere iletilen argüman miktarını sınırlayan bir dil


16

Fikir, +, -,%, vs. gibi operatörlerden esinlenilerek bir veya iki argüman geçirilen işlevler olarak görülebilir ve yan etki görülmez. Ben veya başka birisinin ikiden fazla bağımsız değişkenin geçmesini engelleyen bir dil yazdığını ve yalnızca dönüş değeriyle çalıştığını varsayarsak:

a) böyle bir dil, kodun anlaşılmasını kolaylaştırır mı?

b) Kodun akışı daha açık olur mu? (potansiyel olarak daha az etkileşimin 'gizli' olmasıyla daha fazla adıma zorlanır

c) kısıtlamalar, dili daha karmaşık programlar için aşırı derecede hantal yapar mı?

d) (bonus) artıları / eksileri hakkındaki diğer yorumları

Not:

İki kararın alınması gerekiyordu - birincisi, main () veya eşdeğeri dışında kullanıcı girişine izin verilip verilmeyeceği ve ayrıca dizileri / yapıları geçerken neler olacağına ilişkin kuralın ne olacağı. Örneğin, bir kişi birden fazla değer eklemek için tek bir işlev isterse, bir diziye ayırarak bu sınırlamayı aşabilir. Bu, bir dizinin veya yapının kendisiyle etkileşime girmesine izin vermeyerek durdurulabilir; bu, örneğin, her sayıyı konumuna bağlı olarak farklı bir tutara bölmenize izin verir.


4
Selam. Artıları ve Eksileri listeleri kötü yanıtlar verme eğilimindedir. İhtiyacınız olan bilgileri başka bir biçimde almaya devam etmek için sorunuzu yeniden ifade etmenin herhangi bir yolu var mı?
MetaFight

22
Akıl yürütmen bana anlam ifade etmiyor bile. Bazı işlevlerin birkaç bağımsız değişkeni vardır, bu yüzden tüm işlevleri sınırlayalım? Normalde kişi keyfi kısıtlamalar önerdiğinde, kazanılması gereken bir sebep vardır. Bunun sana ne kazandıracağını göremiyorum.

2
'Ya if' sorularıyla ilgili doğal olarak yanlış bir şey olmadığı için değil (@MetaFight'ın söylediği gibi cevaplamak bazen zor olsa da), ancak bir şeyi düşünen ve bir soru soracak kadar önemseyen siz bile, gerçekten bir yararına, o zaman "ne? hayır! bu aptalca neden bunu yapasın?"

6
Fonksiyon başına sadece tek bir argümana izin veren birkaç dil vardır: lambda hesabına dayalı herhangi bir şey. Sonuç genellikle bir işlev tek bir liste argümanı alınması veya bir fonksiyon tüm argümanlar işlendikten kadar sonraki argüman alan bir işleve dönen geçerli: result = f(a)(b)…(z). Bu, Haskell gibi ML dil ailesinde olduğu gibi kavramsal olarak Lisp, JavaScript veya Perl gibi diğer dillerde de geçerlidir.
amon

3
@Orangesandlemons: Tamam, o zaman sadece çarpma ve toplama (kodlama için) ve bölme ve çıkarma (kod çözme için) kullanarak tek bir tamsayı içinde rasgele sayıda tamsayı kodlayabilirim. Yani, tamsayılara da izin vermemeniz veya en azından çarpma, toplama, bölme ve çıkarma gerekir. (Programlamanın gücünün bir sonucu, neredeyse her şeyi neredeyse her şeyi kullanarak kodlayabilmenizdir ve bu nedenle şeyleri kısıtlamak gerçekten çok zordur. Genel olarak, kısıtlamalar aslında hiçbir şeyi "kısıtlamaz", sadece programcıları rahatsız ederler.)
Jörg W Mittag

Yanıtlar:


40

Robert C. Martin, "Temiz Kod" kitabında maksimum 0, 1 veya 2 parametreli fonksiyonların kullanılmasını şiddetle tavsiye ediyor, bu yüzden en azından kodun bu stili kullanarak daha temiz hale geldiğini düşünen deneyimli bir kitap yazarı var (ancak, elbette buradaki nihai otorite değildir ve görüşleri tartışmalıdır).

Bob Martin IMHO'nun doğru olduğu yerde: 3 veya daha fazla parametreli fonksiyonlar genellikle bir kod kokusu için göstergelerdir. Birçok durumda, parametreler birleştirilmiş bir veri türü oluşturmak için birlikte gruplandırılabilir, diğer durumlarda, fonksiyonun sadece çok fazla yaptığı için bir gösterge olabilir.

Ancak, bunun için yeni bir dil icat etmenin iyi bir fikir olacağını düşünmüyorum:

  • kodunuzda böyle bir kuralı gerçekten uygulamak istiyorsanız, sadece mevcut bir dil için bir kod analiz aracına ihtiyacınız vardır, bunun için tamamen yeni bir dil icat etmeye gerek yoktur (örneğin, C # için 'fxcop' gibi bir şey muhtemelen kullanılabilir) ).

  • bazen, parametreleri yeni bir türle birleştirmek zahmete değmez veya saf yapay bir kombinasyon haline gelir. Örneğin, .Net çerçevesindeki bu File.Openyönteme bakın . Dört parametre alır ve bu API'nın tasarımcılarının bunu kasıtlı olarak yaptığından eminim, çünkü işleve farklı parametreler sağlamanın en pratik yolu olacağını düşündüler.

  • bazen 2'den fazla parametrenin teknik nedenlerle işleri basitleştirdiği gerçek dünya senaryoları vardır (örneğin, basit veri türlerinin kullanımına bağlı olduğunuz ve farklı birleştiremediğiniz mevcut bir API ile 1: 1 eşlemeye ihtiyacınız olduğunda parametreleri tek bir özel nesneye dönüştürür)


16
Birden çok parametreli koku genellikle farklı parametrelerin aslında birbirine ait olmasıdır. Örneğin vücut kitle indeksi, VKİ hesaplamasını ele alalım. Bir kişinin boyunun ve kilosunun bir fonksiyonudur. f (uzunluk, ağırlık), ancak bu iki parametre gerçekten birbirine aittir, çünkü bu hesaplamayı bir kişinin yüksekliği ve bir başkasının ağırlığı ile yapar mıydınız? Yani bunu daha iyi temsil etmek için kişinin ağırlık, uzunluk arayüzüne sahip olabileceği f (kişi) elde edersiniz.
Pieter B

@PieterB: elbette, düzenlememe bakın.
Doc Brown

5
Küçük, küçük dil nitpick: "bir kod kokusu gösterebilir" Bir kod kokusu tanımı gereği sadece bir şeyi tekrar gözden geçirmeniz gerektiğinin bir göstergesi değil midir, sonuçta kodu değiştirmeseniz bile? Yani bir kod kokusu "belirtilmez". Belirli bir özellik bir sorunun olasılığını gösterirse , bir kod kokusudur. Hayır?
jpmc26

6
@ jpmc26: Başka bir bakış açısından, kod kokusu olası bir sorundur, birinin göstergesi değildir ;-) Her şey kod kokusunun tam tanımına bağlıdır (ve bir kez kokladı, kötü gitti, değil mi? ?)
hoffmale

3
@PieterB Aslında bunu yapan var mı? Şimdi, iki keyfi değere sahip bir BMI hesaplamak istediğiniz her seferinde yeni bir Kişi örneği oluşturmanız gerekir. Elbette, uygulamanız zaten başlamak için Kişiler kullanıyorsa ve kendinizi f (person.length, person.height) gibi bir şey yaparken bulursanız, onu biraz temizleyebilirsiniz, ancak özellikle grup parametrelerine yeni nesneler oluşturmak aşırıya kaçmış gibi görünür.
Lawyerson

47

Bu şekilde çalışan birçok dil var, örneğin Haskell. Haskell'de her işlev tam olarak bir bağımsız değişken alır ve tam olarak bir değer döndürür.

N bağımsız değişkenini alan bir işlevi, n-1 bağımsız değişkenlerini alan ve nihai bağımsız değişkeni alan bir işlevi döndüren bir işlevle değiştirmek her zaman mümkündür. Bunu yinelemeli olarak uygulamak, rasgele sayıda bağımsız değişken alan bir işlevi, tam olarak bir bağımsız değişken alan bir işlevle değiştirmek her zaman mümkündür. Ve bu dönüşüm mekanik olarak bir algoritma ile gerçekleştirilebilir.

Buna, 1950'lerde kapsamlı bir şekilde araştıran Haskell Curry'den sonra, 1924'te tanımlayan Moses Schönfinkel ve 1893'te bunu öngören Gottlob Frege'den sonra Frege-Schönfinkeling, Schönfinkeling, Schönfinkel-Currying veya Currying denir.

Başka bir deyişle, argüman sayısının kısıtlanmasının tamamen sıfır etkisi vardır.


2
Elbette işlevlerin döndürülmesine izin verirseniz. Olmasa bile, tek yapmanız gereken ana programda bir sonraki işleve sahip olmaktır. Yani ilk toplama, ilave toplama için bir fonksiyon döndüren bir fonksiyon olduğunda 1 + 1 + 1 olabilir veya sadece iki kez çağrılabilir. İkinci tarz, teorik olarak daha temiz olabilir mi yoksa yanılıyor muyum?

5
"tam olarak sıfır etkisi vardır" - OP sorusu kodun tekrarlanabilirlik artacak veya azalacaktı ve sanırım bir dil için böyle bir tasarım kararı üzerinde hiçbir etkisi yoktur iddia, değil mi?
Doc Brown

3
@DocBrown İyi güç ve operatör aşırı yüklemesi ile, bir köri dili alabilir ve dilsiz bir dil gibi görünmesini sağlayabilirim. Örnek: Bir zinciri başlatmak, zinciri uzatmak ve LHS üzerinde , zincir içeriğinin her birini birer birer geçirerek çağırmak için aşırı f *(call_with: a,b,c,d,e) yükleme . Yeterince zayıf bir operatör aşırı yük sistemi, sözdizimini hantal hale getirir, ancak bu, operatörün aşırı yük sisteminin her şeyden çok arızasıdır. call_with :,*f
Yakk

Aslında, Haskell'in köri, n bağımsız değişkenli bir işlevi bir işleve n - 1 bağımsız değişkenli başka bir işlev döndüren bir işleve indirger.
Ryan Reich

2
@RyanReich Haskell işlevinin "bağımsız değişken sayısı" nın tür imzasında bir "hayalet" görebilirsiniz. Gerçek bir imzadan ziyade bir hayalettir, çünkü genel olarak imzadaki son tip değişkeninin de bir fonksiyon tipi olup olmadığını bilmenin bir yolu yoktur . Her halükarda, bu hayalet, Haskell'de tüm işlevlerin 1 argüman alması ve ya bir işlev dışı değer ya da 1 argüman alan başka bir işlev döndürmesi gerçeğini geçersiz kılmaz. Bu, ->: a-> b-> c'nin bir -> (b-> c) birlikteliği içine yerleştirilmiştir. Yani burada çoğunlukla yanılıyorsunuz.
Ian

7

J bilgisayar dilini öğrenmek için son birkaç haftadır biraz zaman harcadım. J'de hemen hemen her şey bir işleçtir, bu nedenle yalnızca "monads" (yalnızca bir bağımsız değişkene sahip işlevler) ve "dyads" (tam olarak iki bağımsız değişkene sahip işlevler) elde edersiniz. Daha fazla bağımsız değişkene ihtiyacınız varsa, bunları bir dizide veya "kutular" içinde sağlamanız gerekir.

J çok özlü olabilir, ancak selefi APL gibi çok şifreli de olabilir - ancak bu çoğunlukla yaratıcının matematiksel özlülüğü taklit etme hedefinin bir sonucudur. Operatörler oluşturmak için karakterlerden ziyade adları kullanarak bir J programını daha okunabilir hale getirmek mümkündür.


ah, bu yüzden dizilerin kendileriyle etkileşime girmesine izin verir.

5

Geliştiriciyi nasıl kısıtladığına dayalı bir dil, dil geliştiricisinin her programcının ihtiyaçlarını programcının bu ihtiyaçları anladığından daha iyi anladığı varsayımına bağlıdır. Bunun gerçekten geçerli olduğu durumlar vardır. Örneğin, muteksleri ve semaforları kullanarak senkronizasyon gerektiren çok iş parçacıklı programlama üzerindeki kısıtlamalar birçok kişi tarafından "iyi" olarak kabul edilir, çünkü çoğu programcı bu kısıtlamaların kendilerinden sakladığı makineye özgü karmaşıklıklardan tamamen habersizdir. Benzer şekilde, çok azı çok iş parçacıklı çöp toplama algoritmalarının nüanslarını tam olarak kavramak istemektedir; GC algoritmasını kırmanıza izin vermeyen bir dil, bir programcıyı çok fazla nüansın farkında olmaya zorlayan bir dil yerine tercih edilir.

Bir dil geliştiricisi olarak, dilinizi kullanan programcılardan çok daha iyi geçen argümanı neden zararlı olduğunu düşündüğünüz şeyleri yapmalarını engellemenin bir değeri olduğunu anlamanız için geçerli bir argüman yapmanız gerekir. Bunun zor bir argüman olacağını düşünüyorum.

Ayrıca programcılar olduğunu bilmek zorunda olacak sizin kısıtlamaları geçici. 3 veya daha fazla argümana ihtiyaçları varsa, bunları daha az argüman çağrısına dönüştürmek için körükleme gibi teknikler kullanırlar. Bununla birlikte, bu genellikle iyileştirmek yerine okunabilirlik pahasına gelir .

Bu tür bir kuralla bildiğim dillerin çoğu esolangs, sınırlı bir işlevsellik kümesiyle çalışabileceğinizi göstermek için tasarlanmış dillerdir. Özellikle, her karakterin bir opcode olduğu esolangs, sadece opcodes listesini kısa tutmaları gerektiğinden, argüman sayısını sınırlama eğilimindedir.


Bu en iyi cevap.
Jared Smith

1

İki şeye ihtiyacınız olacak:

  • kapatma
  • Bileşik veri türü

Jörg W Mittag tarafından yazılan cevabı açıklamak için matematiksel bir örnek ekleyeceğim .

Gauss işlevini düşünün .

Bir Gauss fonksiyonunun şekli için iki parametre vardır: ortalama (eğrinin merkez konumu) ve varyans (eğrinin darbe genişliğine bağlı olarak). İki parametreye ek olarak, xdeğerlendirmek için serbest değişkenin değerini de sağlamak gerekir.

İlk adımda, ortalama, varyans ve serbest değişken olmak üzere üç parametrenin tümünü alan bir Gauss işlevi tasarlayacağız.

İkinci adımda, ortalama ve varyansı bir şeyde birleştiren bileşik bir veri türü yaratıyoruz.

Üçüncü adımda, ikinci adımda oluşturduğumuz bileşik veri türüne bağlı Gauss işlevinin kapanmasını oluşturarak Gauss işlevinin parametrelendirilmesini yaratırız.

Son olarak, serbest değişkenin xdeğerini ona ileterek üçüncü adımda yaratılan kapatmayı değerlendiriyoruz .

Bu nedenle yapı:

  • Değerlendir (hesaplama)
    • ParameterizedGaussian (kapatma: formül ve bazı bağlı değişkenler)
      • Gauss Parametreleri (bileşik veri türü)
        • Ortalama değer)
        • Varyans (değer)
    • X (serbest değişkenin değeri)

1
  1. Hemen hemen her programlama dilinde, tek argüman olarak bir tür liste, dizi, grup, kayıt veya nesne iletebilirsiniz. Tek amacı, diğer öğeleri tek tek bir işleve geçirmek yerine tutmaktır. Bazı Java IDE'lerin bunu yapmak için bir " Parametre Nesnesini Ayıkla " özelliği bile vardır. Dahili olarak Java, bir dizi oluşturarak ve geçirerek değişken sayıda argüman uygular.

  2. Eğer gerçekten bahsettiğiniz şeyi en saf biçimde yapmak istiyorsanız, lambda hesabına bakmanız gerekir. Tam olarak tarif ettiğin şey bu. Web'de arama yapabilirsiniz, ancak benim için anlamlı olan açıklama Türler ve Programlama Dilleri'ndeydi .

  3. Bak Haskell ve ML (ML basittir) programlama dilleri. Her ikisi de lambda hesabına dayanır ve kavramsal olarak işlev başına sadece bir parametre vardır (biraz şaşıyorsanız).

  4. Josh Bloch'un 2. Maddesi: "Bir çok kurucu parametresiyle karşılaşıldığında bir kurucu düşünün." Bunun ne kadar ayrıntılı olduğunu görebilirsiniz , ancak bu şekilde yazılmış bir API ile çalışmak bir zevktir.

  5. Bazı diller, büyük yöntem imzalarının gezinmesini çok daha kolay hale getirmek için başka bir yaklaşım olan parametreleri adlandırdı. Örneğin Kotlin argümanları adlandırdı .

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.