Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell - How to create a matrix

Given the size of an matrix and a position p. How do I fill the matrix with 1 in p and 0 in other positions?

Ex.: size=(3,3) p=(3,1)

[0 0 0]
[0 0 0]
[1 0 0]

I defined:

type Matrix= [[Int]]
type Pos = (Int,Int)

f:: Pos->Pos->Matrix

The f return for example would be:

 [[0,0,0],[0,0,0],[1,0,0]]

I'm having trouble to start, i.e. in idea how to implement the function f. Can anyone help me?

like image 679
1775 Avatar asked Oct 12 '12 14:10

1775


3 Answers

I like AndrewC's answer, but I'd do it in one go, nesting the list comprehensions and just testing equality for positions, rather than separate rows and columns.

f :: Pos -> Pos -> Matrix
f (h, w) p =  [ [if (y, x) == p then 1 else 0 | x <- [1..w]]
              | y <- [1..h]]

I've chosen my alignment mnemonically so that x stretches horizontally and y stretches vertically, with the heart of the thing being the expression that defines a typical element in terms of its coordinates. The comparison on columns won't happen if the rows are different. I suppose one could use replicate w 0 to compute the all-zero rows slightly more efficiently, at a cost of clarity.

I'd also consider writing

g :: Pos -> Pos -> Matrix
g (h, w) (y, x)  =   replicate (y-1) wzeros
                 ++  (replicate (x-1) 0 ++ 1 : replicate (w-x) 0)
                 :   replicate (h-y) wzeros
  where wzeros = replicate w 0

which is longer, but even more spatially immediate. It preserves more sharing and perhaps does a little less subtraction. But its behaviour is a bit weirder if the position is outside the relevant range.

like image 133
pigworker Avatar answered Sep 28 '22 05:09

pigworker


You could do it by two list comprehensions, one used inside each other:

Break the problem down into two smaller but similar problems:

row b lengthacross = 
   [ --some expression that's 1 if x == b and zero otherwise
         | x <- [1..lengthacross]]

What type would row have?

matrix (a,b) (lendown,lenacross) = 
   [ --a row with a 1 in it or just zeros as appropriate 
        | y <- --an appropriate list
          ]

What type would matrix have?

like image 33
AndrewC Avatar answered Sep 28 '22 06:09

AndrewC


Decompose it.

  1. Write a function of type Pos -> [[Pos]] that takes a size, and gives a "matrix" of that size, but with each element being its own position.

    e.g. ofSize (2,2) = [[(1,1), (1,2)], [(2,1), (2,2)]]

  2. Write a function of type (a -> b) -> [[a]] -> [[b]] that works similarly to map. (Clue: the definition features map. Twice.)

You can then assemble these pieces into a function that starts by generating a "matrix" of positions, then maps that into the desired result.

like image 45
dave4420 Avatar answered Sep 28 '22 05:09

dave4420