5

我正在使用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 的答案会更好。

4

2 回答 2

7

fail _ = Nothing为什么不直接利用Maybe monad的事实呢?

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

变成

Just mthree <- lift $ getInputLine "dessert> "
于 2011-01-22T23:14:31.263 回答
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为你处理好它。

于 2011-01-22T23:16:43.263 回答