Как можно написать класс с двумя параметрами шаблона, где один является списком / массивом другого?

Я хотел бы решить эту проблему в чистоте (язык, очень похожий на Haskell):

E сть class Node tс двумя примерами: instance Node EdgeList а также instance 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,

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) чтобы быть полным типом. Следовательно, тип [] имеет вид *->*, Так же, (,) имеет вид *->*->*потому что это все еще требует двух типов, чтобы сделать (->), (Примечание: это задокументировано в разделе 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 ...
Другие вопросы по тегам