2012-06-03 34 views
15

Bạn đã gãi đầu trong một ngày qua cái này.Biểu thức Monadic trong điều kiện - biên dịch GHC, từ chối cabal

Tôi có một vài chức năng trong mã của tôi trông như thế này:

function :: IO (Maybe Whatever) 
function = do 
    monadFun 
    yaySomeIO 
    status <- maybeItWillFail 
    if checkStatus status -- Did we succeed? 
    then monadTime >>= return . Just . processItPurely 
    else return Nothing 

ghci sẽ được tải và chạy này một cách tương tác với không có vấn đề, và GHC sẽ biên dịch nó hạnh phúc. Chạy này qua cabal, tuy nhiên, mang lại cho tôi điều này:

myProgram.hs:94:16: 
Unexpected semi-colons in conditional: 
    if checkStatus status; then monadTime >>= return . Just . processItPurely; else return Nothing 

Perhaps you meant to use -XDoAndIfThenElse? 

Và bất cứ điều gì tùy chọn -XDoAndIfThenElse này là, tôi dường như không thể tìm thấy một dấu vết của nó bất cứ nơi nào trong bất kỳ tài liệu. Tại sao cabal (hoặc là ghc này vào thời điểm này?) La hét vào tôi để sử dụng dấu chấm phẩy mà CNTT đặt ở nơi đầu tiên? Hoặc đang sử dụng các biểu thức đơn thuần trong câu lệnh if-then-else chỉ là một ý tưởng tồi?

Lưu ý rằng cabal không phàn nàn về vấn đề này tại tất cả:

case checkStatus status of 
    True -> monadTime >>= return . Just . processItPurely 
    _ -> return Nothing 

... ngoại trừ đây là xấu xí như địa ngục và tôi không bao giờ muốn đặt điều này trong mã của tôi. Có ai cho tôi biết chuyện gì đang diễn ra không? Xin vui lòng và cảm ơn trước.

Trả lời

27

"đúng" cách thụt if -expressions trong một -block do là để thụt các elsethen đường xa hơn if, như thế này.

function = do 
    monadFun 
    yaySomeIO 
    status <- maybeItWillFail 
    if checkStatus status -- Did we succeed? 
     then monadTime >>= return . Just . processItPurely 
     else return Nothing 

Điều này là do các dòng có cùng số lượng thụt lề trong khối do thường được coi là các câu lệnh riêng.

Tuy nhiên, có một tiện ích mở rộng được gọi là DoAndIfThenElse sẽ cho phép bạn viết theo cách bạn đã làm. Phần mở rộng này đã được thực hiện tiêu chuẩn trong Haskell 2010, đó là lý do tại sao GHC cho phép nó theo mặc định.

Cabal có xu hướng yêu cầu bạn hiểu rõ hơn về những điều này, vì vậy để sử dụng trong Cabal, bạn cần đề cập đến nó trong tệp .cabal hoặc thêm {-# LANGUAGE DoAndIfThenElse #-} vào đầu mô-đun của bạn.

+3

Cảm ơn, tôi sẽ chỉ thêm thụt lề khi cần thiết! –

6

Đây không phải là câu trả lời trực tiếp cho câu hỏi của bạn, nhưng bạn có thể loại bỏ câu lệnh if bằng cách tận dụng lợi thế của MaybeT. Ngoài ra, foo >>= return . bar cũng giống như bar <$> foo. (<$> là từ Control.Applicative, và cũng giống như fmap)

function :: MaybeT IO Whatever 
function = do 
    lift monadFun 
    lift yaySomeIO 
    status <- lift maybeItWillFail 
    guard (checkStatus status) 
    processItPurely <$> lift monadTime 

Các ít phiền toái duy nhất là tưới nhưng không của lift s, nhưng có nhiều cách để thoát khỏi những.

+1

Sau khi ứng dụng này được thực hiện tôi cần phải nhấn các cuốn sách Haskell một lần nữa. Chắc chắn tôi đã nghe nói về những thứ như Applicative và Functors, nhưng tôi chưa bao giờ sử dụng chúng. Nếu nhiều kiến ​​thức hơn có thể làm cho mã của tôi trở nên quyến rũ hơn thì tôi là tất cả vì nó. –

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