2

I'm solving some problem on https://wiki.haskell.org/99_questions/1_to_10.

I attempts to implements a second solution to problem 3 using guards. My goals is to wrap a guard in order to implement error manangement.

The code is this:

elementAt' :: [a] -> Int -> a 
elementAt' xs k = if k < 1 || k > length xs then error "IndexOutOfbound" else elem xs K
    where elem xs k
        | k == 1 = x
        | k > 1  = elem (tail xs) k

The error is this:

   parse error (possibly incorrect indentation or mismatched brackets)
   |
11 |         | k == 1 = x
   |         ^

I tried to work with indentation, but I didn't succeed

Stoic Lion
  • 470
  • 2
  • 14
  • 2
    The indentation is incorrect, you need to move it at least one space more to the right than the start of `elem`. – Willem Van Onsem May 18 '20 at 10:57
  • There was other errors, but now it works. – Stoic Lion May 18 '20 at 11:07
  • 1
    You might want to read a [short summary of the indentation rules](https://stackoverflow.com/questions/33004521/what-indentation-is-required-for-a-case-statement-within-a-let-statement/33010779#33010779). – chi May 18 '20 at 11:30

1 Answers1

3

The indentation is indeed wrong, you need to move it at least one column more to the right than the start of elem, so:

elementAt' :: [a] -> Int -> a 
elementAt' xs k = if k < 1 || k > length xs then error "IndexOutOfbound" else elem xs K
    where elem xs k
           | k == 1 = x
           | k > 1  = elem (tail xs) k

But this is not sufficient to make this compile. You furthermore wrote K instead of k at the definition of elementAt' xs k = …, furthermore x is not defined, so you can use head, finally you should decrement k in the recursive call:

elementAt' :: [a] -> Int -> a 
elementAt' xs k = if k < 1 || k > length xs then error "IndexOutOfbound" else elem xs k
    where elem xs k
           | k == 1 = head xs
           | k > 1  = elem (tail xs) (k-1)

Now it compiles but still it is not very idiomatic Haskell. You make use of length for example, which runs in linear time with the length of the list. If the list has infinite length, it will get stuck, furthermore you make use of head and tail, and these are non-total functions. Yes, we know that this will always work on a cons, since otherwise k > length would be triggered, but regardless it is often batter to use pattern matching over non-total functions.

Therefore a more idiomatic approach is likely:

elementAt' :: [a] -> Int -> a
elementAt' xs k
    | k < 1 = error "IndexOutOfBound"
    | otherwise = go xs k
    where go [] _ = error "IndexOutOfBound"
          go (x:xs) i
              | i <= 1 = x
              | otherwise = go xs (i-1)

Here we know that k is larger than the length if the list is exhausted, so in the go [] case.

Of course indexing should start at zero, as is documented in EWD831 :).

Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
  • You writed this answer with all errors and idiomatic problems meanwhile I fixed my code after your comment. This is a very complete answer. Thanks a lot. – Stoic Lion May 18 '20 at 11:18