icyrock.com

Home

PureScript experiments - matrices

2017-Mar-31 20:34
purescript-experimentspurescript

Here is a small module that can be used for representing matrices.

To start, this module depends on Ex.String module for padLeft:

1
2
3
4
5
6
7
8
module Ex.String where
 
import Prelude
import Data.Array (replicate)
import Data.String (fromCharArray, length)
 
padLeft :: Char -> Int -> String -> String
padLeft c l s = fromCharArray (replicate (l - length s) c) <> s

Let us look at Ex.Mat module itself. These are the imports we will use:

1
2
3
4
5
6
7
8
9
10
module Ex.Mat where
 
import Prelude
import Data.Array (foldM, replicate, updateAt, (!!))
import Data.Maybe (Maybe, fromJust)
import Data.String (joinWith)
import Data.Tuple (Tuple(..))
import Partial.Unsafe (unsafePartial)
 
import Ex.String (padLeft)

Types of matrix, dimension and cell point, with Show instances:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
newtype Mat a = Mat (Array (Array a))
 
instance showMat :: Show a => Show (Mat a) where
  show (Mat m) = joinWith "\n" (map (srow >>> joinWith " ") m)
    where srow = map (show >>> padLeft ' ' 3)
 
newtype Dim = Dim { w :: Int
                  , h :: Int
                  }
 
instance showDim :: Show Dim where
  show (Dim {w, h}) = "[" <> show w <> "x" <> show h <> "]"
 
newtype Pt = Pt { x :: Int
                , y :: Int
                }
 
instance showPt :: Show Pt where
  show (Pt {x, y}) = "(" <> show x <> "," <> show y <> ")"

A few useful functions:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
makeMat :: forall a. Dim -> a -> Mat a
makeMat (Dim {w, h}) v = Mat $ replicate h row
  where row = replicate w v
 
putAt :: forall a. Pt -> a -> Mat a -> Maybe (Mat a)
putAt (Pt {x, y}) v (Mat m) = do
  r <- m !! y
  nr <- updateAt x v r
  nm <- updateAt y nr m
  pure $ Mat nm
 
putMany :: forall a. Array (Tuple Pt a) -> Mat a -> Maybe (Mat a)
putMany ps m = foldM f m ps
  where f a (Tuple p v) = putAt p v a

Finally, a couple of usage examples:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
p1 :: Mat Int
p1 = makeMat (Dim {w: 4, h: 3}) 0
 
p2m :: Maybe (Mat Int)
p2m = putMany [ Tuple (Pt {x: 0, y: 0}) 1
              , Tuple (Pt {x: 1, y: 0}) 2
              , Tuple (Pt {x: 2, y: 0}) 3
              , Tuple (Pt {x: 3, y: 0}) 4
              , Tuple (Pt {x: 3, y: 1}) 5
              , Tuple (Pt {x: 3, y: 2}) 6
              , Tuple (Pt {x: 2, y: 2}) 7
              , Tuple (Pt {x: 1, y: 2}) 8
              , Tuple (Pt {x: 0, y: 2}) 9
              , Tuple (Pt {x: 0, y: 1}) 10
              , Tuple (Pt {x: 1, y: 1}) 11
              , Tuple (Pt {x: 2, y: 1}) 12
              ]
              p1
 
p2 :: Mat Int
p2 = unsafePartial fromJust p2m

Creating a matrix with certain dimensions and same value in all cells:

1
2
3
4
5
> import Ex.Mat
> p1
  0   0   0   0
  0   0   0   0
  0   0   0   0

Creating a matrix from (point, value) tuples:

1
2
3
4
5
> import Ex.Mat
> p2
  1   2   3   4
 10  11  12   5
  9   8   7   6