Изучаете Haskell, хотите помочь со стилем кодирования? - PullRequest
3 голосов
/ 26 июня 2010

Я начал изучать haskell вчера, и у меня возникла проблема.Немного попробовав разные вещи, я решил наконец прийти сюда и спросить, как это исправить.Кроме того, не стесняйтесь критиковать то, как я все делал до сих пор, чтобы я мог знать, в каком направлении идти.Спасибо.

module Main where
main = putStrLn lastPrime
    where
        lastPrime :: String
        lastPrime = show(last(take 10001 primes))
        primes :: [Int]
        primes = [x| x <- [1..],length [a| a <- [1..lessen(x)], mod x a /= 0] == x - 2]
        lessen :: Int -> Int
        lessen a = ceiling(sqrt(a))

Ответы [ 2 ]

7 голосов
/ 26 июня 2010

Чтобы исправить ошибку типа, вам нужно:

    lessen :: Int -> Int
    lessen a = ceiling (sqrt (fromIntegral a))

a имеет тип Int, но sqrt ожидает тип с плавающей запятой, и самый простой способ преобразования целого типа в другой числовой тип - fromIntegral.

4 голосов
/ 26 июня 2010

В дополнение к ошибке типа в lessen у вас есть логическая ошибка в простых числах:

length [a| a <- [1..lessen(x)], mod x a /= 0] == x - 2

Вы (справедливо) рассматриваете элементы только до lessen x.Это приводит к тому, что в списке почти никогда не будет ровно x - 2 элементов.Как следствие, вы попадете в бесконечный цикл при попытке получить более двух элементов из этого списка (потому что нет 3-го элемента, для которого выполняется условие, но haskell не знает этого, поэтому он переходит к бесконечности, пытаясьчтобы найти его).

Также обратите внимание, что взятие длины списка - это операция O(n), и почти всегда есть лучший способ добиться того, чего вы хотите.

Как примечание стиля,Я бы порекомендовал определить отдельный метод isPrime.Это заставит ваш код выглядеть так:

module Main where
main = putStrLn lastPrime
    where
        lastPrime :: String
        lastPrime = show(last(take 10001 primes))
        isPrime x = length [a| a <- [1..lessen(x)], mod x a /= 0] == x - 2]
        primes :: [Int]
        primes = [x| x <- [1..], isPrime x]
        lessen :: Int -> Int
        lessen a = ceiling(sqrt (fromIntegral a))

Это ИМХО делает понимание списка намного более читабельным.Однако это все еще содержит ошибку.Чтобы избавиться от ошибки, я бы предложил определить isPrime, используя другой подход.Достигнуть до lessen x хорошо (за исключением того, что вы должны начинать с 2, потому что 1 аккуратно делит все), но вместо создания нового списка со всеми делителями, вы должны просто проверить, делит ли любое из чисел в диапазоне x.Для этого мы можем использовать функцию высшего порядка any, поэтому получаем:

isPrime x = not (any (\a -> mod x a == 0) [2 .. lessen x])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...