iIllumination
iIllumination

Reputation: 77

Haskell - Syntax error

Can someone please tell me what is wrong here? I can't figure out where the error is. I'm new to haskell, so I don't know every rule of syntax atm.

parseS (s:xs) | all isDigit s = (xs, Lit (read s)) 
          | s == " " = parseS xs
          | s == "-" = let (remainder, e) = parseS xs in (remainder, Sub e)
          | s == "+" = (xs'', Sum e e') where
                       (xs', e) = parseS xs 
                       (xs'', e') = parseS xs' 

          | s == "*" = (xs'', Mul e e') where     <- parse error on input on this line
                       (xs', e) = parseS xs 
                       (xs'', e') = parseS xs'  

Upvotes: 2

Views: 118

Answers (2)

melpomene
melpomene

Reputation: 85887

This is how Haskell sees your code:

parseS (s:xs)
        | all isDigit s = (xs, Lit (read s)) 
        | s == " " = parseS xs
        | s == "-" = let (remainder, e) = parseS xs in (remainder, Sub e)
        | s == "+" = (xs'', Sum e e')
    where
    (xs', e) = parseS xs 
    (xs'', e') = parseS xs' 

| s == "*" = (xs'', Mul e e')
    where
    (xs', e) = parseS xs 
    (xs'', e') = parseS xs'

A where block attaches to a declaration, which in your case is the whole parseS definition.

The next line starting with | is seen as the start of a new declaration, which is invalid because you can't start a declaration with |.

The easiest fix is to stop using where for local bindings and use let instead, like this:

          | s == "+" =
              let
                  (xs', e) = parseS xs 
                  (xs'', e') = parseS xs' 
              in
              (xs'', Sum e e')

          | s == "*" =
              let
                  (xs', e) = parseS xs 
                  (xs'', e') = parseS xs'
              in
              (xs'', Mul e e')

Upvotes: 2

rampion
rampion

Reputation: 89123

The problem is that the first where clause is taken as the end of the definition for parseS (s:xs). You're trying to add another guarded case afterwards, but the parser doesn't see it as attached to the same definition.

There's several ways you could fix this.

You could fix this by using a let ... in instead for s == "+"

      | s == "+" = let (xs', e) = parseS xs
                       (xs'', e') = parseS xs
                   in (xs'', Sum e e')
      | s == "*" = (xs'', Mul e e') where
                       (xs', e) = parseS xs 
                       (xs'', e') = parseS xs'  

But there's an easier way to do it - just drop that where clause.

      | s == "+" = (xs'', Sum e e')
      | s == "*" = (xs'', Mul e e') where
                       (xs', e) = parseS xs 
                       (xs'', e') = parseS xs'  

The variables defined in a where clause are in scope for the entirety of a definition (for all guard cases), so your definition of xs'' can be reused for both cases.

Upvotes: 3

Related Questions