1

我想用 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

4

1 回答 1

1

这里首先要理解的是,当你写

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

你给l *->*。种类是类型的抽象。粗略地说,kind*意味着你有一个“完整”的类型。例如,Int, [Char],a -> String都是善良的*。当一个类型仍然“需要一个参数”时,它有 kind *->*。例如,如果你有:: Maybe a = Just a | Nothing, thenMaybe Int是 kind *,但只是Maybe是 kind*->*因为它仍然需要一个参数。因此,在编写 时resetGraph :: (l t) -> l t,编译器会识别出这t是 的参数,因此给出kind (这是函数所必需的)l的唯一方法是给出kind (和kind )。resetGraph*l*->*t*

您需要知道的第二件事是类型 as[Char]和kan(Int,Int)a -> Real都写为前缀:[] Char, (,) Int Int, (->) a Real. 您可以比较[]Maybe它仍然需要一个参数(此处Char)才能成为完整类型。因此,类型 []有 kind *->*。同样,(,)has kind *->*->*,因为它仍然需要两个类型才能完成,就像(->). (注意:这在语言报告的第 4.5 节中有记录)。

结合这两者,你应该写:

instance Graph [] Adjacency where
    ...

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

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

顺便说一句:与此类似的事情是在StdEnv类中完成的length

// StdOverloaded.dcl
class length m :: !(m a) -> Int

// StdList.icl
instance length [] where ...
于 2016-11-19T08:15:56.547 回答