내 기능이 무한 목록에서 작동하지 않는 이유는 무엇입니까?
Nov 17 2020
haskell을 배우고 conseq
크기 n의 연속 요소 목록을 반환하는 함수 를 구현하려고합니다 .
conseq :: Int -> [Int] -> [[Int]]
conseq n x
| n == length(x) = [x]
| n > length(x) = [x]
| otherwise = [take n x] ++ (conseq n (drop 1 x))
이것은 올바르게 작동합니다.
> take 5 $ conseq 2 [1..10]
[[1,2],[2,3],[3,4],[4,5],[5,6]]
그러나 [1..]
대신을 전달 [1..10]
하면 프로그램이 무한 루프에 빠집니다.
내가 이해했듯이 haskell은 게으른 평가를 가지고 있으므로 여전히 동일한 결과를 얻을 수 있어야합니까? 그렇 length
습니까? 길이가보다 커지면 처음 두 조건이 거짓으로 평가되지 n
않습니까?
내가 무엇을 오해 했습니까?
답변
4 WillemVanOnsem Nov 17 2020 at 02:40
사용 length
이 좋은 생각이 아닌 주된 이유 중 하나 는 무한 목록에서 평가해야 할 때 무한 루프에 갇히기 때문입니다.
그러나 좋은 소식은 length
. 또한 시간 복잡성을 악화시킬 것입니다. 두 개의 열거 자로 작업 할 수 있습니다. 하나는 다른 하나보다 n-1 자리 앞서 있습니다. 이 열거자가 목록의 끝에 도달하면 첫 번째 열거 자에 여전히 n-1 개의 요소 가 있음을 알고 있으므로 값 생성을 중지 할 수 있습니다.
conseq :: Int -> [a] -> [[a]]
conseq n ys = go (drop (n-1) ys) ys
where go [] _ = []
go (_:as) ba@(~(_:bs)) = take n ba : go as bs
이것은 우리에게 다음을 제공합니다 :
Prelude> conseq 3 [1 ..]
[[1,2,3],[2,3,4],[3,4,5],[4,5,6],[5,6,7],[6,7,8],[7,8,9],[8,9,10],[9,10,11],[10,11,12],[11,12,13],[12,13,14],[13,14,15],[14,15,16],[15,16,17],[16,17,18],[17,18,19],[18,19,20],[19,20,21],[20,21,22],[21,22,23],[22,23,24],[23,24,25],[24,25,26],[25,26,27],…
Prelude> conseq 3 [1 .. 4]
[[1,2,3],[2,3,4]]
4 user253751 Nov 17 2020 at 02:29
당신의 함수가 제일 먼저 계산입니다 length(x)
그것이 반환할지 여부를 알 수 있도록, [x]
, [x]
, 또는[take n x] ++ (conseq n (drop 1 x))
length
목록의 모든 요소 수를 계산합니다. 무한 목록의 길이를 요청하면 계산이 끝나지 않습니다.