在存在主义中包装类型类函数时的模糊类型变量

时间:2014-02-12 09:55:40

标签: haskell typeclass existential-type

我在解释器中使用了类型化的无标记最终编码。不幸的是,我遇到了类型检查阶段的问题。最小的测试用例如下:

{-# LANGUAGE RankNTypes, ExistentialQuantification, NoMonomorphismRestriction #-}
class Program repr where
    ...
    intro1 :: repr a (a, ())
    ...

data DynTerm repr = forall x y. (Typeable x, Typeable y) => DynTerm (repr x y)

ghci> DynTerm intro1

这会产生以下错误:

Could not deduce (Typeable x0) arising from a use of `DynTerm'
from the context (Program repr)
  bound by the inferred type of it :: Program repr => DynTerm repr
  at <interactive>:3:1-14
The type variable `x0' is ambiguous
Possible fix: add a type signature that fixes these type variable(s)
Note: there are several potential instances:
  instance Typeable Void -- Defined in `Data.Void'
  instance [overlap ok] Typeable ()
    -- Defined in `Data.Typeable.Internal'
  instance [overlap ok] Typeable Bool
    -- Defined in `Data.Typeable.Internal'
  ...plus 25 others
In the expression: DynTerm intro1
In an equation for `it': it = DynTerm intro1

我期望编译器推理如下:

  • 尝试统一a with x。
  • 将Typeable a添加到约束列表中(我可以通过类型注释手动添加它,这没有区别)。
  • 成功。
  • 尝试用y来统一(a,())。
  • 请注意,由于我们假设Typeable a,Typeable(a,())也成立。
  • 成功。

然而,似乎未能统一x。

2 个答案:

答案 0 :(得分:3)

使用DynTerm构造函数构造DynTerm类型的值时,GHC必须知道具体类型xy才能确定Typeable应该打包字典。在测试表达式中,您没有提供足够的类型信息来确定具体类型,因此您会收到某些类型变量不明确的错误。如果您专门选择具体的Typeable类型,它就可以使用。

示例(带ScopedTypeVariables):

test :: forall repr. Program repr => DynTerm repr
test = DynTerm (intro1 :: repr Int (Int, ()))

答案 1 :(得分:2)

正如kosmikus所指出的那样,ExistentialQuantification意味着你将抽象出类型变量,但你的数据类型的实现者必须选择一个单态类型:

  

When a value of this type is constructed, s will be instantiated to some concrete type. When such a value is analysed, s is abstract.

请考虑以下事项:

data D = forall a . Show a => D (a -> String) 
-- test0 = D show -- Invalid!
test1 = D (show :: () -> String)

data E = E (forall a . Show a => a -> String)
test2 = E show -- Invalid!
-- test3 = E (show :: () -> String)

所以也许你想要

data DynTerm repr = DynTerm (forall x y. (Typeable x, Typeable y) => repr x y)

但这仍不适用于intro1 - 它的多态性不够((a,())x更具体)。如果您有intro2 :: Program repr => repr x y,则可以撰写DynTerm intro2

相关问题