[Haskell-beginners] Indentation of local functions
Daniel Fischer
daniel.is.fischer at web.de
Mon Feb 16 11:05:19 EST 2009
Am Montag, 16. Februar 2009 16:32 schrieb Miguel Pignatelli:
> Hi all,
>
> This is my first post in this forum, I'm pretty new to Haskell
> (although I have some previous experience in functional programming
> with OCaml).
>
> I'm trying to write the typical function that determines if a list is
> a palindrome.
> The typical answer would be something like:
>
> isPalindrome xs = xs == (reverse xs)
>
> But I find this pretty inefficient (duplication of the list and double
> of needed comparisons).
> So I tried my own version using just indexes:
>
> isPalindrome xs =
> isPalindrome' 0 (length xs)
> where isPalindrome' i j =
> if i == j -- line 43
> then True
> else
> if (xs !! i) == (xs !! (j-1))
> then isPalindrome' (i+1) (j-1)
> else False
>
> But, when trying to load this in ghci it throws the following error:
>
> xxx.hs:43:12: parse error (possibly incorrect indentation)
> Failed, modules loaded: none.
> (Line 43 is marked in the code)
>
> I seems that the definition of isPalindrome' must be in one line. So,
> this works as expected:
>
> isPalindrome xs =
> isPalindrome' 0 (length xs)
> where isPalindrome' i j = if i == j then True else if (xs !! i)
> == (xs !! (j-1)) then isPalindrome' (i+1) (j-1) else False
>
> Is there any way to make the local definition of isPalindrome' more
> readable?
>
Yes, it would be horrible to look at Haskell code if there weren't.
The problem is that originally, the code for isPalindrome' was indented less
than the function name. Specifically, the first relevant token (i.e. not
whitespace or comments) after the keywords do, let, where, case ... of
opens up a new scope, which lasts until something is indented less or equally
far.
To not suffer from e-mailing programmes behaviour regarding leading spaces on
a line, I replace those with '°', then a more readable formatting of your
code would be
isPalindrome xs = isPalindrome' 0 (length xs)
°°°where
°°°°°°isPalindrome' i j
°°°°°°°°°| j <= i = True
°°°°°°°°°| xs !! i /= xs !! (j-1) = False
°°°°°°°°°| otherwise = isPalindrome (i+1) (j-1)
I have replaced your nested ifs by guards (increases readability, IMO) and
corrected the stopping condition so that it also works on words of odd
length.
However, note that Haskell lists aren't arrays, but singly linked lists, so to
find xs !! k, all the first (k+1) cells of the list must be visited, making
your algorithm less efficient than the naive one, since you must visit
O((length xs)^2) cells.
> Any help in understanding this would be appreciated
>
> Thanks in advance,
>
> M;
Cheers,
Daniel
More information about the Beginners
mailing list