Haskell Scoping in verschachtelten Funktionsdefinitionen mit denen
-
10-07-2019 - |
Frage
Ich habe ein Problem mit Haskells Scoping in where
Definitionen. Wenn ich die folgende Funktion f
habe, wo ich die x
auf die lokal definierte Funktion f1
übergeben möchte, ohne explizit als Parameter zu verwenden, erhalte ich eine Fehlermeldung, dass die Art der x
mit dem man in der Ausgabe von f1
unvereinbar ist, obwohl es das gleiche sein:
f :: Eq a => a -> [a] f x = f1 x where f1 :: Eq a => a -> [a] f1 y = [ x, y ]
Der Fehler ist die folgende:
Couldn't match expected type `a1' against inferred type `a' `a1' is a rigid type variable bound by the type signature for `f1' at test.hs:4:11 `a' is a rigid type variable bound by the type signature for `f' at test.hs:1:8 In the expression: x In the expression: [x, y] In the definition of `f1': f1 y = [x, y] Failed, modules loaded: none.
Wenn ich aber die x
als zusätzliche Parameter übergeben, wie ich in dem folgenden Code mit der Funktion g
tat, es funktioniert gut:
g :: Eq a => a -> [a] g x = g1 x x where g1 :: Eq a => a -> a -> [a] g1 x y = [ x, y ]
Gibt es eine Möglichkeit, die Art a
in f
kompatibel zum Typ a
(oder a1
) in f1
zu machen?
Lösung
Das Problem mit Ihrem Code ist der lokal f1 Typ Signatur scoped. Es gibt an, dass f1 jede Art nehmen
f1 :: Eq a => a -> [a]
Auch wenn dies eine lokale Funktion ist, haben Sie diese Funktion verallgemeinern Lage sein, eine Art zu nehmen, die nicht innerhalb von f existieren werden, was auch immer diese Funktion von f HAS kommen empfängt, so dass die Art Unterschrift ist nicht erforderlich.
Entfernen Sie einfach den f1-Typen Signatur.
Edit: Lesen Sie meine Post zurück zu mir, es ist ein bisschen unklar. ein in f1 ist eine parametrisierte Typ, der alles, aber die an sie übergebenen Argumente sind bereits gebunden in f nehmen. So kann diese Funktion nur erhalten, was ihre Mutterfunktion empfängt, die Art Signatur Sie es gibst bricht diese Regel. Hoffe, das ist ein wenig klarer.
Andere Tipps
Dave ist rechts oben. Eine weitere Möglichkeit, daran zu denken ist, dass, obwohl beide Ihrer Art Signaturen auf die Variable a
beziehen, es ist nicht wirklich die gleiche Art Variable. In der Haskell-Prime-Notation können beide Unterschriften mehr explizit geschrieben als:
forall a . Eq a => a -> [a]
was bedeutet, dass für beide Funktionen, sie ein Argument irgendwelcher Art (innerhalb Eq) annehmen kann. Dies ist offensichtlich nicht der Fall. In Standard Haskell 98, ist die einzige Option, die Art Signatur für f1
zu verzichten. Aber GHC (und andere?) Unterstützung lexikalisch scoped Variablen vom Typ . So könnten Sie schreiben
{-# LANGUAGE ScopedTypeVariables #-}
f :: forall a. Eq a => a -> [a]
f x = f1 x
where
f1 :: a -> [a]
f1 y = [ x, y ]
und das würde gut funktionieren.