Haskell Best Practice: досрочное прекращение в 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)

Что довольно круто. Но если вы сравниваете только с Ничем, то ответ TomMD лучше.

2 ответа

Решение

Почему бы просто не использовать тот факт, что fail _ = Nothing Может быть, монада?

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

становится

Just mthree <- lift $ getInputLine "dessert> "

Как насчет вспомогательной функции?

inputLine :: String -> MaybeT (InputT IO) String
inputLine prompt = do
    m <- lift $ getInputLine prompt
    case m of
        Just x -> return x
        Nothing -> mzero

Это можно значительно сократить, используя различные приемы, но я хотел быть ясным. Теперь вы можете просто забыть, что getInputLine может потерпеть неудачу, MaybeT позаботится об этом для вас.

Другие вопросы по тегам