Neden fonksiyon parametrelerine açıklama eklemiyorsunuz?


28

Bu soruyu cevaplandırılabilir hale getirmek için, bir programcının aklındaki belirsizlik maliyetinin birkaç ekstra tuşa basılmasından çok daha pahalı olduğunu varsayalım.

Buna göre, neden takım arkadaşlarımın işlev parametrelerine açıklama yapmamaları ile kaçmalarına izin vereyim ? Aşağıdaki kodu, çok daha karmaşık bir kod parçasının ne olabileceğinin bir örneği olarak alın:

let foo x y = x + y

Şimdi, ipucunun hızlı bir incelemesi size F # 'nin x ve y'nin ints olmasını istediğinizi belirlediğini gösterecektir. Eğer istediğin buysa, her şey yolunda. Ama istediğini yapıp yapmadığını bilmiyorum. İki dizeyi birleştirmek için bu kodu oluşturduysanız ne olur? Ya da muhtemelen iki kat eklemek istediğinizi düşünüyorsanız? Ya da türünü belirlemek için fareyi her bir işlev parametresinin üzerine getirmek istemiyorsam ne olur?

Şimdi bunu örnek olarak alın:

let foo x y = "result: " + x + y

F # şimdi muhtemelen dizeleri birleştirmek istediğinizi varsayar, bu nedenle x ve y dizeleri olarak tanımlanır. Bununla birlikte, kodunuzu koruyan zavallı adam olarak, buna bakabilirim ve belki birlikte x ve y (inç) eklemek isteyip istemediğinizi merak edebilir ve sonucu UI amaçları için bir dizgeye eklemeyi isteyip istemediğinizi merak edebilirim.

Kesinlikle bu kadar basit örnekler için, bir kişi onun gitmesine izin verebilirdi, ancak neden açık türden bir açıklama politikası uygulamıyor?

let foo (x:string) (y:string) = "result: " + x + y

Belirsiz olmanın zararı nedir? Elbette, bir programcı yapmaya çalıştıkları şey için yanlış türler seçebilirdi, ama en azından bunu amaçladıklarını biliyorum, sadece bir gözetim değildi.

Bu ciddi bir soru ... F # için hala çok yeniyim ve şirketimin izini sürdüm. Benim kabul ettiğim standartlar, gelecek yılların kültürüne nüfuz edeceğinden emin olduğum bitmeyen kopyala yapıştırma içine gömülü olan gelecekteki F # kodlamasının temeli olacaktır.

Öyleyse ... F # 'nin tip çıkarımında, tutulması için değerli bir özellik haline getiren, sadece gerektiğinde not veren özel bir şey var mı? Veya uzman F # kullanıcıları, önemsiz olmayan uygulamalar için parametrelerini açıklama alışkanlığı yaratır mı?


Açıklamalı sürüm daha az geneldir. Aynı sebepten dolayı, IEnumerable <> imzasında kullanırsınız ve SortedSet <> değil.
Patrick

2
@Patrick - Hayır, öyle değil, çünkü F # dize türünü çıkarıyor. İşlevin imzasını değiştirmedim, yalnızca açık hale getirdim.
JDB

1
@Patrick - Doğru olsa bile, bunun neden kötü bir şey olduğunu açıklayabilir misin? Programcının istediği şey buysa, belki de imza daha az genel olmalıdır . Belki de daha genel bir imza aslında sorunlara neden olmakta, ancak programcının çok fazla araştırma yapmadan ne kadar net olmasını istediğinden emin değilim.
JDB,

1
İşlevsel dillerde genelliği tercih ettiğinizi ve daha özel bir durumda not aldığınızı söylemenin adil olacağını düşünüyorum; örneğin, daha iyi performans almak istediğinizde ve ipucu türünü kullanarak elde edebilirsiniz. Her yerde açıklamalı işlevler kullanmak, her durumda belirli durumlar için garanti edilmeyen aşırı yükler yazmanızı gerektirir.
Robert Harvey,

Yanıtlar:


30

