Haskell:为2维ZipLists创建一个show实例

时间:2015-12-29 05:40:56

标签: haskell typeclass

我想为类型为ZipList (ZipList a)的二维ziplists创建一个show实例。以下是我的尝试。

import Control.Applicative

showMatrixZipList :: (Show a) => ZipList (ZipList a) -> String
showMatrixZipList = unlines . getZipList .  fmap (unwords . getZipList . fmap show)

instance (Show a) => Show (ZipList (ZipList a)) where
    show matrix = showMatrixZipList matrix

代码仅使用FlexibleInstances进行编译,但只能使用show $ ZipList [ZipList [1,2,3]]执行OverlappingInstances,但它会弹出show (ZipList [1,2,3]),可以使用{{1}修复}}

IncoherentInstances

有没有更好的方法来完成上述工作?

1 个答案:

答案 0 :(得分:3)

注意:这篇文章是用literate Haskell写的。您可以将其保存为Matrix.lhs并在GHCi中尝试。

问题在于您尝试定义实例that already exists

instance Show a => Show (ZipList a) where
  -- ...

相反,请定义您自己的Matrix类型:

newtype Matrix a = Matrix (ZipList (ZipList a))

但是,由于ZipList a基本上是[a]的包装,因此您也可以将其简化为

> newtype Matrix a = Matrix {getMatrix :: [[a]] }

由于其ZipListFunctor个实例,我猜您使用的是Applicative,因此我们为Matrix提供这些实例:

> instance Functor Matrix where
>   fmap f = Matrix . fmap (fmap f) . getMatrix

> instance Applicative Matrix where
>   pure x                      = Matrix [[x]]
>   (Matrix as) <*> (Matrix bs) = Matrix $ zipWith (zipWith id) as bs

现在您可以编写自己的Show实例,它不会重叠:

> showMatrix :: (Show a) => Matrix a -> String
> showMatrix = unlines . fmap (unwords . fmap show) . getMatrix

> instance Show a => Show (Matrix a) where
>   show = showMatrix

如果您已经为ZipList (ZipList a)编写了一些函数,则可以在Matrix上轻松使用它们:

type ZipMatrix a = ZipList (ZipList a)

someZipFunc :: ZipMatrix a -> ZipMatrix a
someZipFunc = -- ...

someMatrixFunc :: Matrix a -> Matrix a
someMatrixFunc = coerce . someZipFunc . coerce

其中coerce is from Data.Coerce并且在相同表示的类型之间进行转换(ZipMatrix aMatrix a基本上都是[[a])。这样您就不必从头开始重写所有当前功能。