I've got a test suite for a refactoring exercise where I'd like it to be compatible with both Data.List
and Data.List.NonEmpty
. The exercise consists of a function foo :: [Foo] -> Foo
and the test suite has some
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
}
, ...
]
To make the test suite polymorphic with OverloadedLists
, I tried
{-# 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
}
, ...
]
but this gives me the error
• 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]
| ^^^^^
I thought to move the IsList list
constraint to the Case
data type, like so
{-# 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), ... ]
but this gives me the error
• 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
| ^^^^^^^^
I'm not sure what the simplest approach here is. Any hints?
The reason this does not work is because the Item
type of a List (l Foo) => l
is not per se Foo
. The extension makes abstraction of that, and thus it expects the elements of your list literal to be of type Item (l Foo)
.
You can however add a type constraint that says that the items are indeed of type 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
}
]
Here we thus say that the Item (l Foo)
should be the same as Foo
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With