私はHaskelineパッケージを使用していて、何かをする前にコマンドラインから3つの文字列を続けて取得したいと思っています。そして、私にとってはきちんとした解決策と思われるものを思いつきました。しかし、私はそれを行うためのより良い方法があるかもしれないと確信しています。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を次のような1行に変換しようと考えています。
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の答えの方が優れています。