F # kullanmıyorum, ancak Haskell'de, dil en yaygın türdeki çıkarımlara sahip olsa da (en azından) en üst seviye tanımları ve bazen de yerel tanımları açıklamak için iyi bir form olarak kabul ediliyor. Bunun birkaç nedeni var:

  • Okuma
    Bir fonksiyonun nasıl kullanılacağını bilmek istediğinizde, imzanın mevcut olması inanılmaz derecede yararlıdır. Kendiniz çıkarmaya çalışmak veya sizin için yapacak araçlara güvenmek yerine, basitçe okuyabilirsiniz.

  • Üstlenmeden
    bir fonksiyonu değiştirmek istediğinizde açık bir imzaya sahip olan, size dönüşümleri orijinal kod niyet korumak bazı güvence verir. Yazılı bir dilde, çok polimorfik kodun yazmayı denetleyeceğini ancak istediğiniz şeyi yapmamasını görebilirsiniz. Tip imzası, bir arayüzde tip bilgisini somutlayan bir “engeldir”.

  • Performans
    Haskell'de, çıkarılan bir işlevin türü, çalışma zamanı gönderimini ifade edebilecek şekilde aşırı yüklenebilir (ön sınıf yoluyla). Sayısal türler için, varsayılan tür isteğe bağlı bir tamsayıdır. Bu özelliklerin tam genelliğine ihtiyacınız yoksa, işlevi ihtiyacınız olan türe göre özelleştirerek performansı artırabilirsiniz.

Yerel tanımlar, let-bound değişkenler ve lambdaların formal parametreleri için, bu tip imzaların genellikle kodda ekleyeceği değerden daha pahalı olduğunu buldum . Bu nedenle, kod incelemesinde, üst seviye tanımlamalar için imzalarda ısrar etmenizi ve başka bir yerde yalnızca makul açıklamalar istemenizi öneririm .


3
Bu çok makul ve iyi dengelenmiş bir yanıt gibi geliyor.
JDB

1
Tanımlamanın açıkça tanımlanmış türlerle tanımlanmasının yeniden yapılanma sırasında yardımcı olabileceğini kabul ediyorum, ancak birim testinin de bu sorunu çözebileceğini ve birim fonksiyonunun, kullanımdan önce tasarlandığı gibi bir fonksiyonun çalışmasını sağlamak için fonksiyonel programlama ile kullanılması gerektiğine inanıyorum. başka bir fonksiyona sahip fonksiyon, bu türleri tanımın dışında bırakmama izin verir ve kırılma değişikliği yaparsam yakalanacağına güvenim olur. Örnek
Guy Coder

