2010-05-09 4 views
6

Tôi muốn biết giải pháp tốt nhất là gì để tạo menu đơn giản với chức năng được mô tả dưới đây (pseudo code) giống như tôi đang sử dụng để:đơn văn bản đơn giản trong Haskell

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

Hoặc có lẽ bất kỳ ý tưởng khác về cách tạo một menu không có trong mẫu được mô tả ở trên?

Trả lời

6

Something như

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 

Bạn có thể có thể chia liệt kê trong "sự lựa chọn" vì vậy bạn chỉ có các mô tả và các chức năng bên trong nó, một chút xa cách, nhưng hoạt động này. Đánh giá "menu" chức năng sẽ cho phép bạn chọn những gì để làm!

+0

dễ dàng :) thêm một câu hỏi: bạn có thể giải thích dòng đầu tiên: (putSrtln .....) Im newbie trong haskell và không biết rằng các toán tử thích. $ và như vậy. Nếu nó không phải là một vấn đề cho bạn nó sẽ giúp tôi. – gruber

+1

Tôi vừa sửa câu trả lời của mình và làm cho nó linh hoạt hơn! Không được thử nghiệm theo bất kỳ cách nào, tôi chỉ viết nó xuống, nhưng bạn sẽ thấy những gì tôi đã làm ở đó :). Về dòng putStrLn đó: về cơ bản tôi đã viết "putStrLn (unlines (bản đồ concatNums lựa chọn))" mà không có các parantheses :) – LukeN

+0

Được rồi, thử nghiệm ngay bây giờ, hoạt động như một sự quyến rũ! – LukeN

10

Có một vài gói mát mẻ cho cách trình độ cao để xây dựng hệ thống dòng lệnh nói chung:

  1. ui-command: Một khuôn khổ cho các chương trình dòng lệnh thân thiện
  2. haskeline: Một giao diện dòng lệnh cho người dùng nhập vào, bằng văn bản trong Haskell.
  3. HCL: Thư viện cấp cao để xây dựng giao diện dòng lệnh.

Tôi đặc biệt thích lệnh ui, vì nó là toàn bộ khung công cụ dòng lệnh của bạn: Nó sẽ gửi đến các hàm xử lý mà bạn cung cấp cho mỗi lệnh và cũng cung cấp trợ giúp cụ thể cho người dùng.

Mục tiêu là một cảm giác được đánh bóng, chứ không phải là cảm giác bị hack.

+0

hi, cảm ơn bạn đã trợ giúp, sau khi tải xuống gói ui-lệnh đó và tất cả phụ thuộc khi Im cố gắng biên dịch ví dụ tôi có lỗi: Không thể tìm thấy mô-đun 'Control.Monad.Trans': nó được tìm thấy trong nhiều gói: monads-fd-0.1.0.1 mtl-1.1.0.2 Làm cách nào để giải quyết vấn đề này? – gruber

+0

Bạn cần phải hủy đăng ký monads-fd mà tôi nghĩ. ghc-pkg unregister monads-fd. –

0

Đây là một ví dụ khác hơi giống menu, ở chỗ nó đọc các ký tự đơn trong phản ứng trực tiếp, mà không yêu cầu người dùng nhấn 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."