包装/展开通用量化类型

时间:2015-08-24 03:43:30

标签: haskell types existential-type

我导入了一个数据类型X,定义为

data X a = X a

在本地,我已经定义了一个通用量化的数据类型Y

type Y = forall a. X a

现在我需要定义两个函数toYfromY。对于fromY,此定义可以正常工作:

fromY :: Y -> X a
fromY a = a

但如果我为toY尝试相同的操作,我会收到错误

Couldn't match type 'a' with 'a0'
'a' is a rigid type variable bound by the type signature for 'toY :: X a -> y'
'a0' is a rigid type variable bound by the type signature for 'toY :: X a -> X a0'
Expected type: X a0
Actual type: X a

如果我理解正确,toY的类型签名将扩展为forall a. X a -> (forall a0. X a0),因为Y被定义为同义词,而不是新类型,因此两个a定义中的s不匹配。

但如果是这种情况,为什么fromY成功检查?除了使用unsafeCoerce之外,还有什么方法可以解决这个问题吗?

2 个答案:

答案 0 :(得分:7)

您声称要定义存在类型,但您没有。

type Y = forall a. X a

定义了一种通用量化类型。对于类型为Y的内容,对于每个 X a,其类型必须为a。要创建一个存在量化的类型,您总是需要使用data,并且我发现GADT语法比传统的存在语法更容易理解。

data Y where
  Y :: forall a . X a -> Y

forall实际上是可选的,但我认为澄清了事情。

我现在太困了以解决你的其他问题,但如果没有其他人的话,明天我会再试一次。

答案 1 :(得分:6)

注:

这更像是一个评论,但我无法真正把它放在那里,因为它本来是不可读的;请原谅我一次。

除了dfeuer已经告诉过你的内容之外,你可能会看到(当你使用他的答案时)toY现在很容易做到,但你可能无法定义fromY - 因为你基本上失去了类型信息,因此无效

{-# LANGUAGE GADTs #-}
module ExTypes where

data X a = X a

data Y where
  Y :: X a -> Y

fromY :: Y -> X a
fromY (Y a) = a

在这里你有两个不同的a s - 一个来自构造函数Y,一个来自X a - 实际上如果你去掉定义并尝试编译:{{1​​}}编译器会告诉你类型fromY (Y a) = a转义

a

我认为你现在唯一能做的就是这样:

Couldn't match expected type `t' with actual type `X a'
  because type variable `a' would escape its scope
This (rigid, skolem) type variable is bound by
  a pattern with constructor
    Y :: forall a. X a -> Y,
  in an equation for `fromY'

但这可能不会太有用。

问题是你通常应该约束useY :: (forall a . X a -> b) -> Y -> b useY f (Y x) = f x 那里(使用类型类)以获得任何有意义的行为 - 但当然我在这里无能为力。

这个wiki article可能会对您有所了解。