Lists of lists are not optimal for dealing with matrices in SML, but it is still a good exercise to write a function for checking if a list of lists is an identity matrix.
A recursive approach is natural. In the following picture:

Note that:
- The first element of the first row is a 1
- The rest of that row is all 0
- The rest of the first column is all 0
- The rest of the matrix (below and to the right of the shaded region) is itself an identity matrix.
As a preliminary, write a function which tests if a list is all 0. You could use the standard basis function all
to do so, though it is easy enough to roll your own:
fun all_zeros [] = true
| all_zeros (x::xs) = x = 0 andalso all_zeros xs
The main function checks the 4 points given above. Some care must be given to various basis cases. The empty list is not an identity matrix. Nor is a list of empty lists. This last case is easy to overlook, but if you pass the function a matrix which has more rows than columns you run out of columns before rows. I am mapping hd
across the bottom rows to extract the rest of column 1 (below the element in the upper left) and am mapping tl
across the bottom rows to get the lower right part of the matrix to feed back into the function recursively. This might produce a nonempty lists of empty lists, so that must be checked:
fun id_matrix [] = false
| id_matrix (row::[]) = (row = [1])
| id_matrix ([]::rows) = false
| id_matrix (row::rows) =
let
val x :: xs = row
in
x = 1 andalso
all_zeros(xs) andalso
all_zeros(map hd rows) andalso
id_matrix(map tl rows)
end
As a final remark -- my code assumes that the lists of lists represents a valid array and merely checks if it is the identity. Passing it a jagged array rather than a matrix could crash it. It would be easy enough to add a check, though it would make the code more cumbersome.