2015-12-29 2 views
3

Я новичок в Haskell. Я пытался решить диофантовое уравнение | x^y-y^x | является простым, используя Haskell, для заданной верхней границы x, y < n.Почему следующий код Haskell висит?

Итак, я написал этот Haskell код:

-- list of primes 
listprimesupto :: Integral a => a -> [a] 
listprimesupto 1 = [] 
listprimesupto 2 = [2] 
listprimesupto n = let halflstprimes = (listprimesupto (n `div` 2)) 
        in halflstprimes++[i|i<-[((n `div` 2)+1)..n], (length [x|x<-halflstprimes, (i `mod` x) == 0])==0 ] 

-- is prime? 
is_prime :: Integral a => a -> Bool 
is_prime 1 = False 
is_prime n = let halflstprimes = (listprimesupto (n `div` 2)) 
      in (length [x|x<-halflstprimes, (n `mod` x) == 0])==0   

-- solve |x^y - y^x| == prime 
xy_yx_p :: Integral t => t -> [(t, t)] 
--xy_yx_p n = [(x,y)|x<-[2..n], y<-[2..n], x < y, (abs (x^y-y^x)) `elem` (listprimesupto (n^3))] -- version 1, works but upper limit too small 
xy_yx_p n = [(x,y)|x<-[2..n], y<-[2..n], x < y, (let t=abs (x^y-y^x) in is_prime t)==True] -- version 2, hangs for n>3 ... 

xy_yx_p n (версия 2, раскомментировать) нависает для п> 3, в GHCi. Ctrl-C даже не работает. Я должен убить ghc из Activity Monitor (я нахожусь на Mac).

Любая идея, что я делаю неправильно в xy_yx_p? Остальные две функции работают нормально.

Заранее спасибо.

+0

Side Примечание: вы можете легко упростить '[(х, у) | x <- [2..n], y <- [(x + 1) .. n], is_prime (abs (x^y - y^x))]. Посмотрите, как никогда не полезно говорить «== Истина»? – dfeuer

+2

Обратите внимание, что 'length [x | x <- xs, px] == 0' может быть написано гораздо приятнее и лениво, так как 'all (not. p) xs' – Cactus

+2

@Cactus: И это намного эффективнее, так как оно разбивается на первый элемент, тогда как 'length xs' придется ждать всего вычисления (если это не пользовательская' length :: Foldable t => t -> Peano' или аналогичная). – Zeta

ответ

8

Итак, если он висит за n = 4, что такого особенного в этом случае? Ну, это t. Для x = 2 и y = 4, вы получите

t = abs (2^4 - 4^2) 
    = abs (16 - 16 ) 
    = abs 0 
    = 0 

Таким образом, вы используете 0 в is_prime, и тем самым в listprimesupto. Это приводит к нескончаемой рекурсии:

listprimesupto 0 = let halflstprimes = (listprimesupto (0 `div` 2)) 
        in -- ..... 

поэтому убедитесь, что вы справляетесь неположительные входы:

listprimesupto n | n <= 0 = [] 

is_prime n | n <= 1 = False 
+1

'5' не следует висеть, если вы использовали описанные выше методы. Но другой займет долгое время ___very___, так как вы вычисляете одни и те же списки снова и снова. А для '10' вам нужны простые числа до' 2486784401 = 10^9 - 9^10'. Это займет какое-то время. – Zeta

+0

Теперь я понял, что n = 4 висит триггером ничего выше 5 висит. Поскольку случай 2^4-4^2 испытывается до k^m-m^k, для любых k> 2 и m> 4. Итак, да, вы правы t = 0. Спасибо. –

+0

Про расчет слишком долго: да, я ожидал этого. Также ожидается, что потребление памяти станет очень большим, потому что (по крайней мере, я понимаю) интегральные типы могут переходить к целым числам, которые могут содержать память. Именно по этой причине я выбрал Haskell для этой проблемы. –

Смежные вопросы