Haskell最佳实践:在Haskeline中提前终止

时间:2011-01-22 23:02:15

标签: haskell monad-transformers haskeline

我正在使用Haskeline包,我希望在我做任何事情之前从命令行连续获得三个字符串,我想出了一个对我来说似乎是一个很好的解决方案。但我相信可能有更好的方法来做到这一点。我正在寻找使用Haskeline包时的最佳实践。请评估以下示例代码的优点:

import System.Console.Haskeline
import Control.Monad.Trans
import Control.Monad.Maybe
import Data.Maybe
import Control.Monad

main :: IO ()
main = runInputT defaultSettings (runMaybeT getStrings) >>= print

getStrings :: MaybeT (InputT IO) (String, String, String)
getStrings = do
   mone <- lift $ getInputLine "food> "
   notNothing mone
   mtwo <- lift $ getInputLine "drink> "
   notNothing mtwo
   mthree <- lift $ getInputLine "dessert> "
   notNothing mthree
   return (fromJust mone, fromJust mtwo, fromJust mthree)
      where
         notNothing a = guard (a /= Nothing)

正如你所看到的,它完成了提前终止的任务,但它仍然看起来有点令人讨厌。我正在考虑尝试将notNothing和getInputLine转换为单行,如:

mone <- notNothing =<< lift $ getInputLine "food> " -- does not type check

我认为这看起来并不那么糟糕。我认为这是非常清晰和简洁的(虽然它没有键入检查所以我将不得不编写一个版本)。

然而,这是我提出的最好的,我的问题最终是:你如何改进这个代码,使其更整洁,更容易阅读?我甚至走在正确的轨道上吗?

编辑:如果您的警卫不是'a / = Nothing',那么我刚刚发现的一个好帮手功能是:

myGuard s = guard (someConditionFunc s) >> s

因为那时你可以写(建议luqui):

mone <- myGuard =<< (lift $ getInputLine prompt)

这很酷。但如果你只与Nothing匹配,那么TomMD的答案会更好。

2 个答案:

答案 0 :(得分:7)

为什么不利用{mon}的fail _ = Nothing这个事实?

mthree <- lift $ getInputLine "dessert> "
notNothing mthree

变为

Just mthree <- lift $ getInputLine "dessert> "

答案 1 :(得分:4)

辅助函数怎么样?

inputLine :: String -> MaybeT (InputT IO) String
inputLine prompt = do
    m <- lift $ getInputLine prompt
    case m of
        Just x -> return x
        Nothing -> mzero

使用各种技巧可以大大缩短这一点,但我想说清楚。现在你可以忘记getInputLine可能会失败,MaybeT会为你解决这个问题。