我正在使用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

我认为看起来还不错。我认为这非常清楚简洁(尽管它没有键入check,所以我将不得不编写一个能做到这一点的版本)。

但是,这是我能想到的最好的选择,最后我的问题是:如何改进此代码使其更整洁,更易读?我什至在正确的轨道上吗?

编辑:如果您的 guard 不是'a/= Nothing'以外的东西,那么我刚刚发现的一个不错的帮助函数是:
myGuard s = guard (someConditionFunc s) >> s

因为那样您可以编写(如luqui建议):
mone <- myGuard =<< (lift $ getInputLine prompt)

真是太酷了。但是,如果您只匹配Nothing,那么TomMD的答案会更好。

最佳答案

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

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

变成
Just mthree <- lift $ getInputLine "dessert> "

关于Haskell最佳实践: Early termination in Haskeline,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/4771199/

10-09 06:41