Ich habe den Typ des Arguments einer Funktion eingeschränkt, anstatt den Typ der Funktion einzugeben.
Ich dachte, dies würde entweder einen Syntaxfehler verursachen oder dem Typ der Funktion weitere Informationen hinzufügen.
Es sieht jedoch so aus, als würde die Einschränkung vollständig ignoriert.
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE RankNTypes #-}
test :: a -> String
test (n :: (Num a, Ord a) => a) =
if n > 10 then "Hello"
else "World"
main = print "Hello World"
Dies ergibt den folgenden Typfehler:
Test3.hs:6:8: error:
• No instance for (Num a) arising from a use of ‘n’
Possible fix:
add (Num a) to the context of
the type signature for:
test :: forall a. a -> String
• In the first argument of ‘(>)’, namely ‘n’
In the expression: n > 10
In the expression: if n > 10 then "Hello" else "World"
|
6 | if n > 10 then "Hello"
| ^
Test3.hs:6:8: error:
• No instance for (Ord a) arising from a use of ‘>’
Possible fix:
add (Ord a) to the context of
the type signature for:
test :: forall a. a -> String
• In the expression: n > 10
In the expression: if n > 10 then "Hello" else "World"
In an equation for ‘test’:
test (n :: (Num a, Ord a) => a)
= if n > 10 then "Hello" else "World"
|
6 | if n > 10 then "Hello"
|
Was bedeutet es eigentlich, eine Einschränkung in den Typ des Arguments zu setzen?
BEARBEITEN:
Warum muss dies RankNTypes
erweitert werden?
Es wird nicht benötigt, wenn ich (Num a, Ord a) =>
Einschränkungen entferne .
Antworten:
Dies ist eine ziemlich exotische Instanz der polymorphen Subsumtion, wie hier beschrieben , die mit der Constraint-Subsumtion interagiert.
Wenn ein Typ
a
subsumiertb
,exp :: a
impliziert diesexp :: b
in der Oberflächensprache. Ein besonderes Beispiel für eine Subsumtion istf :: forall a. a -> a
diesf :: Int -> Int
. Wir haben auchn :: Int
Implikationenn :: c => Int
für jedec
Einschränkung.In der Kernsprache gibt es jedoch überhaupt keine Subsumtion. Jeder Fall der Subsumtion in der Oberflächensprache muss in explizite Lambdas und Anwendungen übersetzt werden. Auch wird
c => a
einfachc -> a
, und die Verwendung von eingeschränkten Funktionen wird in einfache Funktionsanwendung vonf :: c => a
einigen übersetztinst :: c
. Daherf :: forall a. a -> a
wirdf @Int :: Int -> Int
undn :: Int
wird\_ -> n :: c -> Int
.Ein selten verwendeter Fall ist die kontravariante Subsumtionsregel für Funktionen. Folgendes ist gültiger Code:
Dies wird übersetzt in
Ähnlich funktioniert es mit der Subsumtion von Einschränkungen:
Welches ist übersetzt in
Näher an der ursprünglichen Frage, wenn wir haben
als Top-Definition ist sein abgeleiteter Typ
forall a. (Eq a => a) -> Bool
. Wir können jedoch jede Typanmerkung haben, fürf
die der abgeleitete Typ subsumiert wird! So können wir haben:Und GHC ist immer noch glücklich. Der ursprüngliche Code
entspricht der etwas klareren folgenden Version:
Der Typfehler, den Sie erhalten, ist einfach, weil
n
es sich tatsächlich um eine Funktion mit zwei Argumenten handelt, von denen eines den TypNum a
und das andereOrd a
hat und beide Argumente DatensätzeNum
undOrd
Methoden enthalten. Da die Definition jedoch keine solchen Instanzen enthält, können Sie sie nichtn
als Zahl verwenden. Die Übersetzung würden > 10
nach(>) inst (n inst) (10 inst)
, wo konvertiereninst :: Num a
, aber es gibt keine solcheinst
, so dass wir nicht übersetzen können.Daher wird im Hauptteil des
test
Codes noch geprüftn :: (Num a, Ord a) => a)
. Wenn wir jedoch nur "Hallo" zurückgeben, ohne es zu verwenden , erhalten wirn
ähnlich wie im vorherigenf
Fall einen abgeleiteten Typ, der denforall a. a -> String
Annotationstyp subsumiert . Die Subsumtion wird dann in der Übersetzungsausgabe realisiert, indem jedes Vorkommenn
im Körper vontest
mit ersetzt wird\_ -> n
. Dan
dies aber im Körper nicht vorkommt, macht die Übersetzung hier nichts.quelle