4
Haskell'de işlevlerinizi açıklamanın doğru olduğu kabul edilir, ancak idiomatik F # ve OCaml'in belirsizliği ortadan kaldırmak için gerekli olmadıkça ek açıklamaları ihmal etme eğiliminde olduklarına inanıyorum. Bu zararlı olduğunu söylemek değildir (F #'daki açıklama notunun sözdizimi Haskell'den daha çirkin olsa da).
KChaloux

4
@KChaloux yılında OCaml, zaten arayüzü (ek açıklamaları var yazın edilir .mliEğer kuvvetle teşvik edilmektedir birini yazarsanız () dosyası onlar arayüzü ile gereksiz olurdu çünkü ek açıklamalar tanımlamalardan atlanabilir eğilimindedir yazınız..
Gilles ' SO-kötülük '

1
@Gilles @KChaloux gerçekten, F # signature ( .fsi) dosyalarında aynıdır, bir ihtarı vardır : F #, tür çıkarımı için imza dosyaları kullanmaz, bu nedenle uygulamadaki bir şey belirsizse, yine de açıklama eklemeniz gerekir. books.google.ca/…
Yawar Amin 29:16

1

Jon, burada tekrar etmeyeceğim makul bir cevap verdi . Bununla birlikte, size gereksinimlerinizi karşılayabilecek bir seçenek göstereceğim ve bu süreçte evet / hayır dışında farklı bir cevap göreceksiniz.

Son zamanlarda, ayrıştırıcı birleştiricileri kullanarak ayrıştırma ile çalışıyorum. Ayrıştırmayı biliyorsanız, ilk aşamada bir lexer ve ikinci aşamada bir ayrıştırıcı kullanırsınız. Lexer metni belirteçlere, ayrıştırıcı belirteçleri AST'ye dönüştürür. Şimdi F # işlevsel bir dil ve birleştiriciler bir arada kullanılmak üzere tasarlandığında, ayrıştırıcı birleştiriciler, hem lexer hem de ayrıştırıcıda aynı işlevleri kullanmak üzere tasarlanmıştır, ancak ayrıştırıcı birleştirici işlevlerinin türünü ayarlarsanız, yalnızca bunları kullanmak için kullanabilirsiniz lex veya ayrıştırmak ve ikisini birden değil.

Örneğin:

/// Parser that requires a specific item.

// a (tok : 'a) : ('a list -> 'a * 'a list)                     // generic
// a (tok : string) : (string list -> string * string list)     // string
// a (tok : token)  : (token list  -> token  * token list)      // token

veya

/// Parses iterated left-associated binary operator.


// leftbin (prs : 'a -> 'b * 'c) (sep : 'c -> 'd * 'a) (cons : 'd -> 'b -> 'b -> 'b) (err : string) : ('a -> 'b * 'c)                                                                                    // generic
// leftbin (prs : string list -> string * string list) (sep : string list -> string * string list) (cons : string -> string -> string -> string) (err : string) : (string list -> string * string list)  // string
// leftbin (prs : token list  -> token  * token list)  (sep : token list  -> token  * token list)  (cons : token  -> token  -> token  -> token)  (err : string) : (token list  -> token  * token list)   // token

Kod telif hakkı olduğu için buraya dahil etmeyeceğim ancak Github'da mevcut . Buraya kopyalamayın.

İşlevlerin çalışması için, genel parametrelerle bırakılmalıdır, ancak işlev kullanımına bağlı olarak, çıkarılan türleri gösteren yorumlar eklerim. Bu, işlevi kullanım için genel bırakırken bakım işlevini anlamayı kolaylaştırır.


1
Neden jenerik sürümü fonksiyona yazmıyorsunuz? Bu işe yaramaz mı?
01:55

@svick Sorunuzu anlamıyorum. Türleri işlev tanımının dışında bıraktığımı, ancak genel türlerin işlevin anlamını değiştirmeyeceği için genel türlerin işlev tanımlarına eklenebileceğini mi kastediyorsunuz? Eğer öyleyse nedeni kişisel tercihlerden daha fazladır. F # ile ilk başladığımda onları ekledim. Daha ileri F # kullanıcıları ile çalışmaya başladığımda, yorum yapmamasını tercih ettiler çünkü kodları orada imza atmadan değiştirmek daha kolaydı. ...
Guy Coder

Uzun vadede onlara kod çalıştığında herkes için yorum yapıldığını söylerim. Bir fonksiyon yazmaya başladığım zaman, türlere girdim. Fonksiyonu çalıştırdıktan sonra tip imzasını bir yoruma götürürüm ve mümkün olduğunca fazla tipten kaldırırım. Bazı durumlarda F # ile çıkarımda yardımcı olmak için türden ayrılmanız gerekir. Bir süredir, let ve = ile yorum oluşturmayı deniyordum, böylece test satırını yorumlayamazdınız, daha sonra tekrar yorumladıysanız, ama aptal görünüyorlardı ve bir let eklemek ve = o kadar zor değil.
Guy Coder

Bu yorumlar ne sorduğunuzu cevaplarsa bana bildirin, böylece ben de onları cevaba taşıyabilirim.
Guy Coder

2
Yani kodu değiştirirken, yorumları değiştirmez ve eski belgelere neden olabilirsiniz? Bu bana bir avantaj gibi gelmiyor. Dağınık yorumların nasıl dağınık koddan daha iyi olduğunu anlamıyorum. Bana göre, bu yaklaşım iki seçeneğin dezavantajlarını birleştiriyor gibi görünüyor.
Aralık'ta

-8

Hata sayısı, bir programdaki karakter sayısı ile doğru orantılıdır!

Bu genellikle kod satırlarıyla orantılı olan hataların sayısı olarak ifade edilir. Ancak aynı miktarda kod içeren daha az satır olması aynı miktarda hata verir.

Bu nedenle açık olmak güzel olsa da, yazdığınız tüm ek parametreler hatalara yol açabilir.


5
“Hataların sayısı bir programdaki karakterlerin sayısıyla doğru orantılı!” Öyleyse hepimiz APL'ye mi geçmeliyiz ? Çok özlü olmak bir sorun, tıpkı çok ayrıntılı olmak gibi.
svick

5
Bu soruyu cevaplandırılabilir hale getirmek için, bir programcının aklındaki belirsizlik maliyetinin birkaç ekstra tuş
darbesinden
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.