Im having an error with Haskell with cases that i cant find

696 Views Asked by At

So im trying to create this function AgregarMon that basically adds a "Monomio" to "Polinomio" Monomio would end up being an element inside Polinomio which is a list. You are going to understand better in a little bit

type Monomio = (Int, Int)
type Polinomio = [Monomio]

agregarMon :: Monomio -> Polinomio -> Polinomio
agregarMon = \m p -> case m of{ (0,0) -> p;
                                 x -> case p of{[] -> [x];
                                                y:ys -> case (snd x == snd y) of { true -> case ((fst x + fst y)==0) of { true -> ys;
                                                                                                                          false -> (fst x + fst y , snd x):ys;}
                                                                                   false -> case snd x < snd y of{true -> y: agregarMon x ys;
                                                                                                                  false -> x:y:ys;}}}}

I've been looking at my code like an hour, and i cant find the problem. The error says:

Polinomios.hs:45:140: error:
    Unexpected case expression in function application:
        case ((fst x + fst y) == 0) of
          true -> ys
          false -> (fst x + fst y, snd x) : ys
    You could write it with parentheses
    Or perhaps you meant to enable BlockArguments?
   |
45 |                                                                                                 y:ys -> case (snd x == snd y) of { true -> case ((fst x + fst y)==0) of { true -> ys;    |                                                                                                                                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^...

Line 45 is the fourth line on the code from above. Im sorry if im missing info, please let me now. Just in case, someone doesnt knows, fst and snd are on the Prelude. fst takes the first element from a "Monomio" snd the second one. fst = (a,b)->a snd (a,b) -> b

3

There are 3 best solutions below

2
chi On BEST ANSWER
case (snd x == snd y) of { true ->

is wrong: true here is just a variable name, unrelated to the constructor True (with a capital T!). The snippet above is therefore equivalent to

case (snd x == snd y) of { x ->

Hence, the pattern matches any boolean value, True and False. For that reason the other branch false -> ... will never be considered.

I recommend you turn on warnings, since doing so makes GHC report the second branch as redundant code. The fact that the compiler considers a branch useless signals that something is very wrong with the code.

As a final note, in my experience code like

case something of
  True  -> a
  False -> b

is not common, since we can write it as

if something
then a
else b

which is easier to read, in my view.

0
Mark Seemann On

While you can, in a pinch, use curly brackets and semicolons, Haskell isn't a C-based language. It idiomatically uses indentation to indicate function scope.

Something like this would be more idiomatic:

agregarMon :: Monomio -> Polinomio -> Polinomio
agregarMon = \m p -> case m of
                      (0,0) -> p
                      x -> case p of
                            [] -> [x]
                            y:ys -> case (snd x == snd y) of
                                      true -> case ((fst x + fst y)==0) of
                                                true -> ys
                                                false -> (fst x + fst y , snd x):ys
                                      false -> case snd x < snd y of
                                                true -> y: agregarMon x ys
                                                false -> x:y:ys

This compiles (although with warnings, see below), but I don't know if it does what you want it to do. The OP code doesn't compile, so clearly something that does compile isn't equivalent.

All I did, however, was to remove all the curly brackets and semicolons, and instead 'fix' the indentation.

The code is still, in my opinion, too indented, but at least (with one exception) it stays left of 80 characters. Wide code could force people to scroll horizontally, which isn't going to make you many friends.

The above code loads in GHCi, but with warnings:

[1 of 1] Compiling Q58986486        ( 58986486.hs, interpreted )

58986486.hs:14:49: warning: [-Woverlapping-patterns]
    Pattern match is redundant
    In a case alternative: false -> ...
   |
14 |                                                 false -> (fst x + fst y , snd x):ys
   |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

58986486.hs:15:39: warning: [-Woverlapping-patterns]
    Pattern match is redundant
    In a case alternative: false -> ...
   |
15 |                                       false -> case snd x < snd y of
   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^...

58986486.hs:17:49: warning: [-Woverlapping-patterns]
    Pattern match is redundant
    In a case alternative: false -> ...
   |
17 |                                                 false -> x:y:ys
   |                                                 ^^^^^^^^^^^^^^^
Ok, one module loaded.

Thus, I'm not sure that it works as intended.

0
Yuri Kovalenko On

The version of Mark Seemann can be improved though.

Firstly, let's make m and p actual arguments of agregarMon:

agregarMon :: Monomio -> Polinomio -> Polinomio
agregarMon m p = case m of
                      (0,0) -> p
                      x -> case p of
                            [] -> [x]
                            y:ys -> case (snd x == snd y) of
                                      true -> case ((fst x + fst y)==0) of
                                                true -> ys
                                                false -> (fst x + fst y , snd x):ys
                                      false -> case snd x < snd y of
                                                true -> y: agregarMon x ys
                                                false -> x:y:ys

Now we can use pattern matching on agruments to simplify code:

agregarMon :: Monomio -> Polinomio -> Polinomio
agregarMon (0, 0) p = p
agregarMon x [] = [x]
agregarMon (f, s) (y:ys) = case (snd x == snd y) of
                            true -> case ((fst x + fst y)==0) of
                                         true -> ys
                                         false -> (fst x + fst y , snd x):ys
                            false -> case snd x < snd y of
                                          true -> y: agregarMon x ys
                                          false -> x:y:ys

It is not so idiomatic to pattern-match with case a result of condition check, better use if or guards:

agregarMon :: Monomio -> Polinomio -> Polinomio
agregarMon (0, 0) p = p
agregarMon x [] = [x]
agregarMon x@(coefx, powx) (y@(coefy, powy):ys)
  | powx == powy = if coefx + coefy == 0
                   then ys
                   else (coefx + coefy, powx):ys
  | powx < powy = y:agregarMon x ys
  | otherwise = x:y:ys

Now we have some simple cases and a complex one, but even the complex one is not so hard to read and understand (I even made an assumption that you're working with polynomials, coefficients and powers).

You can run it there: https://repl.it/@Yuri12358/so-monomio-polinomio

Maybe this link will help you to improve your understanding of different ways to make branching in your code: http://learnyouahaskell.com/syntax-in-functions#pattern-matching