简体   繁体   English

实例声明中的“非法多态或限定类型”(System-F样式树)

[英]“Illegal polymorphic or qualified type” in instance declaration (System-F style trees)

I'm experimenting with implementing System-F-style data structures in Haskell. 我正在尝试在Haskell中实现System-F样式的数据结构。

I'll use A <B> to mean application of a term A to a type B just to make it unambiguous (also using capitals for types). 我将使用A <B>表示将术语A应用于类型B只是为了使其明确(还对类型使用大写字母)。

Let's say Tree <T> is the type of binary trees with values of type T . 假设Tree <T>是二叉树的类型,其值的类型为T We want to find a type that can act as Tree <T> . 我们想找到一个可以充当Tree <T> There are three constructors: 有三个构造函数:

EmptyTree <T> : (Tree <T>)
Leaf <T> : T → (Tree <T>)
Branch <T> : (Tree <T>) → (Tree <T>) → (Tree <T>)

So, by some cleverness due, I think, to Girard, we can use the following 因此,我认为基于吉拉德的一些聪明才智,我们可以使用以下内容

Tree T = ∀ A. A → (T → A) → (A → A → A) → A

from which 从中

Empty <T>
        = ΛA.λa:A.λf:(T → A).λg:(A → A → A).
            a

Leaf <T> (x:T)
        = ΛA.λa:A.λf:(T → A).λg:(A → A → A).
            f x

Branch <T> (t1:Tree <T>) (t2:Tree <T>)
        = ΛA.λa:A.λf:(T → A).λg:(A → A → A).
            g (t1 <A> a f g) (t2 <A> a f g)

I've found out about the directives needed for these things in Haskell, and I don't think I'm missing any. 我已经在Haskell中找到了用于执行这些操作所需的指令,并且我认为我不会丢失任何指令。 So in Haskell: 因此在Haskell中:

{-# LANGUAGE RankNTypes #-}
type T t = forall a.a -> (t -> a) -> (a -> a -> a) -> a

empty :: T t
empty = \a _ _ -> a
leaf :: t -> T t
leaf x = \_ f _ -> f x
fork :: T t -> T t -> T t
fork t1 t2 = \a f g -> g (t1 a f g) (t2 a f g)

So far, all of this compiles and seems to work. 到目前为止,所有这些都可以编译并且似乎可以使用。 The issue arises when I try to make an instance for Show for my T t type. 当我尝试为T t类型创建Show实例时,就会出现问题。 I've added more directives: 我添加了更多指令:

{-# LANGUAGE RankNTypes, TypeSynonymInstances, FlexibleInstances #-}

and a function for printing the tree 和打印树的功能

displayTree :: Show t => T t -> String
displayTree t = t displayEmpty show displayFork

with appropriate helpers displayEmpty :: String and displayFork :: String -> String -> String . 有合适的助手displayEmpty :: StringdisplayFork :: String -> String -> String This also compiles and works (up to prettiness). 这也可以编译和工作(直到漂亮)。 Now if I try to instantiate T t as an instance of Show 现在,如果我尝试将T t实例化为Show的实例

instance Show t => Show (T t) where
    show = displayTree

I get the following error when trying to compile: 尝试编译时出现以下错误:

    Illegal polymorphic or qualified type: T t
    In the instance declaration for 'Show (T t)'

I (think I) understand the need for TypeSynonymInstances and FlexibleInstances and the pragmatic reasons for their existence, but I don't understand why my type T t still can't be declared an instance of Show . 我(认为我)了解TypeSynonymInstancesFlexibleInstances以及它们存在的实用原因,但是我不明白为什么我的类型T t 仍然不能声明为Show的实例。 Is there a way to do this, and what property of T t means that this is currently problematic in my code? 有没有办法做到这一点, T t什么属性意味着这在我的代码中目前是有问题的?

First, there's a trick which allows you to write some instances for universally quantified types: we remove the forall -s from the instance head, and introduce type equality constraints to whatever types we want to instantiate the variables. 首先,有一个技巧可以让您为通用量化类型编写一些实例:我们从实例头中删除了forall -s,并将类型相等约束引入我们要实例化变量的任何类型。 In our case: 在我们的情况下:

{-# LANGUAGE RankNTypes, FlexibleInstances, TypeFamilies #-}

instance (a ~ String, Show t) => Show (a -> (t -> a) -> (a -> a -> a) -> a) where
  show t = t "nil" show (\l r -> "(" ++ l ++ ", " ++ r ++ ")")

-- show (fork empty (fork (leaf ()) empty)) == "(nil, ((), nil))"

This works because the instance head implicitly quantifies the variable for us. 这是可行的,因为实例头为我们隐式量化了变量。 Of course, if we want to instantiate a polymorphic type to several different types then this trick might not be applicable. 当然,如果我们想将一个多态类型实例化为几种不同的类型,那么这个技巧可能不适用。

On another note, if GHC allowed polymorphic types in instances, that wouldn't be useful, because GHC doesn't support impredicative instantiation (and the ImpredicativeTypes pragma doesn't actually work). 另一个要注意的是,如果GHC在实例中允许多态类型,那将没有用,因为GHC不支持强制性实例化(并且ImpredicativeTypes编译指示实际上不起作用)。 For example, Show (forall a. t) doesn't imply Show [forall a. t] 例如, Show (forall a. t)并不意味着Show [forall a. t] Show [forall a. t] , because [forall a. t] Show [forall a. t] ,因为[forall a. t] [forall a. t] isn't valid to begin with. [forall a. t]开头无效。 Also, class constraints are kinded in the same system as regular type constructors (except that they return in kind Constraint ), so Show (forall a. t) is similarly invalid without impredicative instantiation. 同样,类约束与常规类型构造函数在同一系统中进行分类(除了它们以Constraint类型返回),因此,在没有强制性实例化的情况下, Show (forall a. t) a.t而言Show (forall a. t)同样无效。

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

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