2

I am learning haskell and trying to make a pretty print program. At some point I want to get the length of a row (i.e. number of columns in that row). To be able to do that on my datatype I understand I have to implement Foldable, which relies on Monoid.

Previously my row was just a type alias for a list but for sake of learning I want to make this move

    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

But I get the following compiler error (on 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’

Now I am not familiar with what the kind of a datatype is. I was expecting this to simply defer to Row's only property of type List

2 Answers2

4

When we have Foldable T, T must be a parametric type, i.e. we must be able to form types T Int, T String, etc.

In Haskell we write T :: * -> * for "a type parametrized over a type", since it resembles a function from types to types. The syntax * -> * is called the kind of T.

In your case, Row is not parametrized, it is a plain type, something of kind *, not * -> *. So, Foldable Row is a kind error. In a sense, a foldable must be a generic list-like container, not one that only carries Field as in your case.

You could instead define data Row a = Row [a], and use Row Field when you need that specific case.

Alternatively, you could try MonoFoldable Row from the mono-traversable package, but note that this is a more advanced option, involving type families. Do not take this path lightly before considering its consequences. It ultimately boils down to why you need a Foldable instance.

chi
  • 111,837
  • 3
  • 133
  • 218
  • @HugoPeters With the standard `length` from `Foldable` and non-parametrized `Row` it is indeed impossible. You can declare a different length function, but that will need to have another name (or be in another package, and disambiguate between the two length functions manually). For instance `MonoFoldable` provides `olength` to avoid the name clash. – chi Nov 10 '19 at 17:38
0

what is the "kind" of a datatype?

Types "of kind *" are types of things that can appear in a Haskell program.

Example: Int.

Not an example: Maybe.

a :: Int ; a = 1 can appear in a Haskell program but b :: Maybe ; b = Just 1 can't. It must be b :: Maybe Int ; b = Just 1, to be valid for it to appear in a Haskell program.

What is Maybe Int? It is a type of kind * just as Int is. So what is Maybe? It is a type of kind * -> *. Because Maybe Maybe is also invalid.

The type t appearing after the Maybe must itself be of kind * for Maybe t to be of kind *. Thus the kind of Maybe is * -> *.

Haskell now calls the kind * by new name, Type. Calling it Thing or something could have been more intuitive.

Will Ness
  • 70,110
  • 9
  • 98
  • 181