2016-11-19 73 views
1

我想解决清洁这个问题(非常类似于Haskell这样的语言):如何用两个模板参数编写一个类,其中一个是另一个的列表/数组?

有一个class Node t,有两种情况:instance Node EdgeListinstance Node Adjacency。我想创建一个Graph,它是一个数组或节点列表。

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

回答

1

首先要理解此处是当你写

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

你给l*->*。种类是类型的抽象。粗略地说,亲切的*意味着你有一个'完整的'类型。例如,Int,[Char],a -> String都是*。当一个类型仍然'需要一个参数'时,它有种类*->*。举例来说,如果你有:: Maybe a = Just a | Nothing,然后Maybe Int是样*,而仅仅是Maybe*->*因为它仍然需要一个参数。所以,写resetGraph :: (l t) -> l t时,编译器识别t是一个参数l,所以唯一的办法给予resetGraph*(这是必要的功能),是给l*->*(和t*)。

你需要知道的第二件事是,类型,[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{Adjacency}

顺便说一句:类似这样的事情在做StdEnv与类length

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

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

谢谢你,我现在好理解。出于某种原因,我在'instance Graph [] Node ...'处得到一个错误。错误是:'节点未定义'。节点由两个实例定义。我在'class Graph t2 t2 |没有错误节点t2在哪里' –

+0

@IterAtor不客气。对不起,我写了'Node',我应该写'Adjacency'或'EdgeList'。 (错误告诉你'Node'不是一个类型。)现在已经修复了。 – Keelan

+0

但我觉得我不应该使用'Adjacency'或'EdgeList'直接,因为每次我都需要在'Graph'功能'Node'定义(该功能在这两种情况下的定义) –

相关问题