2011-01-22 9 views
5

Sto utilizzando il pacchetto Haskeline e voglio ottenere tre stringhe in fila dalla riga di comando prima di fare qualsiasi cosa e ho trovato quella che sembra essere una soluzione pulita per me . Ma sono sicuro che potrebbe esserci un modo migliore per farlo. Sto cercando le migliori pratiche durante l'utilizzo del pacchetto Haskeline. Si prega di valutare i meriti del seguente codice di esempio:Haskell Best Practice: terminazione anticipata in Haskeline

import System.Console.Haskeline 
import Control.Monad.Trans 
import Control.Monad.Maybe 
import Data.Maybe 
import Control.Monad 

main :: IO() 
main = runInputT defaultSettings (runMaybeT getStrings) >>= print 

getStrings :: MaybeT (InputT IO) (String, String, String) 
getStrings = do 
    mone <- lift $ getInputLine "food> " 
    notNothing mone 
    mtwo <- lift $ getInputLine "drink> " 
    notNothing mtwo 
    mthree <- lift $ getInputLine "dessert> " 
    notNothing mthree 
    return (fromJust mone, fromJust mtwo, fromJust mthree) 
     where 
     notNothing a = guard (a /= Nothing) 

Come si può vedere si compia il compito di scioglimento anticipato, ma sembra un po 'schifo ancora. Sto pensando di provare a convertire il notNothing del ei getInputLine di in un'unica linea come:

mone <- notNothing =<< lift $ getInputLine "food> " -- does not type check 

Che credo non sembra poi così male. Penso che sia abbastanza chiaro e conciso (sebbene non scriva check, quindi dovrò scrivere una versione che lo faccia).

Tuttavia, questo è il migliore che ho trovato e alla fine la mia domanda è: come procedere per migliorare questo codice per essere più ordinato e più leggibile? Sono sulla buona strada?

Edit: se la guardia è qualcosa di diverso da 'A/= Nothing' quindi una bella funzione di supporto che ho appena scoperto è:

myGuard s = guard (someConditionFunc s) >> s 

perché allora si può scrivere (come luqui suggerito):

mone <- myGuard =<< (lift $ getInputLine prompt) 

Che è bello. Ma se stai confrontando solo con Nothing, la risposta di TomMD è migliore.

+0

Penso che la tua linea combinata non funzioni a causa della precedenza di '$'; prova 'mone <- notNothing = << lift (getInputLine" cibo> ")' –

+0

Se sei interessato alle best practice in generale, dovresti usare hlint sul tuo codice. – amccausl

+0

@amccausl Lo faccio ma non avrebbe suggerito questo non penso. –

risposta

7

Perché non sfruttare solo il fatto che fail _ = Nothing per la monade Forse?

mthree <- lift $ getInputLine "dessert> " 
notNothing mthree 

diventa

Just mthree <- lift $ getInputLine "dessert> " 
+0

Molto bello !! Sembra accecantemente ovvio in retrospettiva! Qualche suggerimento più eccellente? (Anche se dubito che possa diventare molto più piccolo di adesso) –

+0

luqui: 'fail', grazie. I 'error' ed. –

4

Che ne dite di una funzione di supporto?

inputLine :: String -> MaybeT (InputT IO) String 
inputLine prompt = do 
    m <- lift $ getInputLine prompt 
    case m of 
     Just x -> return x 
     Nothing -> mzero 

Questo può essere abbreviato considerevolmente usando vari accorgimenti, ma volevo essere chiaro. Ora puoi solo dimenticare che getInputLine può fallire, MaybeT si prende cura di quello per te.

+0

Il tuo diritto! La migliore funzione di aiuto (imo) è 'myGuard a = guard (condition_with_a) >> return a' perché allora puoi dire 'm <- myGuard = << (lift $ getInputLine prompt)' –