Crazy Psychild
Crazy Psychild

Reputation: 592

Not in scope error

I am writing a simple program to find whether a given list is a matrix or not:

is_matrix :: [[a]] -> Bool
is_matrix [[]] = False
is_matrix (x:xs)
  | x == [] = is_matrix xs
  | x == [a] = True
  | length x == length (head xs) = is_matrix xs
  | otherwise = False

But when i compile the is_matrix.hs file it produces the following error:

Prelude> :load is_matrix.hs
[1 of 1] Compiling Main             ( is_matrix.hs, interpreted )

is_matrix.hs:5:11: Not in scope: `a'
Failed, modules loaded: none.
Prelude>

I have no idea as to why is this happening?

Upvotes: 2

Views: 3032

Answers (2)

awesoon
awesoon

Reputation: 33651

I am not exactly sure, what are you trying to check with the expression x == [a], since [a] is a type "list of a's". Let's try to implement the function, using the matrix definition from Wiki:

A matrix is a rectangular array of numbers or other mathematical objects, for which operations such as addition and multiplication are defined.

So, all we need to check is that all rows in the matrix has the same size. Note, also, that there is a case for, so called, empty matrix:

In some contexts, such as computer algebra programs, it is useful to consider a matrix with no rows or no columns, called an empty matrix.

is_matrix :: [[a]] -> Bool
-- Note, I removed the is_matrix [[]] = False condition
is_matrix (x:xs)
  | null xs                      = True         -- There are no more rows in sub-matrix - the answer is True
  | length x == length (head xs) = is_matrix xs -- The same as in your version
  | otherwise                    = False        -- The same as in your version

This function produces the following output:

*Main> is_matrix [[]]
True
*Main> is_matrix [[1, 2, 3], [4, 5, 6]]
True
*Main> is_matrix [[1, 2, 3], [7], [4, 5, 6]]

This function could also be implemented in more natural way using map function (the question about implementation of allTheSame function):

*Main> let allTheSame xs = all (== head xs) (tail xs)
*Main> let isMatrix = allTheSame . map length  
*Main> isMatrix [[]]
True
*Main> isMatrix [[1, 2, 3], [4, 5, 6]]
True
*Main> isMatrix [[1, 2, 3], [7], [4, 5, 6]]
False

Upvotes: 2

Daniel Perez
Daniel Perez

Reputation: 6903

a is not a variable, it is a type in your definition, so you cannot write x == [a]. I suppose you want to check if x is a single element list. If so you could write the conditions like this

is_matrix :: [[a]] -> Bool
is_matrix [[]] = False
is_matrix ([]:xs) = is_matrix xs
is_matrix ([x]:xs) = True
is_matrix (x:xs)
  | length x == length (head xs) = is_matrix xs
  | otherwise = False

Note that when you use | for the conditions, the variables in the scope are used, new variables are not bound. On the opposite, when using function pattern matching, variables on the left hand side are bound to their match.

By the way, Haskell usually uses camelCase rather than snake_case.

Upvotes: 3

Related Questions