【问题标题】:How is it possible to write a class with two template parameters, where one is a list/array of the other?如何编写一个具有两个模板参数的类,其中一个是另一个的列表/数组?
【发布时间】:2016-11-19 03:02:39
【问题描述】:

我想用 Clean(一种与 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

【问题讨论】:

    标签: functional-programming clean-language


    【解决方案1】:

    这里首先要了解的是,当你写的时候

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

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

    您需要知道的第二件事是[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 ...
    

    【讨论】:

    • 谢谢,我现在明白了。出于某种原因,我在instance Graph [] Node where ... 收到错误消息。错误是:Node undefined。节点定义有两个实例。我在class Graph t1 t2 | Node t2 where 没有收到任何错误
    • @IterAtor 不客气。对不起,我写了Node,我应该写AdjacencyEdgeList。 (错误告诉你Node 不是类型。)现在已修复。
    • 但我认为我不应该直接使用AdjacencyEdgeList,因为我在Graph 中需要的每个函数都在Node 中定义(这些函数在两个实例中都定义了)
    • @IterAtor 在这种情况下,您可以使用class Graph l where resetGraph :: (l t) -> l t | Node t,即将Node 依赖项移动到类成员(因为它不限制类变量)。
    • @IterAtor 或者,定义class Graph l where resetGraph :: l -> l 并使用instance Graph [a] | Node a 进行实例化,具体取决于您是要在Graph 类中强制执行Node 上下文,还是仅在该实例中强制执行。跨度>
    猜你喜欢
    • 2013-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-11
    • 2022-10-14
    • 1970-01-01
    • 2011-04-21
    • 2021-03-22
    相关资源
    最近更新 更多