在下面的示例中,我试图使foo
返回其“预期”多态输出类型。想法是foo
返回一个多态值和一个存在类型,然后bar
指定元组的类型为隐藏类型。 (当然,这只是工作,如果在bar
种类也存在,这是真的在我的情况)以下示例编译:带约束条件的循环打字
{-# LANGUAGE GADTs, ScopedTypeVariables #-}
module Foo where
import Data.Proxy
import Data.Typeable
data HiddenType where
Hidden :: (Typeable a) => Proxy a -> HiddenType
foo :: (i,HiddenType)
foo = (undefined, Hidden (Proxy::Proxy Int))
data Foo where
Foo :: i -> Foo
bar :: Foo
bar =
let (x,h) = foo
in case h of
(Hidden (p::Proxy i)) -> Foo (x :: i)
我真的需要foo
一个Typeable
约束:
foo :: (Typeable i) => (i,HiddenType)
当我再补充一点约束(没有其他变化),我得到这些错误:
Foo.hs:20:15:
No instance for (Typeable t0) arising from a use of ‘foo’
The type variable ‘t0’ is ambiguous
Relevant bindings include x :: t0 (bound at Foo.hs:20:8)
Note: there are several potential instances:
instance [overlap ok] Typeable()
-- Defined in ‘Data.Typeable.Internal’
instance [overlap ok] Typeable Bool
-- Defined in ‘Data.Typeable.Internal’
instance [overlap ok] Typeable Char
-- Defined in ‘Data.Typeable.Internal’
...plus 14 others
In the expression: foo
In a pattern binding: (x, h) = foo
In the expression:
let (x, h) = foo
in case h of { (Hidden (p :: Proxy i)) -> Foo (x :: i) }
Foo.hs:22:35:
Couldn't match expected type ‘a’ with actual type ‘t0’
because type variable ‘a’ would escape its scope
This (rigid, skolem) type variable is bound by
a pattern with constructor
Hidden :: forall a. Typeable a => Proxy a -> HiddenType,
in a case alternative
at Foo.hs:22:6-24
Relevant bindings include
p :: Proxy a (bound at Foo.hs:22:14)
x :: t0 (bound at Foo.hs:20:8)
In the first argument of ‘Foo’, namely ‘(x :: i)’
In the expression: Foo (x :: i)
Failed, modules loaded: none.
我明白,约束变成共同的论点所以在我看来,这里的问题是GHC无法处理GADT的模式绑定。如果可以,我可以用一个递归让利给这样说:
bar :: Foo
bar =
let (x :: i,h) = foo
(Hidden (p::Proxy i)) = h
in Foo x
这应该使范围的限制,提供额外的参数foo
。我在这里的目的是使h
包含一些(隐藏)具体类型i
,它应作为具体类型的多态函数 GHC抱怨:
Foo.hs:19:8:
You cannot bind scoped type variable ‘i’
in a pattern binding signature
In the pattern: x :: i
In the pattern: (x :: i, h)
In a pattern binding:
(x :: i, h) = foo
Foo.hs:20:8:
My brain just exploded
I can't handle pattern bindings for existential or GADT data constructors.
Instead, use a case-expression, or do-notation, to unpack the constructor.
In the pattern: Hidden (p :: Proxy i)
In a pattern binding: (Hidden (p :: Proxy i)) = h
In the expression:
let
(x :: i, h) = foo
(Hidden (p :: Proxy i)) = h
in Foo x
我使用情况下的假设是 1. foo
2.同时计算i
和HiddenType
2.隐藏类型的值涉及(至少部分)第一个元组元素的计算。这意味着我做而不是想在bar
中拨打foo
两次(一次获得HiddenType
,并且一次使用该类型绑定第一个元组元素)。 在foo
上存在约束时,是否有某种方法可以使bar
的定义成为可能?
你究竟想要做什么?这很少有意义。特别是最后一种情况,你试图用''Hidden'内部的其他类型来统一类型变量 - 恰恰与你可以用存在类型做什么相反。第一种情况不起作用,因为您需要选择一个实例,以便可以解析'Typeable i'约束,例如'let(x,h)= foo'必须是'let(x,h)= foo: :(Int,HiddenType)',但这不起作用,因为你不能从'Hidden'内部神奇地产生一个进入。 – user2407038 2014-11-24 05:54:05
你可能试图实现'Data.Dynamic'吗? – user2407038 2014-11-24 05:54:23
@ user2407038听起来很像'Data.Dynamic'。这个例子*真的被切断了,但是它的核心问题是关于AST中的变量类型。 'foo'就像一个'lambda',其中隐藏类型是变量的(预期)类型。 'bar'就像'let',它需要lambda变量的类型,但是隐藏了那个类型。 – crockeea 2014-11-24 14:20:49