배열에는 O (1) 색인이 있습니다. 문제는 각 요소가 느리게 계산된다는 것입니다. 그래서 이것은 당신이 ghci에서이 프로그램을 실행할 때 발생하는 것입니다 : 그 조회가 매우 빠르고
*Main> :set +s
*Main> let t = 100000
(0.00 secs, 556576 bytes)
*Main> let a = fibArray t
Loading package array-0.4.0.0 ... linking ... done.
(0.01 secs, 1033640 bytes)
*Main> a!t -- result omitted
(1.51 secs, 570473504 bytes)
*Main> a!t -- result omitted
(0.17 secs, 17954296 bytes)
*Main>
주, 는 후 이미 한 번 고개 됐어요. array
함수는 썽크 (thunks)에 대한 포인터의 배열을 생성하며 결국에는 값을 산출하기 위해 계산됩니다. 처음으로 가치를 평가할 때이 비용을 지불하게됩니다.여기에 a!t
을 평가하는 썽크의 처음 몇 확장은 다음과 같습니다
a!t -> a!(t-1)+a!(t-2)-> a!(t-2)+a!(t-3)+a!(t-2) -> a!(t-3)+a!(t-4)+a!(t-3)+a!(t-2)
그것은 비싼 계산 자체의 비용이 아니다, 오히려이 매우 큰 썽크를 작성하고 통과 할 필요가있다.
나는 array
에 전달 된 목록의 값을 엄격하게하려고했지만 끝없는 반복이 발생하는 것으로 보였다.
이 문제를 해결하는 일반적인 방법 중 하나는 STArray와 같은 변경 가능한 배열을 사용하는 것입니다. 요소는 배열을 만드는 동안 사용할 수있을 때 업데이트 할 수 있으며 최종 결과는 고정되어 반환됩니다. 벡터 패키지에서는 create
및 constructN
함수를 사용하여 쉽게이 작업을 수행 할 수 있습니다.
-- constructN :: Unbox a => Int -> (Vector a -> a) -> Vector a
import qualified Data.Vector.Unboxed as V
import Data.Int
fibVec :: Int -> V.Vector Int64
fibVec n = V.constructN (n+1) c
where
c v | V.length v == 0 = 0
c v | V.length v == 1 = 1
c v | V.length v == 2 = 1
c v = let len = V.length v
in v V.! (len-1) + v V.! (len-2)
하지만의 fibVec
기능은 언 박싱 벡터와 함께 작동합니다. 정규 벡터 (및 배열)는 충분히 엄격하지 않으므로 이미 발견 한 동일한 문제로 다시 안내됩니다. 그리고 안타깝게도 Integer
에 대한 Unboxed 인스턴스가 없으므로 제한없는 정수 유형 (이 테스트에서는 이미 fibVec
이 오버플로되어 있음)이 필요하면 IO
또는 ST
에 변경 가능한 배열을 만들어야 만 고정밀 성을 유지할 수 있습니다. 당신의 fibArray
예에 특별히 참조
모 놀리 식 배열이란 무엇입니까? – luqui
'IO (U) Array'와'ST (U) Array'는 모 놀리 식으로 보이지 않습니다 ... –
비효율적 인 코드에 대한 간단한 예를 들어 줄 수 있습니까? –