Haskell Best Practice: досрочное прекращение в Haskeline - PullRequest
5 голосов
/ 23 января 2011

Я использую пакет 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 ]

7 голосов
/ 23 января 2011

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

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

становится

Just mthree <- lift $ getInputLine "dessert> "
4 голосов
/ 23 января 2011

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

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

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

...