Haskell中的简单文本菜单

Haskell中的简单文本菜单,haskell,menu,Haskell,Menu,我想知道创建具有以下功能(伪代码)的简单菜单的最佳解决方案是什么,就像我习惯的那样: while (true) { x = readLine(); case (x): x == "1" then do sth1 function x == "2" then do sth2 function } 或者关于如何制作不符合上述模式的菜单的其他想法?类似于 menu :: IO () menu = do putStrLn . unline

我想知道创建具有以下功能(伪代码)的简单菜单的最佳解决方案是什么,就像我习惯的那样:

while (true) {
    x = readLine();
    case (x):
         x == "1" then do sth1 function
         x == "2" then do sth2 function
}
或者关于如何制作不符合上述模式的菜单的其他想法?

类似于

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
菜单::IO()
菜单=do
putStrLn。unlines$map concatNums选项
选择执行。阅读$choice
Nothing->putStrLn“请再试一次”
菜单
其中concatNums(i,(s,))=show i++>“+++s
验证::字符串->可能是Int
验证s=isValid(读取s)
其中isValid[]=Nothing
isValid((n,uu):u)
|边界外n=无
|否则=仅n
边界外n=(n<1)| |(n>长度选择)
选项:[(Int,(String,IO())]
choices=zip[1..][
(“DoSomething”,foo)
,(“退出”,酒吧)
]
执行::Int->IO()
执行n=doExec$filter(\(i,\)->i==n)选项
其中doExec((,(,f)):=f
foo=未定义
bar=未定义

您可能可以在“选项”中拆分枚举,以便只在其中包含描述和函数,稍微分离一点,但这是可行的。评估“菜单”功能将让您选择要执行的操作

对于构建命令行系统的高级方法,通常有一些很酷的软件包:

  • :友好命令行程序的框架
  • :用于用户输入的命令行界面,用Haskell编写
  • :用于构建命令行界面的高级库
  • 我特别喜欢ui命令,因为它是命令行工具的一个完整框架:它将分派给您为每个命令提供的处理程序函数,并向用户提供特定于命令的帮助


    目标是一种精致的感觉,而不是一种刻薄的感觉。

    这里还有一个更像菜单的例子,它直接读取reacts中的单个字符,而不需要用户按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."
    

    很简单:)还有一个问题:你能解释一下第一行吗:(putSrtln…)我是haskell的新手,不知道操作员喜欢。$等等如果这对你来说不是问题,它会帮助我。我只是编辑了我的答案,使它更灵活!没有以任何方式进行测试,我只是写了下来,但你应该看看我在那里做了什么:)。关于putStrLn行:我基本上写了“putStrLn(unlines(map-concatNums-choices)),没有偏执:)Whew,我只是不能发布不完整的代码片段-添加了检查错误的、未编号的输入和越界输入:)嗨,谢谢你的帮助,当我试图编译示例时,下载了包ui命令和所有依赖项后,我出现了错误:找不到模块“Control.Monad.Trans”:它在多个包中找到:monads-fd-0.1.0.1 mtl-1.1.0.2如何解决此问题?我认为您需要注销monads-fd。ghc pkg取消注册monads fd。