3

I'm just starting out with Haskell.

What is the problem with this nested where clause?

length' a = fromIntegral (length a)

isPalin1 xs = fstHalf == reverse sndHalf
    where
        fstHalf = take halfLength xs
        sndHalf = drop halfLength xs
            where halfLength = (length' xs) / 2

The error I get: isPalin1.hs:5:32: Not in scope: ‘halfLength’

The below too is wrong, hopefully someone can tall me why:

length' a = fromIntegral (length a)

isPalin2 xs = fstHalf == reverse sndHalf
    where
        let
            halfLength = (length' xs) / 2
        in
            fstHalf = take halfLength xs
            sndHalf = drop halfLength xs

The error message:

isPalin2.hs:7:17:
    parse error (possibly incorrect indentation or mismatched brackets)
2
  • 5
    The second where is scoped to sndHalf - just remove it and the indentation, and you're fine. Commented Apr 11, 2015 at 7:17
  • 3
    While we're at it, this function could be sooo much simpler: isPlalin xs = reverse xs == xs Commented Apr 11, 2015 at 8:11

2 Answers 2

8

where only applies to one binding, so halfLength in your first snippet is only available to sndHalf. You should write this:

length' a = fromIntegral (length a)

isPalin1 xs = fstHalf == reverse sndHalf
    where
        halfLength = (length' xs) / 2
        fstHalf = take halfLength xs
        sndHalf = drop halfLength xs

This is because where is a scope in itself, so bindings may refer to one another.

As for your second snippet, that's altogether incorrect. A let ⋯ in statement is strictly an expression, and cannot be used in a the binding context of where.

If you where to use let ⋯ in, you would use it like this:

length' a = fromIntegral (length a)

isPalin1 xs =
    let halfLength = (length' xs) / 2
        fstHalf = take halfLength xs
        sndHalf = drop halfLength xs
    in  fstHalf == reverse sndHalf
Sign up to request clarification or add additional context in comments.

Comments

5

As was mentioned in the comments, for isPalin1 the where is scoped to sndHalf, and not fstHalf. The way I would re-write the isPalin1 example (syntactically) is as such:

isPalin1 xs = fstHalf == reverse sndHalf
  where length' a = fromIntegral (length a)
        halfLength = (length' xs) / 2
        fstHalf = take halfLength xs
        sndHalf = drop halfLength xs

That won't give you any parse errors, and the scope all works out. However, it won't compile, because your logic for it is off.

The question is why do you need fromIntegral? The answer, from looking at the code, is that you're trying to split a list in a half, and possibly you got a compilation error earlier when trying to do something like (length xs) / 2. It looks like what you're trying to do is split the list in half, but that simply doesn't work for odd-length lists with the given logic. If a list is of length 11, what should fstHalf and sndHalf be? (fromIntrgral (length xs)) / 2 will make halfLength to be 5.5, but you can't take 5.5 elements from a list, so Haskell's type system gets confused

Instead of this, you can use (length xs) `div` 2 to do integer division, discarding the remainder. If xs is length 10, it will return 5. If xs is length 11, it will return 5. I don't want to give you a full solution in case this is a homework problem, but just think about how you can use integer division to make your program work. Think about how lists being even or odd in length would affect the algorithm that determines if they are palindrome, and make your code take that into account.

As for the second error your getting: the reason is because you have two functions, fstHalf and sndHalf that are located in the in clause of a let statement, causing a parse error. In general, I would advise avoiding nesting where and if statements unless you absolutely have to or you're a masochist. One you clear up the logic, try sticking to the format of the example where statement I gave at the start of this post, it makes things a lot simpler.

And don't give up on Haskell, it grows on you. :)

1 Comment

Haskell most definitely grows on you! :-)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.