如何用两个模板参数编写 class,其中一个是另一个的 list/array?

How is it possible to write a class with two template parameters, where one is a list/array of the other?

我想用 Clean(一种与 Haskell 非常相似的语言)解决这个问题:

有一个 class Node t,有两个实例:instance Node EdgeListinstance Node Adjacency。我想创建一个图形,它是一个数组或节点列表。

Graph的定义是:

class Graph t1 t2 | Node t2 where
    resetGraph  :: (t1 t2) -> (t1 t2)
    graphSize   :: (t1 t2) -> Int
    ...

我想写实例。一种是数组,另一种是列表。首先,我尝试使用列表,但出现错误:t2 not defined

instance Graph [t1] t2 | t2 t1 where
    (resetGraph) :: [t1] -> [t1]
    (resetGraph) x = []
    ...

它会被这样调用:resetGraph listAdj 其中 listAdj 是 Adjacency 个节点的列表

如果我只写:instance Graph [tt] tt 然后我得到这个错误:Error: this type variable occurs more than once in an instance type.

这里首先要明白的是,当你写

class Graph l t | Node t where
    resetGraph :: (l t) -> l t

你给l种类*->*。种类是类型的抽象。粗略地说,kind * 意味着你有一个 'complete' 类型。例如Int[Char]a -> String都是*的种类。当类型仍然是 'needs an argument' 时,它的种类是 *->*。例如,如果您有 :: Maybe a = Just a | Nothing,那么 Maybe Int 属于 *,但 Maybe 属于 *->*,因为它仍然需要一个参数。所以,当写 resetGraph :: (l t) -> l t 时,编译器认为 tl 的参数,所以唯一的方法是给 resetGraph 类型 *(这是必要的对于一个函数),就是给 l kind *->*(和 t kind *)。

您需要知道的第二件事是 [Char](Int,Int)a -> Real 类型也可以写成前缀:[] Char(,) Int Int(->) a Real。你可以比较 []Maybe:它仍然需要一个参数(这里是 Char)是一个完整的类型。因此,类型 [] 具有种类 *->*。类似地,(,) 有种类 *->*->*,因为它仍然需要两个类型才能完整,(->) 也是如此。 (注意:这在 language report 的第 4.5 节中有记录)。

结合这两个,你应该写:

instance Graph [] Adjacency where
    ...

然后,resetGraph的类型解析为([] Adjacency) -> [] Adjacency,与[Adjacency] -> [Adjacency]相同。

对于数组,前缀表示法是 {} Adjacency for {Adjacency}

顺便说一句:在 StdEnv 中用 class length:

完成了类似的事情
// StdOverloaded.dcl
class length m :: !(m a) -> Int

// StdList.icl
instance length [] where ...