7

我有一个用于重构练习的测试套件,我希望它Data.ListData.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
   |                                    ^^^^^^^^

我不确定这里最简单的方法是什么。有什么提示吗?

4

1 回答 1

9

这不起作用的原因是因为Itema 的类型本身List (l Foo) => l不是。该扩展对其进行了抽象,因此它期望列表文字的元素为 type 。 FooItem (l Foo)

但是,您可以添加一个类型约束,表明这些项目确实是 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
         }
  ]

在这里,我们因此说Item (l Foo)应该与 相同Foo

于 2019-12-04T10:23:05.333 回答