为什么 GHC.Types.Any 在这里?
Why GHC.Types.Any here?
我刚才在 Haskell 中打了一些代码,我 运行 犯了一个当时对我来说意义不大的错误。决定在 GHCi 中检查一下,现在我真的很困惑。
λ> :t replicate <$> readLn
replicate <$> readLn :: IO (a -> [a])
λ> f <- replicate <$> readLn
-- I type 4 and press Enter
λ> :t f
f :: GHC.Types.Any -> [GHC.Types.Any]
为什么 f
不是 a -> [a]
类型?我可以 unsafeCoerce
,当然,但是那太冗长和可怕了。
IO (a -> [a])
是多态类型。展开,就是forall a. IO (a -> [a])
。现在,有两件事在这里不起作用。第一,这是一个产生单态函数的多态 IO
动作。本质上,每次执行此操作都会产生一个 one 类型的函数。 a -> [a]
不是真正有效的类型,但如果你的意思是你想要一个 forall a. a -> [a]
,你不会得到一个:
main = do
f <- replicate <$> readLn
print (f (5 :: Int)) -- f can be *one of* Int -> [Int] or Float -> [Float], but not both
print (f (5 :: Float)) -- doesn't compile, comment either line out and it will
第二,GHC 不支持谓词多态性。理论上,如果您正确地编写了 IO
操作,您可以将其设置为 IO (forall a. a -> [a])
,但 GHC 不支持将多态类型(如 forall a. a -> [a]
)放入容器中,如 IO
.
在你的例子中,因为你不使用 f
,GHC 不知道它应该在哪种类型上实例化操作,但它必须选择一个,所以它默认为 Any
.
编辑:绕过 "no impredicative types" 限制的传统方法是将它们隐藏到 newtypes
:
{-# LANGUAGE RankNTypes #-}
-- interestingly, this is a numeric type (it represents the natural numbers)
newtype Replicator = Replicator { runReplicator :: forall a. a -> [a] }
mkReplicator :: Int -> Replicator
mkReplicator i = Replicator (replicate i)
-- mkReplicator =# replicate
main = do
Replicator f <- mkReplicator <$> readLn
print (f (5 :: Int))
print (f (5 :: Float)) -- should work now
可能不值得...
这里有两个问题。一个是用这段代码说明的:
Prelude> do { f <- return (replicate 4); print (f 'a'); print (f 'b') }
"aaaa"
"bbbb"
Prelude> do { f <- return (replicate 4); print (f 'a'); print (f "b") }
[...]
* Couldn't match expected type `Char' with actual type `[Char]'
[...]
Haskell 类型系统的限制导致 f
是单态的,也就是说,只能用于一种类型(您选择的)。 HTNW 已经介绍了这一点。
第二个问题是 GHCi 特有的。这段代码说明了这一点:
Prelude> do { f <- return (replicate 4); print (f 'a') }
"aaaa"
Prelude> f <- return (replicate 4)
Prelude> print (f 'a')
[...]
* Couldn't match expected type `GHC.Types.Any'
with actual type `Char'
[...]
GHC 有两种方法可以将类型分配给类型不明确的表达式。一个是数字默认值,这里不相关。另一个适用于类型、数字或其他方面没有类型类约束的情况。在那种情况下,类型不会影响程序的 运行 时间行为,所以你选择什么并不重要。 GHC 使用 GHC.Types.Any
.
通常情况下,您永远不会看到第二种默认设置的结果,因为它只会在编译器知道类型无关紧要之后发生。
但是,GHCi 会在您输入的每一行后应用这些默认规则,让您没有机会用以后的代码来限制类型。因此,只要它是 Any
.
,您就可以获得您想要的任何类型,而不是您想要的任何类型
我刚才在 Haskell 中打了一些代码,我 运行 犯了一个当时对我来说意义不大的错误。决定在 GHCi 中检查一下,现在我真的很困惑。
λ> :t replicate <$> readLn
replicate <$> readLn :: IO (a -> [a])
λ> f <- replicate <$> readLn
-- I type 4 and press Enter
λ> :t f
f :: GHC.Types.Any -> [GHC.Types.Any]
为什么 f
不是 a -> [a]
类型?我可以 unsafeCoerce
,当然,但是那太冗长和可怕了。
IO (a -> [a])
是多态类型。展开,就是forall a. IO (a -> [a])
。现在,有两件事在这里不起作用。第一,这是一个产生单态函数的多态 IO
动作。本质上,每次执行此操作都会产生一个 one 类型的函数。 a -> [a]
不是真正有效的类型,但如果你的意思是你想要一个 forall a. a -> [a]
,你不会得到一个:
main = do
f <- replicate <$> readLn
print (f (5 :: Int)) -- f can be *one of* Int -> [Int] or Float -> [Float], but not both
print (f (5 :: Float)) -- doesn't compile, comment either line out and it will
第二,GHC 不支持谓词多态性。理论上,如果您正确地编写了 IO
操作,您可以将其设置为 IO (forall a. a -> [a])
,但 GHC 不支持将多态类型(如 forall a. a -> [a]
)放入容器中,如 IO
.
在你的例子中,因为你不使用 f
,GHC 不知道它应该在哪种类型上实例化操作,但它必须选择一个,所以它默认为 Any
.
编辑:绕过 "no impredicative types" 限制的传统方法是将它们隐藏到 newtypes
:
{-# LANGUAGE RankNTypes #-}
-- interestingly, this is a numeric type (it represents the natural numbers)
newtype Replicator = Replicator { runReplicator :: forall a. a -> [a] }
mkReplicator :: Int -> Replicator
mkReplicator i = Replicator (replicate i)
-- mkReplicator =# replicate
main = do
Replicator f <- mkReplicator <$> readLn
print (f (5 :: Int))
print (f (5 :: Float)) -- should work now
可能不值得...
这里有两个问题。一个是用这段代码说明的:
Prelude> do { f <- return (replicate 4); print (f 'a'); print (f 'b') }
"aaaa"
"bbbb"
Prelude> do { f <- return (replicate 4); print (f 'a'); print (f "b") }
[...]
* Couldn't match expected type `Char' with actual type `[Char]'
[...]
Haskell 类型系统的限制导致 f
是单态的,也就是说,只能用于一种类型(您选择的)。 HTNW 已经介绍了这一点。
第二个问题是 GHCi 特有的。这段代码说明了这一点:
Prelude> do { f <- return (replicate 4); print (f 'a') }
"aaaa"
Prelude> f <- return (replicate 4)
Prelude> print (f 'a')
[...]
* Couldn't match expected type `GHC.Types.Any'
with actual type `Char'
[...]
GHC 有两种方法可以将类型分配给类型不明确的表达式。一个是数字默认值,这里不相关。另一个适用于类型、数字或其他方面没有类型类约束的情况。在那种情况下,类型不会影响程序的 运行 时间行为,所以你选择什么并不重要。 GHC 使用 GHC.Types.Any
.
通常情况下,您永远不会看到第二种默认设置的结果,因为它只会在编译器知道类型无关紧要之后发生。
但是,GHCi 会在您输入的每一行后应用这些默认规则,让您没有机会用以后的代码来限制类型。因此,只要它是 Any
.