在这一个人的头上划了一天。
我的代码中有一些看起来像这样的函数:
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(或者就此而言,这是什么?)对我使用IT首先放置的分号大吼大叫?或者在if-then-else语句中使用monadic表达式只是一个坏主意?
请注意,cabal根本没有抱怨这个:
case checkStatus status of
True -> monadTime >>= return . Just . processItPurely
_ -> return Nothing
...除了这是丑陋的,我永远不想把它放在我的代码中。 谁能告诉我发生了什么事?请提前感谢。
答案 0 :(得分:27)
在if
块中缩进do
- 表达式的“正确”方法是缩进else
和then
行,而不是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 #-}
添加到模块的顶部
答案 1 :(得分:6)
这不是您问题的直接答案,但您可以利用MaybeT
来消除if语句。此外,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
唯一的烦恼是lift
的无偿洒水,但有办法摆脱这些。