F #


9

F # öğreniyorum. FP'ye Haskell ile başladım ve bunu merak ettim.

F # .NET dili olduğundan, Mappabletıpkı haskell Functortipi sınıf gibi arayüz tanımlamak benim için daha makul görünüyor .

resim açıklamasını buraya girin

Ancak yukarıdaki resim gibi, F # işlevleri kendi başına ayrılır ve uygulanır. Böyle bir tasarımın tasarım amacı nedir? Benim için, Mappable.mapbunu her veri türü için tanıtmak ve uygulamak daha uygun olacaktır.


Bu soru SO'ya ait değildir. Bu bir programlama sorunu değildir. F # Slack veya başka bir tartışma forumunda sormanızı öneririm.
Bent Tranberg

5
@BentTranberg Cömertçe okunurken, The community is here to help you with specific coding, algorithm, or language problems.diğer kriterler yerine getirildiği sürece dil tasarımı sorularını da kapsayacaktır.
kaefer

3
Uzun lafın kısası, F # 'ın tip sınıfları yoktur ve bu nedenle mapher toplama türü için yeniden uygulanması ve diğer yaygın yüksek dereceli işlevler gerekir. Bir arabirim, her koleksiyon türünün ayrı bir uygulama sağlamasını gerektirdiğinden çok az yardımcı olacaktır.
dumetrulo

Yanıtlar:


20

Evet, yüzeyde çok basit bir soru. Ama bunu sonuna kadar düşünmek için zaman ayırırsanız, ölçülemez tip teorisinin derinliklerine girersiniz. Ve tür teorisi de size bakıyor.

İlk olarak, elbette, F # 'ın tip sınıfları olmadığını doğru bir şekilde anladınız ve bu yüzden. Fakat bir arayüz öneriyorsunuz Mappable. Tamam, buna bakalım.

Diyelim ki böyle bir arayüz beyan edebiliriz. İmzasının nasıl olacağını hayal edebiliyor musunuz?

type Mappable =
    abstract member map : ('a -> 'b) -> 'f<'a> -> 'f<'b>

fArayüzü uygulayan tip nerede . Bekle! F # da buna sahip değil! İşte fdaha yüksek türlü bir değişken ve F # daha yüksek türlüğe sahip değil. Bir işlevi f : 'm<'a> -> 'm<'b>veya bunun gibi bir şeyi bildirmenin bir yolu yoktur .

Ama tamam, diyelim ki bu engeli aştık. Ve şimdi bir arayüze sahip Mappabletarafından uygulanabilir List, Array, Seqve mutfak lavabo. Fakat bekle! Şimdi bir fonksiyon yerine bir metodumuz var ve metodlar iyi oluşturmuyor! Yuvalanmış bir listenin her öğesine 42 eklemeye bakalım:

// Good ol' functions:
add42 nestedList = nestedList |> List.map (List.map ((+) 42))

// Using an interface:
add42 nestedList = nestedList.map (fun l -> l.map ((+) 42))

Bakın: Şimdi bir lambda ifadesi kullanmalıyız! Bu .mapuygulamayı bir değer olarak başka bir işleve geçirmenin bir yolu yoktur . Etkili bir şekilde "değerler olarak işlevler" in sonu (ve evet, biliyorum, bir lambda kullanmak bu örnekte çok kötü görünmüyor, ama bana güven, çok çirkinleşiyor)

Ama bekle, hala işimiz bitmedi. Artık bir yöntem çağrısı olduğuna göre, tür çıkarım işe yaramıyor! .NET yönteminin tür imzası nesnenin türüne bağlı olduğundan, derleyicinin her ikisini de çıkarması için bir yol yoktur. Bu aslında yeni başlayanlar .NET kitaplıklarıyla birlikte çalışırken çok sık karşılaşılan bir sorundur. Ve tek tedavi bir tür imza sağlamaktır:

add42 (nestedList : #Mappable) = nestedList.map (fun l -> l.map ((+) 42))

Oh, ama bu hala yeterli değil! nestedListKendisi için bir imza vermiş olmama rağmen, lambda'nın parametresi için bir imza vermedim l. Böyle bir imza ne olmalı? Olması gerektiğini söyleyebilir misiniz fun (l: #Mappable) -> ...? Oh, ve şimdi nihayet sıralamak-N türleri, gördüğünüz gibi, " böyle #Mappableherhangi bir tür" için bir kısayol - yani kendisi genel bir lambda ifade.'a'a :> Mappable

Ya da alternatif olarak, daha yüksek nezakete geri dönebilir ve nestedListdaha kesin bir şekilde beyan edebiliriz :

add42 (nestedList : 'f<'a<'b>> where 'f :> Mappable, 'a :> Mappable) = ...

Ama tamam, şimdilik tür çıkarımını bir kenara bırakalım ve lambda ifadesine ve şimdi mapbaşka bir işleve değer olarak nasıl geçemeyeceğimize geri dönelim . Diyelim ki söz dizimini Elm'in kayıt alanlarıyla yaptığı gibi bir şeye izin vermek için biraz genişletiyoruz:

add42 nestedList = nestedList.map (.map ((+) 42))

Ne tür olurdu .map? Haskell'de olduğu gibi kısıtlı bir tip olmalı !

.map : Mappable 'f => ('a -> 'b) -> 'f<'a> -> 'f<'b>

Vay canına tamam. .NET'in bu türlerin var olmasına bile izin vermediğini bir kenara bırakarak, etkili bir şekilde geri tip sınıfları aldık!

Ancak F # 'ın ilk başta tip sınıfları olmamasının bir nedeni vardır. Bu nedenin birçok yönü yukarıda açıklanmıştır, ancak bunu daha açık bir şekilde ifade etmek gerekirse: basitlik .

Gördüğünüz gibi, bu bir iplik yumağı. Yazım sınıflarına sahip olduğunuzda, kısıtlamalar, daha yüksek nezaket, rütbe-N (veya en azından rütbe-2) olması gerekir ve bunu bilmeden önce, kestirimci türler, tür işlevleri, GADT'ler ve tüm geri kalanı.

Ama Haskell bütün güzellikler için bir bedel ödüyor. Tüm bu şeyleri çıkarmanın iyi bir yolu olmadığı ortaya çıkıyor . Daha yüksek tür tipleri sorta çalışır, ancak kısıtlamalar zaten yoktur. Rütbe-N - hayal bile etme. Ve işe yaradığında bile, anlamanız gereken bir doktora sahip olmanız gereken tür hataları alırsınız. Bu yüzden Haskell'de her şeye nazikçe imza atmanız önerilir . Şey, her şey değil -her şey , ama gerçekten neredeyse her şey. Ve tip imzaları (örneğin içeride letve where) koymadığınızda - sürpriz-sürpriz, bu yerler aslında monomorfize edilmiştir, bu yüzden esasen basit F # alanına geri dönersiniz.

Öte yandan, F # 'da, tür imzalar çoğunlukla belgeler veya .NET birlikte çalışma için nadirdir. Bu iki durumun dışında, F # içine büyük bir karmaşık program yazabilir ve bir kez tip imzası kullanamazsınız. Tür çıkarımı iyi çalışır, çünkü başa çıkması için çok karmaşık veya belirsiz bir şey yoktur.

Ve bu F #'nın Haskell'e göre büyük avantajı. Evet, Haskell süper karmaşık şeyleri çok hassas bir şekilde ifade etmenize izin veriyor, bu iyi. Ancak F #, neredeyse Python veya Ruby gibi çok istekli olmanıza izin verir ve eğer yanılırsanız derleyicinin sizi yakalamasını sağlar.

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.