2016-05-03 15 views
3

Ich bin auf ein Verhalten gestoßen, das ich in Haskell nicht erklären kann. Ich versuche, eine polymorphe Funktion in einem Datensatztyp zu speichern, den ich in einem ReaderT Monad verwenden möchte. Wenn ich meine Funktion mit asks bekomme, erkennt der Compiler es nicht als polymorph und scheint den Typ beim ersten Auftreten der Funktion zu reparieren. Ich habe ein minimales Beispiel dafür in GHCI:Polymorphe Funktionen in Datensatztypen Haskell

{-# LANGUAGE Rank2Types    #-} 

data Test = Test {f :: (forall a. a -> a)} 

runReaderT (asks f 
      >>= \f -> (liftIO . putStrLn $ show (f 2 :: Int)) 
        >> (liftIO . putStrLn $ show (f "hello")) 
      ) (Test id) 

Beim Versuch, dies zu laufen, erhalte ich:

Couldn't match expected type ‘Int’ with actual type ‘[Char]’ 
In the first argument of ‘f’, namely ‘"hello"’ 
In the first argument of ‘show’, namely ‘(f "hello")’ 
In the second argument of ‘($)’, namely ‘show (f "hello")’ 

jedoch folgende Code funktioniert:

runReaderT (ask 
      >>= \(Test f) -> (liftIO . putStrLn $ show (f 2 :: Int))  
          >> (liftIO . putStrLn $ show (f "hello")) 
      ) (Test id) 

So ist es etwas, speziell mit asks? Ich bin dankbar für jeden Hinweis darauf.

+0

Ich denke, es zu tun hat mit 'f' nach dem \ erscheinen, wenn ich mich nicht irre, sind Lambda-Argumente, wenn Sie noch monomorphic anders angeben. – Ingo

+1

Nur ein Kopf: Rank2Types ist eine veraltete Erweiterung, Aliasing RankNTypes. (Und RankNTypes erlaubt dir nur 'Forall's zu schreiben. Keine Rückmeldung vom Typ GHC, wie Ingo's Antwortdetails.) – hao

Antwort

4

Als ich das letzte Mal überprüft habe, konnte GHC keine höheren Rank-Typen ableiten. Wenn also haben Sie

\f -> ... f x .... f y 

die f kann niemals polymorph sein.

Es gibt nur zwei Stellen, an denen der Typ einer Variablen so offensichtlich ist, dass Typinferenz den höheren Rangtyp erkennt: in Mustern, die Felder mit höherem Rang deklarieren und in der LHS von annotierten Funktionen.

Es sollte auch ausdrücklich auf die Art zu geben, arbeiten, wie in

\(f :: forall a.a -> a) -> .... f x ... f y 
+0

Danke für die schnelle Antwort! Das erklärt es. Also passend zu \ (Test f) -> ist der erste Fall, den du erwähnst, oder? –

+0

Genau, deshalb hat es funktioniert. – Ingo

Verwandte Themen