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
When we have
Foldable T,Tmust be a parametric type, i.e. we must be able to form typesT 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 ofT.In your case,
Rowis not parametrized, it is a plain type, something of kind*, not* -> *. So,Foldable Rowis a kind error. In a sense, a foldable must be a generic list-like container, not one that only carriesFieldas in your case.You could instead define
data Row a = Row [a], and useRow Fieldwhen you need that specific case.Alternatively, you could try
MonoFoldable Rowfrom themono-traversablepackage, 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 aFoldableinstance.