Как можно написать класс с двумя параметрами шаблона, где один является списком / массивом другого?
Я хотел бы решить эту проблему в чистоте (язык, очень похожий на 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 ...