2013-09-04 15 views
9

Funkcja ta jest błędna i nie będzie skompilować:Dlaczego liczby Num nie można porównać z 0?

checkIsZero :: (Num a) => a -> String 
checkIsZero a = if a == 0 
        then "Zero" 
        else "Not zero" 

To nie działa z powodu porównania pomiędzy Num i 0 w wyrażeniu a == 0. Zmiana Num na Integral powoduje, że jest to ważna funkcja.

Co to jest ta niegodziwa magia, która nie pozwala mi porównać moich liczb z 0?!

+0

w ghci wydaje się działać na num; czy używasz ghc? jaki jest komunikat o błędzie? – jev

+0

Umieszczam powyższą funkcję w "functions.hs', następnie robię': l functions.hs' w 'ghci' i otrzymuję błąd' Nie można wywnioskować (Eq a) wynikającego z użycia '==' ' –

+3

@jev Od GHC 7.4, to nie powinno działać, przynajmniej nie z tym typem podpisu. 'Eq' nie jest już domniemany przez' Num'. –

Odpowiedz

23

Num wymaga wystąpienia wdrożyć +, *, abs, signum i fromInteger. Zauważ, że == nie ma na liście! Są to egzemplarze typu Eq, które muszą implementować ==.

Ograniczenie Num jest niewystarczające - potrzebne jest również ograniczenie na Eq. Poniższe skompiluje.

checkIsZero :: (Eq a, Num a) => a -> String 
checkIsZero a | a == 0 = "Zero" 
       | otherwise = "Not zero" 

Integral działa, ponieważ coś, co jest instancją Integral sama musi być instancją Ord, który z kolei musi być instancją Eq.

Możesz sprawdzić wszystkie te rzeczy, używając hoogle i zagłębiając się w źródło.

+0

Szybki komentarz - Myślę, że klasa "Integral" jest kolejnym przykładem zerwania klas numerycznych Haskella. Pojęcie, które próbuje uchwycić, to "operacje, które można dzielić z resztą". W matematyce nazywamy to "domeną euklidesową" i obejmuje ona obiekty takie jak liczby całkowite gausów, pierścienie wielomianowe i szeregi potęgowe, które niekoniecznie mają sensowną instancję 'Ord' i nie dopuszczają osadzania w liczbach całkowitych (jak jest to wymagane przez 'toInteger'). Wolałbym zobaczyć klasę 'EuclideanDomain' i oddzielną klasę' Integral', która mogłaby obejmować np. liczby całkowite Z i Z/pZ dla p prim. –

10

Powodem nie wymagając instancję Eq definiowania instancji Num jest, że to wyklucza użytecznych przykładów jak

instance Num b => Num (a -> b) where 
    f + g = \x -> f x + g x 
    f - g = \x -> f x - g x 
    f * x = \x -> f x * g x 
    abs f = \x -> abs (f x) 
    signum f = \x -> signum (f x) 
    fromInteger = const . fromInteger 

ponieważ nie można zapisać wystąpienie Eq dla funkcji.

+4

Odnosi się to nie tylko do takich przypadków funkcji, ale także do algebry symbolicznej, nieskończonej precyzji, typu automatycznej pochodnej ... – leftaroundabout

+2

Myślę, że niektórzy ludzie argumentowaliby, że twój opis danej instancji jest "użyteczny"! –

+5

@BenMillwood Powiedziałbym, że ci ludzie nie są wystarczająco pomysłowi. Przykładowy przypadek użycia, patrz [ten dokument] (http://conal.net/papers/beautiful-differentiation/beautiful-differentiation.pdf), który opisuje prosty sposób implementacji automatycznego różnicowania w Haskell, który zawiera linie takie jak 'cos = cos>

0

Jeśli dane są instancją Num a, to nie jest beneficjentem, że dane te są instancją Eq a.

Integer (i Int, Double) ma zarówno przypadki: instance Num Integer i instance Eq Integer i program nie jest

Integral jest zdefiniowana jako

class (Real a, Enum a)=> Integral a where ... 
class (Num a, Ord a)=> Real a where ... 
class Eq a => Ord a where ... 

~= class (Num a, Eq a, Enum a)=> Integral a where ... --means 
+0

Mój 'ghci' mówi, że' Ord' nie 'Eq' jest superklasą' Real'. –

+0

@Ben Millwood: dzięki, masz rację. Naprawię to. – wit

Powiązane problemy