Haskell 为什么';这不是型式检验吗?
编译器抱怨:Haskell 为什么';这不是型式检验吗?,haskell,Haskell,编译器抱怨: 无法推断由于使用“bar”而产生的(二进制t0) 从上下文:(二进制t,foot) 受以下类型签名的约束: 复制:福尔t。(二进制t,Foo t)=>代理t->() 无法推断因使用“Foo”而产生的(Foo t2) 从上下文:(二进制t,foot) 受以下类型签名的约束: 复制:福尔t。(二进制t,Foo t)=>代理t->() 具体地说,我很惊讶它没有看到我将t传递到bar,并创建了t0类型变量。t2甚至更神秘,因为foo是用类型t显式注释的,默认情况下,类型变量的作用域不是
- 无法推断由于使用“bar”而产生的(二进制t0) 从上下文:(二进制t,foot) 受以下类型签名的约束: 复制:福尔t。(二进制t,Foo t)=>代理t->()
- 无法推断因使用“Foo”而产生的(Foo t2) 从上下文:(二进制t,foot) 受以下类型签名的约束: 复制:福尔t。(二进制t,Foo t)=>代理t->()
具体地说,我很惊讶它没有看到我将
t
传递到bar
,并创建了t0
类型变量。t2
甚至更神秘,因为foo
是用类型t显式注释的,默认情况下,类型变量的作用域不是这样的。函数签名中的t
与函数体中的t
不相同。您的代码与此等效:
class Foo t where
foo :: t
bar :: Binary t => t -> ()
bar = undefined
repro :: (Binary t, Foo t) => Proxy t -> ()
repro _proxy =
bar (foo :: t)
repro :: (Binary t, Foo t) => Proxy t -> ()
repro _proxy =
bar (foo :: a)
您需要启用ScopedTypeVariables扩展,并为所有t
添加显式的
repro :: (Binary t, Foo t) => Proxy t -> ()
repro _proxy =
bar (foo :: a)
您可能需要打开ScopedTypeVariables
扩展,然后使用
{-# LANGUAGE ScopedTypeVariables #-}
repro :: forall t. (Binary t, Foo t) => Proxy t -> ()
repro _proxy =
bar (foo :: t)
否则,foo::t
中的t
与repro
签名中的另一个t
不相关。本质上,foo::t
等同于foo::forall a。a
这可以说是Haskell定义中最不喜欢的特性之一,ScopedTypeVariables
非常流行,因为它允许解决这个问题。(在我看来,默认情况下它应该是打开的。)为了完整性,这也可以在没有扩展的情况下处理。这里的关键技巧是编写一个类型比需要限制得更多的函数,将代理
的type参数与Foo
实例连接起来。因此:
repro :: forall t. (Binary t, Foo t) => Proxy t -> ()
repro _proxy = bar (foo :: t)
当然,现代的方法是使用更多的扩展来完全消除代理:
-- most general possible type is Foo b => a -> b
fooForProxy :: Foo t => proxy t -> t
fooForProxy _proxy = foo
-- I've changed Proxy to proxy here because that's good practice, but everything
-- works fine with your original signature.
repro :: (Binary t, Foo t) => proxy t -> ()
repro = bar . fooForProxy
调用repro
将再次需要一个类型应用程序,如repro@Int
或其他任何类型