Haskell 最佳实践:在 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 的答案会更好。
I am using the Haskeline package and I want to get three strings in a row from the command line before I do anything and I have come up with what seems to be a neat solution to me. But I am sure that there might be a better way to do it. I am looking for best practices while using the Haskeline package. Please evaluate the merits of the following example code:
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)
As you can see it accomplishes the task of early termination but it looks a bit yucky still. I'm thinking of trying to convert the notNothing's and the getInputLine's into a single line like:
mone <- notNothing =<< lift $ getInputLine "food> " -- does not type check
Which I think does not look that bad. I think that is pretty clear and concise (though it does not type check so I will have to write a version that does).
However, this is the best I have come up with and my question finally is: How would you go about improving this code to be neater and more readily readable? Am I even on the right track?
Edit: If your guard is something other than 'a /= Nothing' then a nice helper function that I just discovered is:
myGuard s = guard (someConditionFunc s) >> s
Because then you can write (as luqui suggested):
mone <- myGuard =<< (lift $ getInputLine prompt)
Which is pretty cool. But if you are matching against only Nothing then TomMD's answer is better.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
为什么不直接利用 Maybe monad 的
fail _ = Nothing
事实呢?变成
Why not just leverage the fact that
fail _ = Nothing
for the Maybe monad?becomes
辅助功能怎么样?
使用各种技巧可以大大缩短这个时间,但我想澄清一下。现在您可以忘记
getInputLine
可能会失败,MaybeT
会为您解决这个问题。How about a helper function?
This can be shortened considerably using various tricks, but I wanted to be clear. Now you can just forget that
getInputLine
can fail,MaybeT
takes care of that for you.