15

为这个问题挠了一天。

我的代码中有一些函数如下所示:

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选项是什么,我似乎都无法在任何文档的任何地方找到它的踪迹。为什么 cabal(或者此时是 ghc?)因为我使用 IT 首先放在那里的分号而对我大喊大叫?或者在 if-then-else 语句中使用单子表达式只是一个坏主意?

请注意,阴谋集团根本不会抱怨这一点:

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

...除了这很难看,我永远不想把它放在我的代码中。谁能告诉我发生了什么事?请提前致谢。

4

2 回答 2

27

if在-block 中缩进 - 表达式的“正确”方法do是将elseandthen行缩进到比 更远的位置if,就像这样。

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

这不是您问题的直接答案,但您可以利用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 回答