5
isqrt :: Integer -> Integer 
isqrt = floor . sqrt . fromIntegral 

primes :: [Integer] 
primes = sieve [2..] where 
sieve (p:ps) = p : sieve [x | x <- ps, x `mod` p > 0] 

primeFactors :: Integer -> [Integer] 
primeFactors n = takeWhile (< n) [x | x <- primes, n `mod` x == 0] 

Đây là mã của tôi. Tôi nghĩ rằng bạn đoán những gì tôi đang cố gắng làm: Một danh sách các yếu tố chính của một số cho trước bằng cách sử dụng danh sách vô hạn các số nguyên tố. Nhưng mã này không đánh giá uể oải.Haskell không đánh giá Lazily takeWhile

Khi tôi sử dụng ghci:l mycode.hs và nhập primeFactors 24, kết quả là [2, 3 (và con trỏ liên tục nhấp nháy ở đó) không có thêm Prelude> nhắc. Tôi nghĩ có vấn đề ở đó. Tôi đang làm gì sai?

Cảm ơn.

+3

Lưu ý rằng danh sách '' [x | x <- số nguyên tố, 10 'mod' x == 0]' 'là _not_' [2,5] ', nhưng giống như '2: 5: infiniteLoop', bởi vì sau' 5' vô hạn nhiều số nguyên tố 'x' sẽ là đã cố gắng vì họ có thể vượt qua bài kiểm tra. Tất nhiên chúng tôi biết họ sẽ không, nhưng danh sách hiểu không biết điều đó. Sau đó 'takeWhile' bị kẹt trong vòng lặp. – chi

+0

@chi Vâng, tôi biết rằng nó sẽ là một danh sách vô hạn, cảm ơn bạn. Nhưng tôi nghĩ rằng 'takeWhile' sẽ ngừng đánh giá danh sách vô hạn khi vị từ không giữ nữa. –

+3

Không. Nó không phải là một danh sách vô hạn. Trên đó 'takeWhile' sẽ không có vấn đề gì. Hãy thử 'takeWhile (<= 10) [1 ..]' và 'takeWhile (<= 10) (1: 2: 5: cho f n = f (n + 1) trong f 3)'. Ở đây '[1 ..]' là một danh sách vô hạn, trong khi '1: 2: 5: ...' không phải là - nó là một danh sách với một cột sống không xác định sau phần tử thứ 3 của nó. Trong một danh sách vô hạn, 'n danh sách' sẽ luôn luôn quay trở lại, thay vào đó khi cột sống không xác định, nó sẽ không. – chi

Trả lời

7

takeWhile không bao giờ chấm dứt đối số hỗn hợp. Nếu n là hỗn hợp, nó không có các yếu tố chính >= n, vì vậy takeWhile sẽ chỉ ngồi ở đó.

Áp dụng takeWhile vào danh sách số nguyên tố và sau đó lọc kết quả với n mod x, như thế này:

primeFactors n = [x | x <- takeWhile (<= n) primes, n `mod` x == 0] 

(<= được sử dụng thay vì < cho đúng đắn tối đa, do đó thừa số nguyên tố của một số nguyên tố sẽ bao gồm số đó).

+0

Mã của bạn hoạt động tốt, cảm ơn. Nhưng tôi không chắc tôi hiểu tình huống 'takeWhile'. Thực sự nó dừng ở đâu? Hay nó là sự hiểu biết danh sách gây ra vô cực? –

+1

@ D.Jones Cả hai. Xem xét: 'takeWhile p xs', nếu' xs' là hữu hạn hơn 'takeWhile p xs' là hữu hạn, tuy nhiên nếu' xs' là vô hạn hơn 'takeWhile p xs' * có thể * là hữu hạn hoặc vô hạn, tùy thuộc vào việc có tồn tại hay không một tiền tố hữu hạn của 'xs' trong đó' p' trở thành sai. Trong trường hợp của bạn, việc hiểu danh sách sẽ mang lại một tiền tố hữu hạn, trong đó tất cả các phần tử làm cho 'p' đúng, và sau đó không có thêm phần tử nào được tạo ra * tuy nhiên * danh sách-comprehension tiếp tục thử các số nguyên tố mãi mãi. – Bakuriu

+2

Điều quan trọng là phải phân biệt giữa danh sách và danh sách "hữu hạn" (a.k.a. chấm dứt) chỉ có một số phần tử hữu hạn. Ví dụ. '1: 2: 3: []' là hữu hạn (kết thúc) và '1: 2: 3: infiniteLoop' không phải là mặc dù nó chỉ có 3 phần tử. Vì vậy, việc hiểu danh sách không chấm dứt, mặc dù nó chỉ tạo ra một số lượng hữu hạn các phần tử; và 'takeWhile' không chấm dứt, bởi vì điều kiện không bao giờ trở thành' false' và đối số danh sách (danh sách hiểu) không chấm dứt. –

1

Vấn đề của bạn không phải là trực tiếp takeWhile, mà là danh sách hiểu.

[x | x <- primes, n `mod` x == 0] 

Đối n = 24, chúng tôi nhận 24 `mod` 2 == 024 `mod` 3 == 0, vì vậy giá trị của danh sách hiểu này bắt đầu với 2 : 3 : .... Nhưng hãy xem xét phần ....

Việc hiểu danh sách phải tiếp tục kéo các giá trị từ primes và kiểm tra 24 `mod` x == 0. Vì không còn yếu tố chính nào của 24, sẽ không có gì vượt qua bài kiểm tra đó và được phát ra như là giá trị thứ ba của việc hiểu danh sách. Nhưng vì luôn có một nguyên tố khác để kiểm tra, nó sẽ không bao giờ dừng lại và kết luận rằng đuôi còn lại của danh sách trống.

Bởi vì điều này được đánh giá rất lười biếng, nếu bạn chỉ yêu cầu hai yếu tố đầu tiên của danh sách này thì bạn ổn. Nhưng nếu chương trình của bạn có nhu cầu thứ ba (hoặc thậm chí chỉ biết có hay không có yếu tố thứ ba), thì việc hiểu danh sách sẽ chỉ xoay vòng mãi mãi để tìm ra.

takeWhile (< 24) tiếp tục kéo các phần tử khỏi đối số của nó cho đến khi tìm thấy phần tử không phải là < 24. 23 cả hai đều vượt qua bài kiểm tra đó, vì vậy takeWhile (< 24)không cần phải biết yếu tố thứ ba của việc hiểu danh sách là gì.

Nhưng nó không thực sự là vấn đề với takeWhile; vấn đề là bạn đã viết một danh sách hiểu để tìm tất cả các yếu tố chính (và không có gì khác), và sau đó cố gắng sử dụng một bộ lọc trên các kết quả để cắt đứt sự khám phá vô tận của tất cả các số nguyên tố cao hơn không thể là yếu tố.Điều đó không thực sự có ý nghĩa nếu bạn dừng lại để suy nghĩ về nó; theo định nghĩa, bất kỳ thứ gì không phải là yếu tố chính không thể là thành phần của danh sách đó, do đó bạn không thể lọc ra các yếu tố không lớn hơn n từ danh sách đó. Thay vào đó, bạn cần lọc đầu vào để hiểu danh sách đó để nó không cố gắng khám phá một không gian vô hạn, như câu trả lời của @ n.m.

Các vấn đề liên quan