我想为 ZipList (ZipList a) 类型的二维 ziplist 创建一个 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
编译,但只能用OverlappingInstances
执行show $ZipList [ZipList [1,2,3]]
,但随后它会搞砸 show (ZipList [1,2,3])
,这可以通过 IncoherentInstances
修复。
{-# LANGUAGE FlexibleInstances, OverlappingInstances, IncoherentInstances #-}
是否有更好的方法来实现上述目的?
最佳答案
注意:这篇文章写于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]] }
我猜您使用的是 ZipList
,因为它的 Functor
和 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 a
和 Matrix a
本质上都是 [[a]
)。这样您就不必从头开始重写当前的所有函数。
关于Haskell:为二维 ZipList 创建一个显示实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34505104/