2011-05-25 32 views
18

imzaların ben derleme yaparken aşağıdaki hata iletisini alabilirsiniz:Aşırı yükleme fonksiyonu haskell

Yinelenen tip imzası:
weightedMedian.hs: 71: 0-39: findVal :: [ValPair] -> Çift -> Çift
weightedMedian.hs: 68: 0-36: findVal :: [ValPair] -> Int -> Çift

Çözümümün findValI ve findValD sahip olmaktır. Ancak, findValI sadece Int türünü bir Double'e dönüştürür ve findValD öğesini çağırır.

Ayrıca ben Num (Int, Çift) türlerine değil desen maçı yüzden sadece ben farklı adlar gerek olmazdı Birçok dilde

findVal :: [ValPair] -> Num -> Double 

tip imzasını değiştiremezsiniz olabilir. Haskell'de neden farklı isimlere ihtiyacım var? Bu dile eklemek zor olur muydu? Yoksa orada ejderha var mı?

+1

fonksiyon imza kaldırmayı deneyin tip sınıfları ve sınıf örneklerini ilan içerir: findVal' otomatik olarak hesaplanır işlev imzayı görmek için t. Muhtemelen int ya da double'a sahip olmaz, bunun yerine 'num a => [valPair] -> a -> double' gibi bir şeye benzersiniz. –

+0

@Anupam Jain: Aslında "gerçek" versiyon [ValPair] -> Double -> Double. Bunu yapmak için Augustss 'tekniğini kullanabilirim ve sonra listenin imzaladığı imzayla son bulurum. –

cevap

28

Ad-hoc polimorfizmi (ve adı aşırı yükleme) typeclasses tarafından Haskell verilmektedir:

class CanFindVal a where 
      findVal :: [ValPair] -> a -> Double 

instance CanFindVal Double where 
    findVal xs d = ... 

instance CanFindVal Int where 
    findVal xs d = findVal xs (fromIntegral d :: Double) 

Not bu durumda, findVal beri "gerçekten" bir Double ihtiyacı olduğunu, sadece her zaman almak olurdu bir çift ve bir int geçmek için gerektiğinde, sadece arama sitesinde fromIntegral kullanın. Tipik olarak, aslında farklı davranışlar ya da mantık söz konusu olduğunda yazım tiplerini tercih etmeniz gerekir. tarzı aşırı yüklenmesini (iyi o sortof typeclasses ile yapar ama biz aynı şekilde bunları kullanmayın) -

+2

Elbette, bu çalışır, ancak bu durumda deyimsel bir çözüm değil. CanFindVal, korkunç derecede anlamlı bir yazım değil. -1 – luqui

+5

hangi tür sclv tür: "Genellikle, aslında farklı davranış veya mantık karıştırarak dahil, tipecler istiyorum." – MatrixFrog

+0

oops, yep. benim hatam. % -) – luqui

6

Haskell C++ desteklemiyor. Ve evet, çoğu zaman tür çıkarımı ile ilgisi olan (üstel zaman ya da kararsız hale gelir ya da bunun gibi bir şey) eklemeyle ilgili bazı ejderhalar vardır. Ancak, bunun gibi "uygunluk" kodunu görmek Haskell'de oldukça nadirdir. Hangisi, Int veya Double? Int yönteminiz Double yöntemine delege ettiğinden, benim tahminim Double "doğru" biridir. Sadece onu kullan. Çünkü edebi aşırı yüklenme nedeniyle, hala demek de mümkün:

findVal whatever 42 

Ve 42 bir Double olarak ele alınacaktır. Bu bozan tek vaka yerde temelde bir Int bir şey var ve bu argüman olarak geçmesi gerekiyor gerekiyorsa olduğunu. Sonra fromIntegral kullanın. Ancak, kodunuzun her yerde "doğru" türünü kullanmasını sağlamak istiyorsanız, bu durum nadir olacaktır (ve dönüştürmeniz gerektiğinde, buna dikkat çekmeye değer olacaktır).

+0

