我正在使用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的答案会更好。
答案 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
会为你解决这个问题。