Простое текстовое меню в Haskell

Я хотел бы знать то, что является лучшим решением создать простое меню с функциональностью, описанной ниже (псевдо код) точно так же, как я привык к:

while (true) {
    x = readLine();
    case (x):
         x == "1" then do sth1 function
         x == "2" then do sth2 function
}

Или возможно какие-либо другие идеи о том, как сделать меню не в шаблоне описанным выше?

6
задан Pang 9 May 2017 в 01:39
поделиться

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

Вы, вероятно, могли бы разделить перечисление на «варианты», чтобы внутри были только описания и функции, небольшое разделение, но это работает. Оценка функции «меню» позволит вам выбрать, что делать!

6
ответ дан 8 December 2019 в 14:41
поделиться

Есть несколько классных пакетов для высокоуровневых способов построения систем командной строки в целом:

  1. ui-command: Фреймворк для дружественных программ командной строки
  2. haskeline: Интерфейс командной строки для пользовательского ввода, написанный на языке Haskell.
  3. HCL: Высокоуровневая библиотека для построения интерфейсов командной строки.

Мне особенно нравится ui-command, поскольку это целый фреймворк для ваших инструментов командной строки: Он будет отправлять функции-обработчики, которые вы предоставите для каждой команды, а также предоставлять пользователю помощь по конкретным командам.

Цель - ощущение полированности, а не халтуры.

10
ответ дан 8 December 2019 в 14:41
поделиться

Вот другой пример, который немного больше похож на меню, в том смысле, что он считывает отдельные символы и реагирует на них напрямую, не требуя от пользователя нажатия клавиши 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."
0
ответ дан 8 December 2019 в 14:41
поделиться
Другие вопросы по тегам:

Похожие вопросы: