我偶然发现了一个我无法在Haskell中解释的行为。我试图在记录类型中存储多态函数,我想在ReaderT Monad中使用它。当我使用asks
获取函数时,编译器不会将其识别为多态,并且似乎在函数的第一次出现时修复了该类型。我在ghci中创建了一个最小的例子:
{-# 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)
尝试运行时,我得到:
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")’
但是,以下代码有效:
runReaderT (ask
>>= \(Test f) -> (liftIO . putStrLn $ show (f 2 :: Int))
>> (liftIO . putStrLn $ show (f "hello"))
) (Test id)
asks
这是特别的吗?我对此提出任何建议表示感谢。
答案 0 :(得分:4)
上次我查看时,GHC无法推断出更高等级的类型。因此,当你有
\f -> ... f x .... f y
f
永远不会是多态的。
只有两个地方,某些变量的类型是如此明显,以至于类型推断识别出更高级别的类型:在声明更高等级字段的模式中以及在带注释函数的LHS中。
它也应该明确地给出类型,比如
\(f :: forall a.a -> a) -> .... f x ... f y