Sorunuz "hangisi, Int veya Double?" oldukça fazla yer var. Ağırlıklı bir fonksiyona sahip bir "ağırlıklı medyan" fonksiyonu yazmam isteniyordu. Bu, bir grup ağırlık ve değer alan ve bu durumda "ağırlıklı" medyanı hesaplayan bir ağırlıklı ortalama fonksiyona benziyordu. Ağırlığınız sadece doğal sayılarsa, bu iyi olur. Bununla birlikte, kesirli ağırlıklarımız var ve ben medyanı “tahmin ediyoruz”. Matematiksel olarak biraz anlamsız olan, ancak proje kapsamında yararlı olan. Yani, evet, bir Int veya Tamsayı olmalı ama ağırlıklar için Çiftler kullanıyorum. Bu başımı incitti! –

13

Hem findVal :: [ValPair] -> Double -> Double hem de findVal :: [ValPair] -> Int -> Double'un desteklenmesi genellikle tehlikeli olan ad-hoc polimorfizmini (bkz. http://www.haskell.org/haskellwiki/Ad-hoc_polymorphism) gerektirir. Nedeni ad-hoc polimorfizm aynı sözdizimi ile semantik değiştirmeye izin vermesidir.

Haskell parametrik polimorfizmi ne denir tercih ediyor. Bunu her zaman tip değişkeni bulunan tip imzaları ile görürsünüz.

Haskell tip sınıfları aracılığıyla geçici polimorfizm daha güvenli bir sürümünü destekler.

Üç seçeneğiniz var.

  1. Açık bir işlev adıyla ne yaptığınıza devam edin. Bu makul, hatta bazı c kütüphaneleri, örneğin opengl tarafından kullanılır.
  2. Özel bir tür sınıfı kullanın. Bu muhtemelen en iyi yoldur, ancak ağırdır ve çok miktarda kod gerektirir (haskells tarafından çok kompakt standartlar). Kod için sclv'nin cevabına bak.
  3. varolan tipi sınıfını kullanmayı deneyin ve (eğer GHC kullanıyorsanız) uzmanlık performansı olsun. Bunun gibi

: Bu durumda

findVal :: Num a => [ValPair] -> a -> Double 
{-# SPECIALISE findVal :: [ValPair] -> Int -> Double #-} 
{-# SPECIALISE findVal :: [ValPair] -> Double -> Double #-} 
findVal = ... 
+0

Uzmanlaşmayı kontrol edeceğim. Arka kapıda gizlice görünmek gibi görünüyor ama ben onu alacağım. –

3

, bunu ikinci argüman için Int ve Double hem işleyen bir işlevi yazmak kolay olduğunu düşünüyorum. Sadece findVal yazınız, böylece ikinci argümanda realToFrac. Bu Int'u Double'a dönüştürecek ve sadece Double'u bırakacaktır. Sonra tembelseniz, derleyicinin sizin için türünü çıkarmasına izin verin.

+0

realToFrac kesinlikle bu sorunu giderir. Ben Haskell aşırı C++ tür olsaydı ..... –

+0

@Tim Perry Bazen güzel olurdu büyük sorun bir C++ programcısı gibi düşünüyordum olduğunu düşünüyorum, ama çoğu zaman etrafında güzel bir yol var. – augustss

+0

@augustss Bazen "NP-complete tipi çıkarım her ne zaman düpedüz heyecan verici geliyor" derken? – semicolon

0

diğer birçok programlama dilinde böyle farklı parametre tipleri gibi (bir çeşit) kendi imzaları, aynı adı ancak farklı diğer şeylere sahip fonksiyonlar bildirebilirsiniz. Bu aşırı yükleme denir ve kesinlikle ad-hoc polimorfizm elde etmek için en popüler yoldur.

Haskell kasten tasarımcılar ad-hoc polymorphism ulaşmanın en iyi yolu olarak düşünmüyoruz çünkü aşırı DESTEKLEMEZ. Haskell yolu yerine polimorfizm kısıtlıdır ve `GHCi ve tip o kadar yükleme,

İlgili konular