In your readsMatrix function, you have
readsMatrix ('-':s) = [(Nul, rest) | (' ',rest) <- reads s]
That means after the '-' is consumed, the remainder of the input string is passed to
reads :: ReadS Char
but the Read instance for Char expects a character enclosed in single quotes, like 'h'.
To get an element (' ',rest) in the result, you need - after optional whitespace before it - the character sequence '\'' : ' ' : '\'' : whatever. You don't have those in your expected input. What you want to do there is removing the space after the '-', so if the space is optional, and may be more than one character long,
readsMatrix ('-':s) = [(Nul, dropWhile isSpace s)]
would work (if newlines, tabs etc. are also to be ignored). If you just want one mandatory space, the pattern should be
readsMatrix ('-':' ':s) = [(Nul, s)]
The second equation
readsMatrix s = [(Val x,rest)| (x,' ':rest) <- reads s]
may work as is, but requires that values are followed by a space, so for example readMatrix "3" :: [(Value Int, [Char])] would return an empty list.
I think you'd rather have the space optional there too, so maybe
readsMatrix s = [(Val x, dropWhile isSpace rest) | (x,rest) <- reads s]
is what you want, but since reads ignores leading whitespace for most types,
readsMatrix s = [(Val x, rest) | (x, rest) <- reads s]
may be better.
But you're not ignoring leading whitespace before a '-', so that would need to be done too.
Maybe the implementation would be better done using
lex :: ReadS String
from the Prelude, that splits a string into tokens roughly following the Haskell syntax, e.g.
ghci> lex "(12 + 34) abc"
[("(","12 + 34) abc")]
splits off the opening parenthesis, from the remainder the token "12" would be split off etc.
One possibility using lex, so that leading whitespace is duly ignored would be
readsMatrix s = do
(tok, rest) <- lex s
case tok of
"-" -> return (Nul, rest)
_ -> case reads tok of
[(x,"")] -> return (Val x, rest)
_ -> []
Finally,
read "- 8 - - 3" :: Value Int
would lead to a *** Exception: Prelude.read: no parse even then, because read only succeeds if there is only whitespace following the converted token, but after converting the initial '-' there are still four more convertible tokens in the remainder of the input.
read "- 8 - - 3" :: [Value Int]
on the other hand should succeed.