John Stef
John Stef

Reputation: 595

Show matrix function in haskell

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

Answers (2)

epsilonhalbe
epsilonhalbe

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

Edit

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

Edit2

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

MathematicalOrchid
MathematicalOrchid

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

Related Questions