繁体   English   中英

Haskell中的非法多态或限定类型

[英]Illegal polymorphic or qualified type in Haskell

为什么Haskell在尝试解析这种类型的签名时会抱怨?

f :: (a,s) -> (forall r.(r -> (a,r)),s)

Haskell不支持impredicative类型,特别是不允许forall出现在任何类型的构造函数下(除了-> )。

例如, Maybe (forall a. a), [forall a. a->a], ((forall a. a), Bool) Maybe (forall a. a), [forall a. a->a], ((forall a. a), Bool)是被禁止的。

如果这是您想要的,请使用newtype包装器。

newtype T = T (forall a. a->a)
foo :: [T] -- OK
foo = [T id]

出于好奇,你想用这种类型做什么? 它看起来像quote的连接组合类型,如[X] quote == [[X]] (有时称为unit )。 换句话说,它在堆栈顶部取一个值并将其包装在一个函数中,该函数在应用时将该值推送到堆栈。

这是我过去用于此类功能的一种表示。 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')

使用newtype包装器,我们可以创建一个函数(某个输入和输出arity),它在栈的“rest”中是多态的。

newtype as :-> bs = Fun (forall s. Tupled as s -> Tupled bs s)

这是隐藏impredicative多态的标准方法,即在函数箭头(->)之外的类型构造函数下使用forall -quantified类型,就像你在尝试编写时所做的那样(forall r. (r -> (a, r)), s) Haskell不直接支持这个,但是如果你使用newtype包装器,那么编译器就知道何时引入并消除forall

通过展开这个newtype并将其应用于堆栈类型,我们可以将一个包装函数应用于堆栈。

apply :: forall z as bs. (as :-> bs) -> Tupled as z -> Tupled bs z
apply (Fun f) as = f @z as

quote组合器在函数中包装堆栈的顶部元素:

quote :: forall a s. (a, s) -> ([] :-> '[a], s)
quote (a, s) = (Fun $ \s' -> (a, s'), s)

unquote将堆栈上的函数应用于堆栈的其余部分。

unquote
  :: forall z as bs s
  .  (Tupled as z ~ s)
  => (as :-> bs, s)
  -> Tupled bs z
unquote (f, s) = apply @z f s

(注意等式约束Tupled as z ~ s ,它的意思是“输入堆栈型s必须与一系列类型开始as ,以及任何残留被称为z ”)。

add是加法运算符(+)提升到堆栈; 它只是添加了堆栈的前两个元素。

add :: forall a. (Num a) => '[a, a] :-> '[a]
add = Fun $ \ (x, (y, s)) -> (x + y, s)

现在,引用和取消引用元素会使其保持不变:

unquote (quote ("hello", ()) == ("hello", ())

添加功能可以直接应用......

apply add (1, (2, ())) == (3, ())

...或者放在堆叠上然后应用。

unquote (add, (1, (2, ()))) == (3, ())

这需要以下扩展:

  • DataKinds允许类型级别的类型列表

  • RankNTypesScopedTypeVariables允许明确forall S和带类型变量进入活动范围,所以我们可以参考他们TypeApplications ,因为我们需要AllowAmbiguousTypes推迟指定“栈”类型,直到调用点,如apply @zf as

  • TypeFamilies以启用Tupled类型系列

  • TypeOperators给出了很好的符号名称:->到包装函数类型

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM