在原始代码中,可以看到我只是将一个表达式提取到绑定中,这是haskell声称应该总是可能的基本事情之一。
最小情况(在freenode上@dminuoso的帮助下创建)
我希望g
保持多态性(以便可以将其提供给其他期望它的函数):
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
main = do
let a :: forall t. Functor t => t () = undefined
let g :: forall u. Functor u => u () = a
pure ()
错误:
source_file.hs:6:44:
Couldn't match expected type ‘forall (u :: * -> *).
Functor u =>
u ()’
with actual type ‘t0 ()’
When checking that: t0 ()
is more polymorphic than: forall (u :: * -> *). Functor u => u ()
In the expression: a
原始问题(动机)发布在#haskell IRC上:
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
class Monad m => Monad' m where
instance Monad' IO where
f1 :: (forall m . Monad' m => m Int) -> IO Int
f1 g = do
let a :: forall n . Monad' n => n Int = g
a
-- this works
--f1 :: (forall m . Monad' m => m Int) -> IO Int
--f1 g = do
-- g
main = print $ "Hello, world!"
但是我得到了
source_file.hs:12:45:
Couldn't match expected type ‘forall (n :: * -> *).
Monad' n =>
n Int’
with actual type ‘m0 Int’
When checking that: m0 Int
is more polymorphic than: forall (n :: * -> *). Monad' n => n Int
In the expression: g
基于https://ghc.haskell.org/trac/ghc/ticket/12587,我尝试显式应用类型以帮助类型检查器:
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
class Monad m => Monad' m where
instance Monad' IO where
f1 :: (forall m . Monad' m => m Int) -> IO Int
f1 g = do
let a :: forall n . Monad' n => n Int = g @n
a
main = print $ "Hello, world!"
但是我得到:
main.hs:13:48: error: Not in scope: type variable ‘n’
答案 0 :(得分:1)
freenode上的@Lears指出,将类型声明放在之上,该声明对其进行了修复,因此可能是GHC中的某种错误。即
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
main = do
let a :: forall t. Functor t => t () = undefined
let g :: forall u. Functor u => u () = a
putStrLn "success"
失败
但是
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
main = do
let a :: forall t. Functor t => t () = undefined
let g :: forall u. Functor u => u ()
g = a
putStrLn "success"
成功。
答案 1 :(得分:1)
documentation on pattern type signatures的相关位是这样的:
与表达式和声明类型签名不同,模式类型签名不是隐式概括的。
因此,模式签名(如您所写的)是一种特殊情况,即泛化(这是将单态类型t
提到范围外的类型变量a
转换为多态类型forall a. t
)未完成。您可以使用任何其他形式的类型签名来恢复一般化过程。例如代替
let foo :: forall a. a = undefined
尝试:
let foo :: forall a. a
foo = undefined
答案 2 :(得分:1)
写作时会发生什么
a :: forall f. Functor f => f ()
a = _
?具体来说,GHC正在寻找哪种类型的表达式来填补空缺(_
)?您可能会认为它正在寻找forall f. Functor f => f ()
,但这并不完全正确。相反,a
实际上更像一个函数,GHC隐式地插入两个参数:一个名为f
且类型为* -> *
的类型参数,以及一个约束{{1}的实例。 }(未命名,就像所有实例一样)。
Functor f
GHC在a :: forall f. Functor f => f ()
a @f {Functor f} = _
-- @-syntax is a currently proposed extension, {}-syntax is fake
(type f :: * -> *; instance Functor f
)的上下文中寻找。这与在{em> f ()
的上下文中寻找(A -> B) -> C -> D
和寻找D
之间是一样的。如果我直接拥有f :: A -> B; c :: C
,则在第一种情况下,我只能写solution :: (A -> B) -> C -> D
,但是在第二种情况下,我必须写出solution
。
这不是你写的时候发生的事情
solution f c
由于您使用的是模式类型签名,而不是普通的模式签名,因此GHC不再为您隐式绑定类型变量和实例。现在,GHC诚实且真实地希望您用a :: forall f. Functor f => f () = _
来填充_
。这很难,我们很快就会看到...
(我真的不认为Daniel Wagner所引用的内容在这里是相关的。我相信这只是指两者之间的差异(当forall f. Functor f => f ()
处于打开状态且ScopedTypeVariables
不在范围内时) type a
隐含的意思是5 :: Num a => a
的方式,而5 :: forall a. Num a => a
不是的意思是g :: a -> a = id
的方式。)
写作时会发生什么
g :: forall a. a -> a = id
?具体来说,它是什么类型?您可能会认为它是undefined
,但这并不完全正确。是的,没错,{em>本身,forall a. a
的类型为undefined
,但是GHC不允许您自己全部写forall a. a
。取而代之的是,表达式中undefined
的每次出现都始终应用于类型参数。上面的内容被隐式重写为
undefined
,然后创建一个新的统一变量(实际上没有名称)undefined @_a0
。该表达式的类型为_a0
。如果我在需要_a0
的上下文中使用此表达式,则Int
必须等于_a0
,并且GHC设置Int
,将表达式重写为
_a0 := Int
(由于undefined @Int
可以 set 设置为某种变量,因此称为统一变量。它位于“我们的”内部控制之下。上方_a0
不能” 可以设置为任何值。它是给定的,并且位于“他们”(用户)的外部控制之下,从而使其成为skolem变量。)
通常,类型变量的自动绑定和统一变量的自动应用效果很好。例如,这两种方法都可以正常工作:
f
undefined :: forall a. a
因为它们分别扩展为
bot :: forall a. a
bot = undefined
(\@a -> undefined @a) :: forall a. a
这样做的时候
bot :: forall a. a
bot @a = undefined @a
,您使某些非常奇怪的事情发生。如前所述,带有a :: forall f. Functor f => f () = undefined
的模式类型签名不会引入任何内容。 RHS上的forall
实际上必须是undefined
。统一变量的隐式应用仍然存在:
forall f. Functor f => f ()
a :: forall f. Functor f => f () = undefined @_a0
,因此undefined @_a0 :: _a0
必须成立。因此,GHC必须设置_a0 ~ (forall f. Functor f => f ())
。通常,这是一个禁忌,因为这是强制性的多态性:将类型变量设置为包含_a0 := (forall f. Functor f => f ())
的类型。但是,在足够陈旧的GHC中,某些功能允许这样做。也就是说,forall
的类型不是undefined
,而是forall (a :: *). a
,其中forall (a :: OpenKind). a
允许这种不可思议性。这意味着您的代码将通过
OpenKind
如果你写
a :: forall f. Functor f => f () = undefined @(forall f. Functor f => f ())
,它将不起作用,因为a :: forall f. Functor f => f () = bot
与bot
的魔术酱不同。此外,这在较新的GHC中将不起作用,后者已消除了这种不可思议的强制性多态性。 (我说这是一件好事)。
您对undefined
的定义,即使具有模式签名,的确确实具有所需的类型a
。该问题现在位于forall f. Functor f => f ()
中:
g
同样, g :: forall f. Functor f => f () = a
不会绑定g
或type f :: * -> *
。同时,instance Functor f
被应用于一些隐式内容:
a
但是... RHS现在具有类型g :: forall f. Functor f => f () = a @_f0 {_}
,而LHS希望它具有类型_f0 ()
。这些看起来不一样。因此,输入错误。
由于您不能停止将forall f. Functor f => f ()
隐式应用到类型变量而只写a
,因此必须在g = a
中允许类型变量的隐式绑定:>
g
这有效。
答案 3 :(得分:-1)
如果我打了一个打孔,GHC
会给我这个:
foo.hs:11:45: error:
• Cannot instantiate unification variable ‘t0’
with a type involving foralls:
forall (b :: * -> *). Monad' b => b Int
GHC doesn't yet support impredicative polymorphism
• In the expression: _
In a pattern binding:
a :: forall (b :: * -> *). Monad' b => b Int = _
In the expression:
do let a :: forall b. Monad' b => b Int = _
a
|
11 | let a :: forall b . Monad' b => b Int = _
|
鉴于评论GHC doesn't yet support impredicative polymorphism
,您可能无法尝试。