[英]Illegal polymorphic or qualified type in Haskell
为什么Haskell在尝试解析这种类型的签名时会抱怨?
f :: (a,s) -> (forall r.(r -> (a,r)),s)
Haskell does not support impredicative types, and in particular does not allow forall
to appear under any type constructor (except ->
). Haskell不支持impredicative类型,特别是不允许forall
出现在任何类型的构造函数下(除了->
)。
For example, Maybe (forall a. a), [forall a. a->a], ((forall a. a), Bool)
例如, Maybe (forall a. a), [forall a. a->a], ((forall a. a), Bool)
Maybe (forall a. a), [forall a. a->a], ((forall a. a), Bool)
are forbidden. Maybe (forall a. a), [forall a. a->a], ((forall a. a), Bool)
是被禁止的。
Use a newtype
wrapper if that's what you want. 如果这是您想要的,请使用newtype
包装器。
newtype T = T (forall a. a->a)
foo :: [T] -- OK
foo = [T id]
Out of curiosity, what are you trying to use this type for? 出于好奇,你想用这种类型做什么? It looks like the type of a concatenative combinator like quote
such that [X] quote == [[X]]
(sometimes called unit
). 它看起来像quote
的连接组合类型,如[X] quote == [[X]]
(有时称为unit
)。 In other words, it takes a value atop the stack and wraps it in a function which, when applied, pushes that value to the stack. 换句话说,它在堆栈顶部取一个值并将其包装在一个函数中,该函数在应用时将该值推送到堆栈。
Here's one representation I've used in the past for such functions. 这是我过去用于此类功能的一种表示。 The Tupled
type family converts a list of types into a nested tuple to represent a stack. Tupled
类型系列将类型列表转换为嵌套元组以表示堆栈。
-- Tupled '[t1, t2, ..., tn] s == (t1, (t2, (... (tn, s))))
type family Tupled ts t where
Tupled '[] t' = t'
Tupled (t ': ts) t' = (t, Tupled ts t')
Using a newtype
wrapper we can make a function (of a certain input & output arity) that's polymorphic in the “rest” of the stack. 使用newtype
包装器,我们可以创建一个函数(某个输入和输出arity),它在栈的“rest”中是多态的。
newtype as :-> bs = Fun (forall s. Tupled as s -> Tupled bs s)
This is the standard way of hiding impredicative polymorphism , that is, using forall
-quantified types under a type constructor other than a function arrow (->)
, as you did when you tried to write (forall r. (r -> (a, r)), s)
. 这是隐藏impredicative多态的标准方法,即在函数箭头(->)
之外的类型构造函数下使用forall
-quantified类型,就像你在尝试编写时所做的那样(forall r. (r -> (a, r)), s)
。 Haskell doesn't support this directly, but if you use a newtype
wrapper then the compiler knows exactly when to introduce and eliminate the forall
. Haskell不直接支持这个,但是如果你使用newtype
包装器,那么编译器就知道何时引入并消除forall
。
By unwrapping this newtype
and applying it to the stack type, we can apply a wrapped function to a stack. 通过展开这个newtype
并将其应用于堆栈类型,我们可以将一个包装函数应用于堆栈。
apply :: forall z as bs. (as :-> bs) -> Tupled as z -> Tupled bs z
apply (Fun f) as = f @z as
The quote
combinator wraps the top element of the stack in a function: quote
组合器在函数中包装堆栈的顶部元素:
quote :: forall a s. (a, s) -> ([] :-> '[a], s)
quote (a, s) = (Fun $ \s' -> (a, s'), s)
unquote
applies a function on the stack to the rest of the stack. unquote
将堆栈上的函数应用于堆栈的其余部分。
unquote
:: forall z as bs s
. (Tupled as z ~ s)
=> (as :-> bs, s)
-> Tupled bs z
unquote (f, s) = apply @z f s
(Note the equality constraint Tupled as z ~ s
, which means “The input stack type s
must begin with the series of types as
, and whatever remains is called z
”.) (注意等式约束Tupled as z ~ s
,它的意思是“输入堆栈型s
必须与一系列类型开始as
,以及任何残留被称为z
”)。
add
is the addition operator (+)
lifted to stacks; add
是加法运算符(+)
提升到堆栈; it just adds the top two elements of the stack. 它只是添加了堆栈的前两个元素。
add :: forall a. (Num a) => '[a, a] :-> '[a]
add = Fun $ \ (x, (y, s)) -> (x + y, s)
Now, quoting and unquoting an element leaves it unchanged: 现在,引用和取消引用元素会使其保持不变:
unquote (quote ("hello", ()) == ("hello", ())
The addition function can be applied directly… 添加功能可以直接应用......
apply add (1, (2, ())) == (3, ())
…Or placed on the stack and then applied. ...或者放在堆叠上然后应用。
unquote (add, (1, (2, ()))) == (3, ())
This requires the following extensions: 这需要以下扩展:
DataKinds
to allow type-level lists of types DataKinds
允许类型级别的类型列表
RankNTypes
and ScopedTypeVariables
to allow explicit forall
s and bring type variables into scope so we can refer to them with TypeApplications
, because we need AllowAmbiguousTypes
to defer specifying the “stack” type until a call site, as in apply @zf as
RankNTypes
和ScopedTypeVariables
允许明确forall
S和带类型变量进入活动范围,所以我们可以参考他们TypeApplications
,因为我们需要AllowAmbiguousTypes
推迟指定“栈”类型,直到调用点,如apply @zf as
TypeFamilies
to enable the Tupled
type family TypeFamilies
以启用Tupled
类型系列
TypeOperators
to give the nice symbolic name :->
to wrapped function types TypeOperators
给出了很好的符号名称:->
到包装函数类型
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.