0

While learning Haskell, I've to do a function to return all whole numbers divisors of a given number. So, I've created it using two nested where clauses, but it doesn't work.

Error returned: exs2.hs:49:24: Parse error in pattern: negRef / 2

divisors' :: (Integral a) => a -> [a]
divisors' x = divs x (x/2) [x]
  where
    divs ref 1 list = negDiv (-ref) (-2) ((-1):1:list)
    divs ref num list = if (mod ref num == 0) then divs ref (num-1) (num:list) else divs ref (num-1) list
      where
        negDiv negRef (negRef/2) negList = (negRef:(negRef/2):negList)
        negDiv negRef negNum negList = if (mod negRef negNum == 0) then negDiv (negNum-1) (negNum:negList) else negDiv (negNum-1) negList

What's the wrong thing then? It seems to be well indented.

4
  • 4
    negRef/2 is not a valid pattern. Commented Aug 24, 2016 at 8:47
  • 3
    The inner where clause is in scope for only the second line in the definition of divs. When the first line of divs calls negDiv, the inner where clause is not in scope. That and the pattern thing. Commented Aug 24, 2016 at 8:55
  • Then how could I correctly write that division pattern? @MathematicalOrchid Commented Aug 24, 2016 at 11:33
  • 1
    @flamenquino You can't; you need to use a guard: negDiv x y negList | x == y/2 = (x:y:negList) Other cases are specified as additional guards, since the patterns x and y will match anything. Commented Aug 24, 2016 at 12:15

3 Answers 3

4

Your second where-clause doesn't use any name from the divs scope. You can just use one single clause like so:

divisors' :: (Integral a) => a -> [a]
divisors' x = divs x (x/2) [x]
  where
    divs ref 1 list = negDiv (-ref) (-2) ((-1):1:list)
    divs ref num list = if (mod ref num == 0) then divs ref (num-1) (num:list) else divs ref (num-1) list
    negDiv negRef (negRef/2) negList = (negRef:(negRef/2):negList)
    negDiv negRef negNum negList = if (mod negRef negNum == 0) then negDiv (negNum-1) (negNum:negList) else negDiv (negNum-1) negList

If you really want to express your function with nested clauses, you can use let ... in.

But in this case this is not useful, I recommend using the where clause (which is often preferred to let ... in, considered to be less idiomatic in most cases).

The reason why it is not working is that the clause is attached to the second equation of divs, not the first one which uses negDiv.

PS: As MathematicalOrchid said, negRef/2 is not a valid pattern, that is where your error comes from.

Sign up to request clarification or add additional context in comments.

1 Comment

Sometimes where is preferable to let, sometimes it's the other way around. I don't think one is more idiomatic than the other. See stackoverflow.com/questions/4362328/haskell-where-vs-let for example.
2

Another issue is that the / operator doesn't work on integers. In Haskell, / is the division operator for fields, and as such requires a Fractional type such as Rational or Double.

For integer division you should instead use div or quot.

1 Comment

I've done it before, using div, but it returned me the same error.
1

You have several problems:

  1. You can only pattern match on literals and data constructors, not arbitrary functions like /.
  2. / is only defined for Fractional a values, not Integral. Use div instead.
  3. You definitions of negDiv are missing an argument in the recursive calls. It's not clear what the arguments should be, though.

A mostly corrected version:

divisors' :: (Integral a) => a -> [a]
divisors' x = divs x (x `div` 2) [x]
  where
    divs ref 1 list = negDiv (-ref) (-2) ((-1):1:list)
    divs ref num list | ref `mod` num == 0 = divs ref (num-1) (num:list) 
                      | otherwise          = divs ref (num-1) list
    -- Three arguments, but only two given to each recursive call
    negDiv x y negList | x == negRef `div` 2 = x:y:negList
                       | x `mod` y == 0      = negDiv (y-1) (y:negList)
                       | otherwise           = negDiv (y-1) negList

By the way, this is much more simply done with

divisors' x = ds ++ (map negate ds)               -- positive and negative ds
              where ds = filter (divs x) [1..x]   -- d such that d divides x
                    x `divs` y = x `mod` y == 0   -- Does y divide x?

or even

divisors' x = [d | d <- [(-x)..x], d /= 0, x `mod` d == 0]

Anytime you find yourself writing recursive functions to iterate over a list, you are probably overlooking the correct higher-order function or list comprehension.

Comments

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.