Литерал OverloadedLists верхнего уровня
У меня есть набор тестов для рефакторинга, и я бы хотел, чтобы он был совместим с обоими Data.List
а также Data.List.NonEmpty
. Упражнение состоит из функцииfoo :: [Foo] -> Foo
и в наборе тестов есть
data Case = Case
{ description :: String
, input :: [Foo]
, expected :: Foo
}
cases :: [Case]
cases =
[ Case { description = "blah blah"
, input = [Foo 1, Foo 2, Foo 3]
, expected = Foo 1
}
, ...
]
Чтобы сделать набор тестов полиморфным с OverloadedLists
, Я попытался
{-# LANGUAGE OverloadedLists #-}
...
data Case list = Case
{ description :: String
, input :: list Foo
, expected :: Foo
}
cases =
[ Case { description = "blah blah"
, input = [Foo 1, Foo 2, Foo 3]
, expected = Foo 1
}
, ...
]
но это дает мне ошибку
• Couldn't match expected type ‘GHC.Exts.Item (list0 Foo)’
with actual type ‘Foo’
The type variable ‘list0’ is ambiguous
...
|
50 | , input = [Foo 1, Foo 2, Foo 3]
| ^^^^^
Я думал переместить IsList list
ограничение на Case
тип данных, вот так
{-# LANGUAGE GADTs #-}
{-# LANGUAGE OverloadedLists #-}
...
data Case list where
Case :: IsList list => String -> list Foo -> Foo -> Case list
cases =
[ Case "blah blah" [Foo 1, Foo 2, Foo 3] (Foo 1), ... ]
но это дает мне ошибку
• Expected kind ‘* -> *’, but ‘list’ has kind ‘*’
• In the type ‘list Foo’
In the definition of data constructor ‘Case’
In the data declaration for ‘Case’
|
24 | Case :: IsList list => String -> list Foo -> Foo -> Case list
| ^^^^^^^^
Я не уверен, какой здесь самый простой подход. Есть подсказки?
1 ответ
Причина, по которой это не работает, заключается в том, что Item
тип List (l Foo) => l
не сам по себе Foo
. Расширение делает это абстракцией и, следовательно, ожидает, что элементы вашего литерала списка будут иметь типItem (l Foo)
.
Однако вы можете добавить ограничение типа, которое говорит, что элементы действительно имеют тип Foo
:
{-# LANGUAGE OverloadedLists #-}
data Case list = Case
{ description :: String
, input :: list Foo
, expected :: Foo
}
cases :: (IsList (l Foo), Item (l Foo) ~ Foo) => [Case l]
cases = [
Case { description = "blah blah"
, input = [Foo 1, Foo 2, Foo 3]
, expected = Foo 1
}
]
Таким образом, мы говорим, что Item (l Foo)
должно быть таким же, как Foo
.