简体   繁体   中英

Top-level OverloadedLists literal

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), ) => [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 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM