2010-12-27 4 views
8

내가 하스켈에 새로 온 사람, 나는 조금을 시도하고있다 :하스켈 주요 테스트

isPrime :: Integer->Bool 
isPrime x = ([] == [y | y<-[2..floor (sqrt x)], mod x y == 0]) 

나는 몇 가지 질문이 있습니다. 나는 .hs를로드 할 때

  1. 왜, WinHugs 말 : (Floating Integer, RealFrac Integer)의 인스턴스가 isPrime의 정의에 필요한?
  2. 해석기가 오른쪽 집합에서 하나의 요소를 찾으면 즉시 중단하거나 모든 집합을 계산합니까? 내 말이 무슨 뜻인지 알 것 같아.

영어로 죄송합니다.

답변

17

1) 문제는 sqrt(Floating a) => a -> a 유형이지만 정수를 인수로 사용하려고합니다. 따라서 Integer를 먼저 Floating으로 변환해야합니다.

2 sqrt (fromIntegral x))를 작성하여 나는 == 게으른하지 않아야 할 이유를 볼하지만) 무한리스트에 작품으로 빈 콜렉션에 대한 테스트를 위해 당신은 확실히 게으른입니다 null 기능을 (사용할 수 있습니다

isPrime :: Integer->Bool 
isPrime x = null [y | y<-[2..floor (sqrt (fromIntegral x))], x `mod` y == 0] 

그러나 더 관용적 인 해결책을 얻으려면 문제를 더 작은 하위 문제로 나눕니다. 우선, Y의 *의 Y와 Y의 모든 요소의리스트를 필요 < = X :

filter (\y -> x `mod`y == 0) (takeWhile (\y -> y*y <= x) [2..]) 

그렇다면 우리는 그리스트 있는지 확인해야

takeWhile (\y -> y*y <= x) [2..] 

그렇다면 우리는 X 분할 요소만을 필요

isPrime x = null (filter (\y -> x `mod`y == 0) (takeWhile (\y -> y*y <= x) [2..])) 

그리고 이것은 당신에게 Lisp 다운을 보이는 경우, $

isPrime x = null $ filter (\y -> x `mod` y == 0) $ takeWhile (\y -> y*y <= x) [2..] 
0 괄호의 일부를 대체 : 비어 추가 설명을 위해

당신은 람다 "아웃소싱"할 수

isPrime x = not $ any divisible $ takeWhile notTooBig [2..] where 
    divisible y = x `mod`y == 0 
    notTooBig y = y*y <= x 
+0

마지막 선언은 2보다 크거나 같은 모든 숫자에서 작동합니다. 1의 경우 1이 소수가 아니므로 소수임을 잘못 나타냅니다. isPrime이 작동하려면 – Elmex80s

7
  1. sqrt 때문에 유형 Floating a => a -> a 있습니다. 즉, 입력은 Floating 유형이어야하며 출력은 동일한 유형이어야합니다. 즉, xFloating 유형이어야합니다. 그러나 xInteger 유형이고 Floating 유형이 아닌 것으로 선언했습니다. 또한 floor에는 RealFrac 유형이 필요하므로 x도 입력해야합니다.

    오류 메시지는 물론이의 인스턴스 Floating Integer (및 RealFrac에 대해 동일)를 정의하여 IntegerFloating 유형 (함으로써.

    이 경우에 올바른 방법이 아니라고 수정 제안합니다. 오히려 당신은 (FloatingRealFrac의 인스턴스 인)을 Realx 변환 fromIntegral를 사용하고 sqrt에 그를 제공해야합니다.

  2. 예. 즉시 ==가 보는대로 오른쪽 피연산자는을 가지고 적어도 하나의 요소는 []과 같지 않으므로 False을 반환합니다.

    즉, null은 목록이 [] ==보다 비어 있는지 확인하는 관용적 인 방법입니다. 두 번째 점에 대해서는

+2

관용적 인 해결책은'truncate '를 제안합니다. sqrt. fromntegral'에 대해. 1과'all (\ y -> x \'mod \'y/= 0) [...]'. – delnan

1

, 예를 들어, 중지 :

[] == [x | x <- [1..]] 

반환 False

+3

'[x | x <- [1 ..]]'은'[1 ..]'btw와 같습니다. – sepp2k

-2
  1. 내가 WinHugs는 정수 등의 모듈을 가져올 필요하다고 생각 ... 지능 시도
  2. 예를 들어 전화 할 때까지 통역사가 아무 것도 계산하지 않습니다. isPrime 32 그러면 표현식이 느리게 계산됩니다.

PS 귀하의 isPrime 구현은 최상의 구현이 아닙니다!

+0

1) Integer 용 "import [ing] 모듈"은 문제가 아닙니다. 문제는 그의 정의에 따르면 WinHugs가 말했듯이 isPrime의 정의에 필요한 "(Floating Integer, RealFrac Integer) 인스턴스"입니다. 2) 예, 그리고 ...?그건 그다지 관련이 없어요. 어떻게 대응해야할지 모르겠군요. 먼저 정의가 작동하도록 수정 한 다음 사용 방법에 대해 걱정하십시오. 추신 :) OP의 isPrime 구현이 최선이 아니라, 그걸 구현 한 "그"입니다! 자신의 문제를 해결하는 방법을 설명하고, 직접 작성하거나 "GTFO!" – BMeph

+0

1) 네 말이 맞아, 나는 아주 오랫동안 하스켈을 사용하지 않았다. 2) 나는 그가 학생과 같다고 들었을 때, 그가 스스로 알아 내야 할 대답을 줄 이유가 없다. 나는 대학에서 가장 최적의 isPrime 구현을 가지고 있지만 단지 답을 게시함으로써 어떤 좋은 결과도 보이지 않는다. 단지 복사 만 할 수 있었고 하스켈을 잘 생각한다고 생각한다. 3) 인생을 정리하고 존엄성을 가져라. –

1

Landei의 솔루션입니다 : 어떤 $하지 null와 $ 필터를 교체하여

isPrime x = null $ filter divisible $ takeWhile notTooBig [2..] where 
    divisible y = x `mod`y == 0 
    notTooBig y = y*y <= x 

당신은 거의 "사람이 읽을 수있는"수를 그러나 더 효율적인 ¹ 구현을 원한다면 (BMeph에게 감사드립니다) :

-- list of all primes 
primes :: [Integer] 
primes = sieve (2 : 3 : possible [1..]) where 
    sieve (p : xs) = p : sieve [x | x <- xs, x `mod` p > 0] 
    possible (x:xs) = 6*x-1 : 6*x+1 : possible xs 

isPrime :: Integer -> Bool 
isPrime n = shortCircuit || (not $ any divisible $ takeWhile inRangeOf primes) where 
    shortCircuit = elem n [2,3] || (n < 25 && ((n-1) `mod` 6 == 0 || (n+1) `mod` 6 == 0)) 
    divisible y = n `mod` y == 0 
    inRangeOf y = y * y <= n 

'효율성'은 다음과 같습니다. f rom 상수 소수의 사용. , 하스켈 런타임이 때문에 이후의 호출은 그것은 sieve 값이 단순히 재귀 테이블입니다 논리 참고로 숫자의 범위를 제거

  • 을 평가하지 않는 결과를 캐시 할 수

    1. : 그것은 두 가지 방법으로 검색을 향상 여기서 의 머리를 말하고 목록은 소수이며 그것을 추가합니다. 리스트의 나머지 부분에 대해 숫자를 구성하는리스트에 다른 값이 이미 존재하지 않으면 possible은 모든 가능한 소수가 형태 6 * k-1 또는 6에 있으므로 가능한 모든 소수의 목록입니다 * K-1 (2, 3) 것을 제외하고는 동일한 규칙이 적용된다 shortCircuit 너무 빨리 DF로

    계산

  • 에서 각주 구제
    ¹ 여전히 소수를 찾는 것은 대단히 비효율적 인 방법입니다. 수천을 넘는 소수가 필요하다면 시브 분열을 사용하지 말고 체를 대신 사용하십시오. far more efficient 개의 구현이 hackage에 있습니다.

    +0

    shortcircuit를 제거해야합니다. 예를 들어 25는 프라임이 아닌 25와 일치합니다. 그것을 컴파일하기 위해서는 ($가 아닌 나눌 수있는 $ takeWhile inRangeOf 소수도) 주위에 대괄호가 필요하다. – rdrey

    +0

    'primes'에 대한 코드는 생성 된 소수의 수에서 * quadratic *입니다. 에라 토 스테 네스의 체의 이론적 인 시간 복잡성은 생성 된'n' 소수에서'O (n * log n * log (log n))'입니다. 시험 분할의 이론적 인 복잡성은'O (n^1.5/(log n)^0.5)'이다. 그렇다면 왜 그 코드는 시험 배분이 단순 해 보이는가? 그 이유는 입력 스트림에서 프라임의 사각형이 보일 때까지 * 각 필터 *의 실행이 *** 연기되어야하기 때문입니다. 입력 스트림을 1/3로 희석하면 상수 요소가 줄어 듭니다. –