Reputation: 53
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
Upvotes: 2
Views: 188
Reputation: 71065
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.
Upvotes: 0
Reputation: 116139
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.
Upvotes: 4