Haskell:为二维 ZipList 创建一个显示实例

标签 haskell typeclass

我想为 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,因为它的 FunctorApplicative 实例,所以让我们为 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])。这样您就不必从头开始重写当前的所有函数。

关于Haskell:为二维 ZipList 创建一个显示实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34505104/

相关文章:

haskell - 你能在 Haskell 中为整个类而不是类型创建一个类的实例吗?

Haskell:a -> a 类型函数的示例,除了标识

haskell - 无法创建 monad 转换器的派生实例

Haskell 在(理论上)不应该出现的情况下陷入僵局

haskell - 在 Haskell 中使用类型类访问相似数据类型的字段

scala - 部分应用的通用函数 "cannot be cast to Nothing"

haskell - 为类型类的子类定义方法

parsing - 秒差距输入意外结束

regex - 在 Haskell 中插入 regexp() SQLite 函数 (Database.SQLite3 ,"direct-sqlite")

haskell - Haskell 中 FFI 调用的类型自动转换