Простое текстовое меню в Haskell
Я хотел бы знать, какое лучшее решение для создания простого меню с функциональностью, описанной ниже (псевдо-код), как я привык:
while (true) {
x = readLine();
case (x):
x == "1" then do sth1 function
x == "2" then do sth2 function
}
или может какие-то другие идеи о том, как сделать меню не в описанной выше схеме?
3 ответов
что-то вроде
menu :: IO ()
menu = do
putStrLn . unlines $ map concatNums choices
choice <- getLine
case validate choice of
Just n -> execute . read $ choice
Nothing -> putStrLn "Please try again"
menu
where concatNums (i, (s, _)) = show i ++ ".) " ++ s
validate :: String -> Maybe Int
validate s = isValid (reads s)
where isValid [] = Nothing
isValid ((n, _):_)
| outOfBounds n = Nothing
| otherwise = Just n
outOfBounds n = (n < 1) || (n > length choices)
choices :: [(Int, (String, IO ()))]
choices = zip [1.. ] [
("DoSomething", foo)
, ("Quit", bar)
]
execute :: Int -> IO ()
execute n = doExec $ filter (\(i, _) -> i == n) choices
where doExec ((_, (_,f)):_) = f
foo = undefined
bar = undefined
вы, вероятно, могли бы разделить перечисление в "choices", поэтому у вас есть только описания и функции внутри него, немного разделения, но это работает. Оценка функции "меню" позволит вам выбрать, что делать!
есть несколько классных пакетов для высокоуровневых способов создания систем командной строки в целом:
- ui-command: рамки для дружественных программ командной строки
- haskeline: интерфейс командной строки для ввода пользователем, написанный на языке Haskell.
- HCL: библиотека высокого уровня для построения интерфейсов командной строки.
Мне особенно нравится ui-command, так как это целая структура для ваши инструменты командной строки: он будет отправлять функции обработчика, которые вы предоставляете для каждой команды, а также предоставлять конкретную помощь пользователю.
цель-это полированное чувство, а не хакерское чувство.
вот еще один пример, который немного больше похож на меню, в том, что он читает отдельные символы в реагирует напрямую, не требуя от пользователя нажать enter.
import System.IO
import System.Exit
import Control.Monad
main = forever (printMenu >> readChoice >>= menuAction)
printMenu = putStr "\np)rint 'Hello, world!'\ne)xit\nyour choice: " >> hFlush stdout
readChoice = hSetBuffering stdin NoBuffering >> hSetEcho stdin False >> getChar
menuAction 'p' = putStrLn "\nHello, world!"
menuAction 'e' = exitSuccess
menuAction _ = hPutStrLn stderr "\nInvalid choice."