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.

fant0me
  • 201
  • 1
  • 3
  • 15
  • 4
    `negRef/2` is not a valid pattern. – MathematicalOrchid Aug 24 '16 at 08: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. – pigworker Aug 24 '16 at 08:55
  • Then how could I correctly write that division pattern? @MathematicalOrchid – fant0me Aug 24 '16 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. – chepner Aug 24 '16 at 12:15

3 Answers3

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.

Community
  • 1
  • 1
baxbaxwalanuksiwe
  • 1,474
  • 10
  • 20
  • 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 http://stackoverflow.com/questions/4362328/haskell-where-vs-let for example. – Taylor Fausak Aug 25 '16 at 15:10
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.

Community
  • 1
  • 1
Lambda Fairy
  • 13,814
  • 7
  • 42
  • 68
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.

chepner
  • 497,756
  • 71
  • 530
  • 681