【问题标题】:Haskell - container of container and instance declrationHaskell - 容器和实例声明的容器
【发布时间】:2013-10-19 18:43:16
【问题描述】:

来自 Haskell 新手的简短版本:假设我有一个类 Container,其中 Container 有 * -> * 种类。我想把它放到另一个容器中,并且仍然使第二个容器成为原始类的实例,例如:

data Container2 a container = Container2 (container a)

instance Container (Conrainer2 a) where ...

但这似乎是不可能的,因为 GHC 总是会产生如下错误:

Kind mis-match

    The first argument of `Container' should have kind `* -> *',
    but `Container2 a' has kind `(* -> *) -> *'

是否有可能解决这个问题?

长版:我正在使用以下代码对 Java 中的迭代器接口进行建模:

module Main where

data NextResult a iter = Stop | More a (iter a)

class Iter iter where
  next :: iter a -> NextResult a iter

-- Convert iterator to a list
toList :: (Iter c) => c a -> [a]
toList iter = case next iter of
  Stop -> []
  More value iter2 -> value : toList iter2 

-- List itself is iterator
instance Iter [] where
  next [] = Stop
  next (x:xs) = More x xs

main = let iter = [1,2,3,4,5] in print $ toList iter

使用 GHC 7.4.1 编译并打印预期的 1 2 3 4 5。现在我想定义一个转换迭代器,它从一个函数和一个迭代器构造一个新的迭代器。为此,我添加了以下几行:

data TransformedIter from to iter = TransformedIter (from->to) (iter from)

instance Iter (TransformedIter from to) where
  next (TransformedIter f iter) = case next iter of
    Stop -> Stop
    More value iter2 -> More (f value) (TransformedIter f iter2)

但这产生了错误:

Main.hs:21:16:
    Kind mis-match
    The first argument of `Iter' should have kind `* -> *',
    but `TransformedIter from to' has kind `(* -> *) -> *'
    In the instance declaration for `Iter (TransformedIter from to)'

我试图解决这个问题,但结果始终是一种或另一种类型的错误。那么如何在 Haskell 中对这种转换进行建模呢?

更新

我误解了实例声明的工作原理。根据下面的建议,我翻转了 TransformedIter 类型的顺序并最终得到:

module Main where

data NextResult a iter = Stop | More a (iter a)

class Iter iter where
  next :: iter a -> NextResult a iter

toList :: (Iter c) => c a -> [a]
toList iter = case next iter of
  Stop -> []
  More value iter2 -> value : toList iter2 

instance Iter [] where
  next [] = Stop
  next (x:xs) = More x xs

main = let iter = [1,2,3,4,5] in print $ toList iter

data TransformedIter iter from to = TransformedIter (from->to) (iter from)

instance Iter (TransformedIter iter from) where
  next (TransformedIter f iter) = case next iter of
    Stop -> Stop
    More value iter2 -> More (f value) (TransformedIter f iter2)

然而,这又产生了另一个错误:

Main.hs:22:40:
    No instance for (Iter iter)
      arising from a use of `next'
    In the expression: next iter
    In the expression:
      case next iter of {
        Stop -> Stop
        More value iter2 -> More (f value) (TransformedIter f iter2) }
    In an equation for `next':
        next (TransformedIter f iter)
          = case next iter of {
              Stop -> Stop
              More value iter2 -> More (f value) (TransformedIter f iter2) }

我将实例声明更改为:

instance Iter (Iter iter => TransformedIter iter from) where

这又产生了一个错误:

Main.hs:21:10:
    Illegal instance declaration for `Iter
                                        (Iter iter => TransformedIter iter from)'
      (All instance types must be of the form (T a1 ... an)
       where a1 ... an are *distinct type variables*,
       and each type variable appears at most once in the instance head.
       Use -XFlexibleInstances if you want to disable this.)
    In the instance declaration for `Iter (Iter iter =>
                                           TransformedIter iter from)'

在我添加了 -XFlexibleInstances 之后,我得到了:

Main.hs:21:10:
    Illegal polymorphic or qualified type:
      Iter iter => TransformedIter iter from
    In the instance declaration for `Iter (Iter iter =>
                                           TransformedIter iter from)'

所以我仍然看不到如何将 TransformedIter 声明为 Iter 的实例。有什么线索吗?

更新 2

使用 GADTs GHC 扩展我设法定义了 TransformedIter:

module Main where

data NextResult a iter = Stop | More a (iter a)

class Iter iter where
  next :: iter a -> NextResult a iter

toList :: (Iter c) => c a -> [a]
toList iter = case next iter of
  Stop -> []
  More value iter2 -> value : toList iter2 

instance Iter [] where
  next [] = Stop
  next (x:xs) = More x xs

data TransformedIter iter from to where
  TransformedIter :: Iter iter => 
                     (from->to) -> (iter from) -> TransformedIter iter from to

instance Iter (TransformedIter iter from) where
  next (TransformedIter f iter) = case next iter of
    Stop -> Stop
    More value iter2 -> More (f value) (TransformedIter f iter2)

twice = (*) 2

main = let iter = TransformedIter twice [1,2,3,4,5] in print $ toList iter

编译并打印预期的 2 4 6 8 10。但是这个扩展真的有必要吗?

【问题讨论】:

  • 只需翻转 data Container2 container a = Container2 (container a) 之类的参数即可。当您有instance Iter f 时,它预计您可以为元素a 上的迭代器编写f a,而如果您有type F = TransformedIter from to,那么F a 不是a 元素上的迭代器,它是一个迭代器来自内部迭代器 a 的元素 to
  • 另外,这个类在 Haskell 中已经存在 Foldable。特别是,任何Foldable t 都有toList :: t a -> [a],它可以让你构建你的迭代器。
  • 谢谢@J。 Abrahamson ,我明白类型排序有什么问题。但我现在又遇到了一个错误,请查看更新版本。
  • 试试instance Iter iter => Iter (TransformedIter iter from) where:约束是第一位的。
  • 如果您的问题得到解决,适当的做法是为您自己的问题添加一个答案(并继续接受它),而不是修改问题以包含答案。这样,未来的访问者将一眼就知道问题在哪里结束,解决方案从哪里开始! =)

标签: haskell


【解决方案1】:

J. Abrahamson 在 cmets 中给出了答案,现在我终于有了一个无需使用任何 GHC 扩展即可工作的版本(我之前在实例声明中使用了错误的上下文语法):

module Main where

data NextResult a iter = Stop | More a (iter a)

class Iter iter where
  next :: iter a -> NextResult a iter

toList :: (Iter c) => c a -> [a]
toList iter = case next iter of
  Stop -> []
  More value iter2 -> value : toList iter2 

instance Iter [] where
  next [] = Stop
  next (x:xs) = More x xs

data TransformedIter iter from to = TransformedIter (from->to) (iter from)

instance Iter iter => Iter (TransformedIter iter from) where
  next (TransformedIter f iter) = case next iter of
    Stop -> Stop
    More value iter2 -> More (f value) (TransformedIter f iter2)

twice = (*) 2

main = let iter = TransformedIter twice [1,2,3,4,5] in print $ toList iter

打印 2 4 6 8 10

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-29
    • 1970-01-01
    • 2011-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-05
    • 1970-01-01
    相关资源
    最近更新 更多