5

haskell, is it possible to debug an analysis error?

 2 years ago
source link: https://www.codesd.com/item/haskell-is-it-possible-to-debug-an-analysis-error.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

haskell, is it possible to debug an analysis error?

advertisements

I am working through some exercises I found accompanying a set of lectures online and have come across a problem I cannot overcome, essentially, I have a function defined in a file as

doubleEveryOtherHelper :: [Integer] -> Int ->  [Integer]
doubleEveryOtherHelper ((x:x1:xs) len)
    | len > 2   = x : 2*x1 : doubleEveryOtherHelper(xs (len - 1))
    | len == 2 = x : 2*x1
    | len == 1 = [2*x]
    | otherwise = []

and upon loading the file I get this(and only this):

Parse error in pattern: (x : x1 : xs)

Regardless of what the function may or may not do if I ever managed to load it, is there any way of getting ghci to tell me everything it was trying to parse in human readable form so that I can figure out these things for myself (i.e. if I can see what it was actually trying to parse (presumably garbage), as opposed to what I think it was trying to parse (a function name and two arguments: a list and an Int, and then the list to return dependent on the value of len) then fixing it should be a lot easier)?

All I know right now is that it is wrong ... for some reason (and even if some kind person tells me what was my mistake in this instance, I don't want to be stumped again by ever so slightly different problems in the future.)


As far as I know, there's no way to coerce GHCI to give you more information than that (although I'm admittedly not a very experienced GHCI user). Haskell errors can be very cryptic, but the ability to recognize and understand them will come with time and experience. In the meantime, I can give you a few tips on understanding and fixing that error:

  • Parse error This means that GHCI was unable to understand the lexicographic structure of your code, regardless of what the code you wrote was supposed to do. Common causes of parse errors include inconsistent indentation and mismatched delimiters, such as an extra or missing closing ). This lets you know that there is a problem with the top-level syntax you are using, specifically:

  • in pattern: Since you're using it in your code, I presume that you are familiar with pattern matching. This lets us know that there is a problem with the syntax you are using in a pattern expression. Specifically, around this one:

  • (x : x1 : xs) This is a valid pattern for matching a list of two or more elements. We know that this structure caused an error, but since it's valid in and of itself, we can conclude that this pattern caused a parse error because of the context in which it was used.

Widening our field of vision to look at the whole pattern, we spy an extraneous pair of parentheses surrounding the pattern that is throwing off the parser:

(   (x:x1:xs) len   ) --These should not be here

Since (x:x1:xs) and len are not part of the same data structure, they should not be placed together in parentheses (Haskell is different in this from many languages where all arguments in a function call are surrounded together by parentheses). Removing these parentheses fixes the parse error...

doubleEveryOtherHelper :: [Integer] -> Int ->  [Integer]
doubleEveryOtherHelper (x:x1:xs) len
    | len > 2   = x : 2*x1 : doubleEveryOtherHelper(xs (len - 1))
    | len == 2 = x : 2*x1
    | len == 1 = [2*x]
    | otherwise = []

...but reveals a plethora of other errors sprinkled throughout our now lexicographically (but not logically correct function. Happy debugging!

Edit: seemed like a dick move to leave all those new errors there for you, so I fixed them. Here's a function that will compile correctly (although I haven't tested to see if it actually works or not):

doubleEveryOtherHelper :: [Integer] -> Int ->  [Integer]
doubleEveryOtherHelper (x:x1:xs) len --no parens around pattern
    --fixed parens to account for operator precedence
    | len > 2   = x : (2*x1) : (doubleEveryOtherHelper xs (len - 1)) --removed parens around call to doubleEveryOtherHelper, same error as before
    | len == 2 = x : [2*x1]
    | len == 1 = [2*x]
    | otherwise = []

Note that lines 3 and 4 can be written much more clearly:

 | len > 2  = [x, 2*x1] ++ doubleEveryOtherHelper xs (len - 1)
 | len == 2 = [x, 2*x1]

Tags haskell

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK