Reputation: 595
I've just started learning functional programming with Haskell and I need your help in the case below.
The idea is to display a Matrix using the show function in the following way:
> Mat [[1,2,3],[4,5,6]]
1 2 3
4 5 6
I already have a suggested solution that achieves the above outcome, but I do not particularly understand it.
data Mat a = Mat {mrows :: [[a]]}
instance (Show a) => Show (Mat a) where
show = unlines . map (unwords . map show) . mrows
I have searched on the internet regarding this part Mat {mrows :: [[a]]}
but could not find any helpful answer. Why we can't just declare it as Mat [[a]]
?
Also, how does exactly the last line achieves the above outcome. My apologies if the answer is too obvious, but I literally just started learning Haskell.
Upvotes: 3
Views: 940
Reputation: 15949
It is actually no problem - if you want to you can declare it this way
data Mat a = Mat [[a]]
then you just have to alter the show instance declaration a bit
instance (Show a) => Show (Mat a) where
show (Mat x) = unlines $ map (unwords . map show) x
The other approach has a few upsides:
If you want to get a bit more performance you can change the data
keyword to newtype
.
Moreover if you want to assert that this list of lists contain only lists of the same size - you can not export the constructor Mat
but provide a 'smart' constructor mat :: [[a]] -> Maybe (Mat a)
like:
mat x = if (length $ nub $ map length x) <= 1) then Just x else Nothing
but with the latter approach you can always still extract the [[a]]
part if you export mrows
module Mat (Mat, mrows, mat) where ...
would hide the Mat
construcor, but export the type of Mat
where
module Mat (Mat(..), mat) ...
would export everything
AAAAAnother thing - if you have a type with multiple records say
data Pirate = Pirate { head :: HeadThing
, rightArm :: ArmThing
, leftArm :: ArmThing
, rightLeg :: LegThing
, leftLeg :: LegThing}
data ArmThing = ...
data HeadThing = ...
data LegThing = ...
you can update one (or more "members") with record syntax - i.e.
redBeard :: Pirate
redBeard = blackbeard {head = RedBeard, rightArm = Hook}
Upvotes: 6
Reputation: 62828
data Mat a = Mat {mrows :: [[a]]}
This is Haskell's "record syntax". (That's the term you want to search for.) The above declaration is identical to
data Mat a = Mat [[a]]
The difference is that the second one declares a Mat
constructor with an "unnamed" field of type [[a]]
, which the first one names the field mrows
. In particular, this auto-defines a function
mrows :: Mat a -> [[a]]
that "unwraps" the Mat
constructor. You can also use the name mrows
in patterns, but that's generally more useful for constructors with dozens of fields, not just one.
A named field can always be referred to using unnamed syntax as well, so the named version does everything the unnamed version does plus a bit more.
Upvotes: 2