首页 > 解决方案 > 由于类型错误,无法实现可折叠实例

问题描述

我正在学习haskell并尝试制作一个漂亮的打印程序。在某些时候,我想获得一行的长度(即该行中的列数)。为了能够在我的数据类型上做到这一点,我知道我必须实现可折叠的,它依赖于 Monoid。

以前我的行只是列表的类型别名,但为了学习,我想采取这一行动

    import System.IO
    import System.Directory
    import Control.Monad
    import Data.Maybe
    import Data.Monoid
    import Data.Foldable
    import Data.Functor
    import Data.List.Split

    type Field = String
    data Row = Row [Field]

    instance Monoid Row where
        mempty = Row []


    instance Foldable Row where
        foldMap f (Row fs) = foldMap f fs

但我收到以下编译器错误(在 ghci 8.0.2 上)

main.hs:20:19: error:
    • Expected kind ‘* -> *’, but ‘Row’ has kind ‘*’
    • In the first argument of ‘Foldable’, namely ‘Row’
      In the instance declaration for ‘Foldable Row’

现在我不熟悉数据类型的类型。我希望这只是简单地遵循 Row 的 List 类型的唯一属性

标签: haskellghcfoldable

解决方案


当我们有Foldable T,T必须是参数类型,即我们必须能够形成类型T Int,T String等。

在 Haskell 中,我们T :: * -> *为“在类型上参数化的类型”写作,因为它类似于从类型到类型的函数。这种语法* -> *称为. _T

在您的情况下,Row不是参数化的,它是一种普通类型,某种类型的东西*,而不是* -> *. 所以,Foldable Row是一种错误。从某种意义上说,可折叠的必须是一个通用的类似列表的容器,而不是仅Field在您的情况下携带的容器。

您可以改为定义data Row a = Row [a], 并Row Field在需要特定情况时使用。

MonoFoldable Row或者,您可以从包中尝试mono-traversable,但请注意,这是一个更高级的选项,涉及类型族。在考虑其后果之前,不要掉以轻心。它最终归结为您需要实例的原因。Foldable


推荐阅读