2010-05-09 14 views
6

Vorrei sapere qual è la soluzione migliore per creare menu semplice con funzionalità descritte di seguito (pseudo codice), proprio come ci sono abituato:menu di testo semplice in Haskell

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

O forse altre idee su come creare un menu non nello schema sopra descritto?

risposta

6

Qualcosa di simile

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 

Probabilmente si può dividere l'enumerazione di "scelte" in modo da avere solo le descrizioni e le funzioni al suo interno, un po 'di separazione, ma questo funziona. Valutare la funzione "menu" ti permetterà di scegliere cosa fare!

+0

così facile :) ancora una domanda: Potrebbe spiegare prima linea: (putSrtln .....) Im novizio in Haskell e non so che gli operatori come. $ e così via. Se non è un problema per te, mi aiuterebbe. – gruber

+1

Ho appena modificato la mia risposta e l'ho resa più flessibile! Non testato in alcun modo, l'ho appena scritto, ma dovresti vedere cosa ho fatto lì :). Riguardo a questa linea putStrLn: ho praticamente scritto "putStrLn (unlines (map concatNums choices))" senza le parestes :) – LukeN

+0

Ok, testato ora, funziona come un incantesimo! – LukeN

10

Ci sono alcuni pacchetti freddi per modi di alto livello per costruire sistemi di linea di comando in generale:

  1. ui-command: Un quadro per i programmi a riga di comando amichevoli
  2. haskeline: Un'interfaccia a riga di comando per l'input dell'utente, scritte in Haskell.
  3. HCL: libreria di alto livello per la creazione di interfacce a linea di comando.

Mi piace particolarmente il comando ui, poiché è un intero framework per gli strumenti della riga di comando: invierà alle funzioni del gestore fornite per ogni comando e fornirà anche l'aiuto specifico del comando all'utente.

L'obiettivo è una sensazione raffinata, piuttosto che una sensazione di hacker.

+0

ciao, grazie per l'aiuto, dopo aver scaricato quel pacchetto ui-command e alldependencies quando Sto provando a compilare example I have error: Impossibile trovare il modulo 'Control.Monad.Trans ': è stato trovato in più pacchetti: monads-fd-0.1.0.1 mtl-1.1.0.2 Come posso risolvere questo? – gruber

+0

Dovrai annullare la registrazione di monads-fd, penso. ghc-pkg annulla la registrazione di monads-fd. –

0

Ecco un altro esempio che è un po 'più simile a un menu, in quanto legge i singoli caratteri in modo che reagiscano direttamente, senza richiedere all'utente di premere Invio.

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." 
Problemi correlati