2011-02-06 29 views
5

Tôi có một quy trình (a) thực hiện một số IO, (b) xây dựng bảng tra cứu và (c) trả về hành động IO sử dụng bảng tra cứu. Nhưng khi biên dịch với -O, GHC (phiên bản 6.12.1) inlines xây dựng bảng tra cứu, để nó được đánh giá lại cho mọi cuộc gọi của hành động IO.Lặp lại đánh giá biểu thức thuần túy trong hành động IO

Ví dụ:

module Main where 
import Data.Array 
import Data.IORef 
import Control.Monad 

makeAction getX getY sumRef = do 
    x <- getX 
    let a = listArray (0, 1000) [x ..] 
    return $ do 
     y <- getY 
     modifyIORef sumRef (\sum -> sum + a ! y) 

main = do 
    sumRef <- newIORef 0 
    action <- makeAction getX getY sumRef 
    replicateM_ 100000 action 
    n <- readIORef sumRef 
    putStrLn (show n) 
    where 
    getX = return (1 :: Int) 
    getY = return 0 

là vấn đề này nổi tiếng đủ để có một workaround GHC-cao độ tiêu chuẩn - hoặc làm thế nào bạn sẽ điều chỉnh chương trình để a không liên tục được phân bổ?

+0

Bạn đã thử pragma '{- # NOINLINE # -}'? – fuz

+0

@FUZxxl Có, '{- # NOINLINE a # -}' trên địa phương 'a' không làm điều đó. – antonakos

+0

Nếu bạn muốn một bảng tra cứu và muốn chia sẻ nó giữa các hành động lặp lại, chắc chắn bạn nên tách riêng nó ra khỏi hàm @ makeAction @? Dường như makeAction sẽ tạo một mảng mỗi lần bất kể nội tuyến. Có lẽ bạn nên sử dụng một IOArray treo ra khỏi hàm makeAction. –

Trả lời

4

Cách giải quyết đơn giản nhất là để buộc đánh giá bằng cách sử dụng các chú thích nghiêm khắc.

{-# LANGUAGE BangPatterns #-} 

Sau đó buộc phân bổ bằng cách đơn giản làm a nghiêm ngặt bằng cách sử dụng ! ("bang").

let !a = listArray (0, 1000) [x ..] 

Hoặc, nếu bạn đang làm việc trong đơn IO, chú thích nghiêm ngặt có thể không phải lúc nào cũng hữu ích. Để buộc đánh giá biểu thức trước khi một số hành động IO chạy, bạn có thể sử dụng evaluate. Ví dụ:

let a = listArray (0, 1000) [x ..] 
    evaluate a 
2

Hãy thử buộc a khi xây dựng giá trị monadic trở lại:

makeAction getX getY sumRef = do 
    x <- getX 
    let a = listArray (0, 1000) [x ..] 
    return $ a `seq` do 
     y <- getY 
     modifyIORef sumRef (\sum -> sum + a ! y) 
Các vấn đề liên quan