Functional programming 如何使用两个模板参数编写一个类,其中一个是另一个的列表/数组?
我想用Clean(一种非常类似于Haskell的语言)解决这个问题: 有一个Functional programming 如何使用两个模板参数编写一个类,其中一个是另一个的列表/数组?,functional-programming,clean-language,Functional Programming,Clean Language,我想用Clean(一种非常类似于Haskell的语言)解决这个问题: 有一个类节点t,它有两个实例:实例节点边列表和实例节点邻接。我想创建一个图,它是一个数组或节点列表 图形的定义是: class Graph t1 t2 | Node t2 where resetGraph :: (t1 t2) -> (t1 t2) graphSize :: (t1 t2) -> Int ... 我想写实例。一个带数组,一个带列表。首先,我尝试使用list,但得到一个
类节点t
,它有两个实例:实例节点边列表
和实例节点邻接
。我想创建一个图,它是一个数组或节点列表
图形的定义是:
class Graph t1 t2 | Node t2 where
resetGraph :: (t1 t2) -> (t1 t2)
graphSize :: (t1 t2) -> Int
...
我想写实例。一个带数组,一个带列表。首先,我尝试使用list,但得到一个错误:t2未定义
instance Graph [t1] t2 | t2 t1 where
(resetGraph) :: [t1] -> [t1]
(resetGraph) x = []
...
例如,可以这样调用它:resetGraph listAdj
,其中listAdj是邻接
节点的列表
如果我只写:实例图[tt]tt
,那么我会得到这个错误:错误:这个类型变量在一个实例类型中出现不止一次
class Graph l t | Node t where
resetGraph :: (l t) -> l t
你给的是l
种类*->*
。种类是对类型的抽象。大致上,kind*
表示您有一个“完整”类型。例如,Int
,[Char]
,a->String
都是同类的*
。当类型仍然“需要参数”时,它的种类为*->*
。例如,如果您有::可能a=只是一个|无
,那么可能Int
属于*
类型,但简单地说可能
属于*->*
类型,因为它仍然需要一个参数。因此,当编写resetGraph::(lt)->lt
时,编译器认识到t
是l
的一个参数,因此给出resetGraph
种类*
的唯一方法是给出l
种类*
(和t
种类*
)
您需要知道的第二件事是,[Char]
、(Int,Int)
和a->Real
等类型也可以写入前缀:[]Char
,(,)Int Int
,(>)Real
。您可以将[]
与进行比较:它仍然需要一个参数(此处为Char
)才能成为完整的类型。因此,类型[]
具有种类*->*
。类似地,(,)
也有种类*->*->*
,因为它仍然需要两种类型才能完成,(>)
。(注:本手册第4.5节对此进行了记录)
结合这两者,你应该写:
instance Graph [] Adjacency where
...
然后,resetGraph
的类型被解析为([]邻接)->[]邻接
,这与[邻接]->[邻接]
相同
对于数组,前缀表示法是{}Adjacency
表示{Adjacency}
顺便说一下:类似的操作在StdEnv
中通过类length
完成:
// StdOverloaded.dcl
class length m :: !(m a) -> Int
// StdList.icl
instance length [] where ...
谢谢,我现在更明白了。由于某种原因,我在实例图[]节点上得到一个错误,其中…
。错误是:节点未定义
。节点由两个实例定义。我在类图t1 t2 |节点t2没有发现错误,在那里
@IterAtor欢迎您。很抱歉,我写了节点
,我应该在那里写邻接
或边列表
。(错误告诉您,Node
不是一个类型。)它现在已被修复。但我认为我不应该直接使用Adjacency
或EdgeList
,因为我在Graph
中需要的每个函数都是在Node
中定义的(在两个实例中都定义了这些函数)@IterAtor在这种情况下,您可以使用类图l where resetGraph::(l t)->l t | Node t
,即将节点
依赖项移动到类成员(因为它不限制类变量)。@迭代器或者,定义类图l where resetGraph::l->l
,并用实例图[a]|节点a
实例化,取决于您是要在图形
类中还是仅在该实例中强制执行节点
上下文。