0
votes

This portion of code checks if a number given (First element in a list) is zero (yes i tried == 0 but got other errors) It then return all elements of another list except the first one. If not, it returns another list. The function is of type [a] and 'newpack' needs to be a variable as it is used later.

                              if ((position!!1) < 1)
                                then 
                                    let newpack =   drop ((length pack)-1) pack
                                else
                                    let newpack = (take ((position!!1)-1) pack) ++ (drop ((position!!1)+1) pack)

error is 46:73: parse error on input `else'

Do have any idea why this is not working? Is it that'let's needs an 'in' with them?

Thanks for your help,

J

2
Note: position !! 1 yields the second element of the list position (or a runtime error, if it is too short). Indices are 0-based. - Daniel Fischer
If you come from a C-style language, just train yourself to exchange every Haskell if a then b else c with a? b : c in your mind. What imperative languages call if is when in Haskell (not available by default, you have to import Control.Monad), but you can't use that in this way either. - leftaroundabout

2 Answers

4
votes

Yes, the in part is not optional. You can write this as:

let newpack = if (position !! 1) < 1
                then drop ((length pack)-1) pack
                else (take ((position!!1)-1) pack) ++ (drop ((position!!1)+1) pack)
in ...rest of code...

If you're in a do block, then you can omit in onwards, but either way, you can't put the conditional outside the binding.

(If you're hoping to modify newpack as if it was a mutable variable, that's just not possible; all let does is give a name to a value, you can't actually modify anything. But how to structure your code without this would be beyond the scope of this question; if you need help with that, you should ask another.)

Some stylistic notes:

  • Explicit list indexing is generally considered a bad idea; depending on what it's used for, you might want to consider making position a tuple or some other data structure.

  • Similarly, length is probably a bad idea too (it has to traverse the entire list just to give a result).

  • You have a lot of redundant parentheses: drop ((length pack)-1) can be simply drop (length pack - 1).

A nicer way to write this (from a purely aesthetic point of view — i.e. ignoring the list indexing and use of length) would be (using guards):

let firstPos = position !! 1
    newPack
      | firstPos == 0 = drop (length pack - 1) pack
      | otherwise     = take (firstPos - 1) pack ++ drop (firstPos + 1) pack
in ...
2
votes

Is it that 'let's needs an 'in' with them?

Yes. (do-blocks are a special case; however, even in a do-block, the rest of the block is a bit like being in an implicit in.) You might consider writing something like this:

let newpack = if {- ... -} then {- ... -} else {- ... -} in
{- the rest of your computation that uses newpack -}