2016-08-24 2 views
0

При изучении Haskell я должен выполнить функцию, чтобы возвращать все целые числа чисел заданного числа. Итак, я создал его, используя два вложенных предложения where, но это не сработает.Использование вложенных предложений `where` в Haskell

Ошибка возвращается: 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 

Что неправильно, что тогда? Кажется, он хорошо отстут.

+4

'negRef/2' неправильный шаблон. – MathematicalOrchid

+3

Предложение inner where доступно только для второй строки в определении div. Когда первая строка divs вызывает negDiv, предложение inner where не имеет значения. Это и образец. – pigworker

+0

Тогда как я мог правильно написать этот шаблон разделения? @MathematicsOrchid – fant0me

ответ

2

Ваш второй where -clause не использует никаких имен из области divs. Вы можете просто использовать один единственный пункт, как так:

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 

Если вы действительно хотите, чтобы выразить свою функцию с вложенными пунктами, вы можете использовать let ... in.

Но в этом случае это не полезно, я рекомендую использовать пункт where (который часто предпочитается let ... in, который в большинстве случаев считается менее идиоматичным).

Причина, по которой она не работает, заключается в том, что предложение привязано ко второму уравнению divs, а не к первому, которое использует negDiv.

PS: В качестве MathematicalOrchid said, negRef/2 недействительный шаблон, вот откуда исходит ваша ошибка.

+0

Иногда 'where' предпочтительнее' let', иногда это наоборот. Я не думаю, что человек более идиоматичен, чем другой. Например, http://stackoverflow.com/questions/4362328/haskell-where-vs-let. –

2

Другая проблема заключается в том, что оператор / не работает с целыми числами. В Haskell / является оператором деления полей, и для этого требуется тип Fractional, такой как Rational или Double.

Для целое число подразделение вы должны использовать div or quot.

+0

Я делал это раньше, используя 'div', но он возвратил мне ту же ошибку. – fant0me

1

У вас есть несколько проблем:

  1. Вы можете только шаблон матч на литералах и конструкторах данных, а не произвольные функции, такие как /.
  2. / определен только для Fractional a значений, а не Integral. Вместо этого используйте div.
  3. В определениях negDiv отсутствуют аргументы в рекурсивных вызовах. Однако неясно, какие аргументы должны быть.

основном исправленная версия:

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 

Кстати, это гораздо проще сделать с

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? 

или даже

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

В любое время вы обнаруживаете, что пишете рекурсивные функции для перебора списка, вы, вероятно, не замечаете правильную функцию более высокого порядка или понимание списка.