15

これで1日頭を悩ませています。

私のコードには、次のような関数がいくつかあります。

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 はこれを問題なく対話的に読み込んで実行し、ghc は問題なくコンパイルします。ただし、これをcabalで実行すると、次のようになります。

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?

そして、この-XDoAndIfThenElseオプションが何であれ、ドキュメントのどこにもその痕跡を見つけることができないようです. なぜカバール (またはこの時点でこれは ghc ですか?) が、IT が最初にセミコロンを使用したことについて私に怒鳴っているのですか? それとも、if-then-else ステートメントでモナド式を使用するのは悪い考えですか?

cabal はこれについてまったく文句を言わないことに注意してください。

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

...これは地獄のように醜いことを除いて、これを自分のコードに入れたくありません。誰が何が起こっているのか教えてもらえますか? よろしくお願いします。

4

2 に答える 2

27

if-block 内の-expression をインデントする「正しい」方法は、このようにと行を よりもさらにdoインデントすることです。elsethenif

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

これは、do通常、ブロック内でインデント量が同じ行が別のステートメントとして扱われるためです。

DoAndIfThenElseしかし、あなたがしたようにそれを書くことを可能にするという拡張機能があります。この拡張機能は Haskell 2010 で標準化されたため、GHC ではデフォルトで有効になっています。

Cabal は、これらのことについてより明確にすることを要求する傾向があるため、Cabal で使用するには、.cabalファイルで言及するか{-# LANGUAGE DoAndIfThenElse #-}、モジュールの先頭に追加する必要があります。

于 2012-06-03T02:25:48.693 に答える
6

これはあなたの質問に対する直接的な回答ではありませんが、を利用して if ステートメントを削除できますMaybeT。また、foo >>= return . barと同じbar <$> fooです。(<$>は からControl.Applicative、 は と同じですfmap)

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

唯一の煩わしさは不当にlifts をまき散らすことですが、それらを取り除く方法があります。

于 2012-06-04T20:14:36.183 に答える