2016-11-22 21 views
5

GHC viết lại assert s khi tối ưu hóa chỉ id. Hoặc cách khác, hành vi của nó có thể được thay đổi bằng cờ trình biên dịch. Tuy nhiên, tôi nhận thấy điều tương tự không xảy ra với trace. Có phiên bản trace chỉ kết thúc dưới dạng id nếu cờ không được đặt hay không?Làm "theo dõi" tối ưu hóa như "khẳng định"?

Nói chung, có cách để thay đổi hành vi của một hàm dựa trên cờ trình biên dịch được sử dụng để biên dịch mô-đun gọi (không phải cờ được sử dụng để biên dịch chính nó). Giống như assert. Hay là ma thuật GHC này chỉ có thể xảy ra với assert?

+4

Tôi luôn ở hàng rào để trả lời các câu hỏi như thế này. "Tôi không biết một cách" không thực sự là một câu trả lời - nhưng nếu không ai sẵn sàng nói, thì bạn sẽ không nhận được phản hồi nào cả ... –

+0

GHC thực hiện một số biên dịch riêng biệt. Nếu mô-đun xác định không lộ ra một mở ra, mô-đun gọi bị mắc kẹt với mã đối tượng. – dfeuer

+3

Không phải ở máy tính của tôi ngay bây giờ, nhưng còn việc đặt một cuộc gọi để theo dõi bên trong khẳng định, và để cho toàn bộ khẳng định được tối ưu hóa đi? –

Trả lời

6

Không, ít nhất không dựa trên assert. Phép thuật cho assert hoạt động theo hướng khác và thay thế hàm nhận dạng bằng một xác nhận.

Dưới đây là assert from base 4.9:

-- Assertion function. This simply ignores its boolean argument. 
-- The compiler may rewrite it to @('assertError' line)@. 

-- | If the first argument evaluates to 'True', then the result is the 
-- second argument. Otherwise an 'AssertionFailed' exception is raised, 
-- containing a 'String' with the source file and line number of the 
-- call to 'assert'. 
-- 
-- Assertions can normally be turned on or off with a compiler flag 
-- (for GHC, assertions are normally on unless optimisation is turned on 
-- with @[email protected] or the @[email protected] 
-- option is given). When assertions are turned off, the first 
-- argument to 'assert' is ignored, and the second argument is 
-- returned as the result. 

--  SLPJ: in 5.04 etc 'assert' is in GHC.Prim, 
--  but from Template Haskell onwards it's simply 
--  defined here in Base.lhs 
assert :: Bool -> a -> a 
assert _pred r = r 
9

Cảnh báo: Tôi đã không cố gắng này ...

Bạn có thể thay thế các mô-đun Debug.Trace hoàn toàn với cờ biên dịch. Thực hiện một mô-đun với hiện thực tầm thường của chức năng trong Debug.Trace:

module NoTrace (trace) where: 

trace :: String -> a -> a 
{-# INLINE trace #-} 
trace _message = id 

... 

Đặt module này trong một gói có tên no-trace.

Ẩn mô-đun Debug.Trace trong đối số thành ghc theo including every module từ gói cơ sở ngoại trừ Debug.Trace. Thay thế Debug.Trace bằng NoTrace từ gói no-trace.

ghc -package="base (Control, Control.Applicative, ..., Data.Word, Foreign, ...)" \ 
    -package="no-trace (NoTrace as Debug.Trace)" \ 
    ... 

này đến từ ý tưởng điên rồ của việc sử dụng cờ biên dịch rằng những thay đổi khúc dạo đầu để thay thế cho khúc dạo đầu với một trong đó có rewrite rules để loại bỏ trace s, nhưng những quy tắc viết lại sẽ làm hỏng bất cứ điều gì mà nhập khẩu một mô-đun được biên dịch với họ, ngay cả khi một nhà nhập khẩu hạ nguồn vẫn muốn sử dụng dấu vết. Khi tìm kiếm cách thay thế khúc dạo đầu, tôi thấy rằng ghc có thể thay thế bất kỳ mô-đun nào thay thế.

5

OK, quay lại máy tính của tôi và cuối cùng nhớ ra tôi muốn chứng minh điều này. Ở đây đi:

import Control.Exception 
import Debug.Trace 
import Control.Monad 

traceDebug :: String -> a -> a 
traceDebug msg = assert (trace msg True) 

main :: IO() 
main = replicateM_ 2 $ do 
    print $ traceDebug "here1"() 
    print $ traceDebug "here2"() 
    print $ traceDebug "here3"() 

Khi biên soạn mà không tối ưu, sản lượng là:

here1 
() 
here2 
() 
here3 
() 
() 
() 
() 

Với việc tối ưu:

() 
() 
() 
() 
() 
() 

Vì vậy, tôi nghĩ rằng đây đề cập đến yêu cầu, với sự báo trước chuẩn xung quanh trace rằng một khi thunk đã được đánh giá, nó sẽ không được đánh giá lần thứ hai (đó là lý do tại sao các thông điệp chỉ xảy ra lần đầu tiên thông qua do-block).