2017-02-21 6 views
2

ich folgende Art Signatur haben:Warum (Num a, a Ord) => a

let kessel :: (Ord a, Num b) => a -> b -> a; kessel = undefined 

Als ich nach Ergebnistyp gefragt:

:t kessel 1 2 

Ich habe:

kessel 1 2 :: (Num a, Ord a) => a 

Warum nicht Integer?

+0

Es wird 'Integer' wenn Sie den Compiler versichern, dass das erste Argument ein' Integer', kein '' Int' Double' usw. Also ': t kessel (1 :: Integer) 2' ist' Integer' – Michael

+0

Warum bekomme ich nicht nur 'Num' statt' (Num a, Ord a) => a' –

+1

Nur das erste Argument Angelegenheiten. Es muss "Ord" sein, weil du das verlangt hast. Es muss "Num" sein, weil Sie ein numerisches Literal verwendet haben. – Michael

Antwort

9

Da 1 hat Num a => a Typ:

ghci> :t 1 
1 :: Num a => a 
ghci> :t kessel 
kessel :: (Num b, Ord a) => a -> b -> a 
ghci> :t kessel 1 
kessel 1 :: (Num a, Num b, Ord a) => b -> a 
ghci> :t kessel 1 2 
kessel 1 2 :: (Num a, Ord a) => a 

Die Einschränkungen von 1 (Num) erhalten zu den bereits bestehenden hinzugefügt. Es ist das gleiche, wenn Sie id verwenden, zB:

id :: a -> a 
id 1 :: Num a => a 

längere Erklärung

Wenn Sie kessel :: (Ord a, Num b) => a -> (b -> a) verwenden, können Sie den Compiler sagen, dass kesseljedea nehmen, dass eine Instanz von Ord ist. kessel wird dann eine Funktion von jede andere (nicht notwendigerweise anders) Typ b, die auch eine Instanz von Num zu der zuvor genannten Art a.

Dies bedeutet, dass das erste Argument Sie kessel verwenden a gesetzt werden:

ghci> :t kessel (1 :: Int) 
kessel (1 :: Int) :: Num b => b -> Int 
ghci> :t kessel 'A' 
kessel 'A' :: Num b => b -> Char 
ghci> :t kessel "Hello, World!" 
kessel "Hello, World!" :: Num b => b -> String 

In all diesen Fällen ist die Art des Arguments klar war. Was aber, wenn wir einen Wert verwenden, der polymorph ist? Zum Beispiel diese:

magic :: Magic a => a 

Und lassen Sie uns auch eine einfachere Funktion, nämlich const:

const :: a -> b -> a 
const x y = x 

Was ist const magic? Beginnen wir einfacher. Was ist const "Hello, World?"?

const     :: a  -> b -> a 
"Hello, World?"  :: String 
const "Hello, World?" ::   b -> String 

Wir ersetzten jedes Auftreten von a mit "Hello, World?" ‚s-Typ. Nun zurück zu unserem magic Beispiel:

const  ::   a -> b -> a 
magic  :: Magic t => t 
const magic :: Magic t =>  b -> t 

Auch hier ersetzen wir jedes Vorkommen von a mit unserer Art, in diesem Fall t. Wir dürfen jedoch die zusätzliche Nebenbedingung t, nämlich Magic, nicht vergessen. Wir müssen es mitbringen. Daher erhalten wir hier die zusätzliche Einschränkung. Aber wenn es eine Beschränkung auf a gibt, müssen wir sie immer noch auf t setzen.

Gehen wir nun zurück zu Ihrem ursprünglichen kessel:

kessel :: (Num b, Ord a  ) => a -> b -> a 
1  :: (Num n    ) => n 
kessel 1 :: (Num na, Ord na, Num b) =>  b -> na 

Wir noch a ‚s ursprüngliche Beschränkung halten. Daher haben wir jetzt zwei Einschränkungen, Num und Ord. Wenn wir jetzt einen beliebigen Typ verwenden, der die Bedingung Num erfüllt, haben wir nur noch na. Da es nicht auf der rechten Seite ist nicht mehr, kann seine Einschränkung verworfen werden:

kessel 1 2 :: (Num na, Ord na) => na 
+0

Wie kann ich 'kessel 1 :: (Num a, Num b, Orda) => b -> a' lesen? Warum kann ich 'b' hier 'kessel 1 2 :: (Num a, Ord a) => a' eliminieren? Ich kann 'a' hier nicht 'kessel 1 2 :: (Num a, Ord a) => a' eliminieren, weil immer noch gebunden? –

+0

Das Ergebnis von 'ID 1 :: Num a => a' wäre eine Instanz von 'Num'? Was ist eine Context-Vererbung von der Klasse (der Operator '=>')? –

+0

Sie können "a" in "kessel 1 2 :: (Num a, Ord a) => a" eliminieren, indem Sie dem Compiler genau sagen, was Sie mit "1" meinen, z. 'kessel (1 :: Integer) 2 :: Integer' Wie es aussieht, kann ein numerisches Literal in jedem numerischen Typ' a' sein, was 'Num a => ...' bedeutet. – Michael

Verwandte Themen