2013-04-08 17 views
10

Spesso mi ritrovo a scrivere il codice che assomiglia a questo:Feeding un'espressione monadica in meno o quando

import System.Directory (doesFileExist) 
import Control.Monad (unless) 

example = do 
    fileExists <- doesFileExist "wombat.txt" 
    unless fileExists $ putStrLn "Guess I should create the file, huh?" 

Forse un modo migliore è:

example2 = 
    doesFileExist "wombat.txt" >>= 
    (\b -> unless b $ putStrLn "Guess I should create the file, huh?") 

Qual è l'approccio migliore qui?

+5

Binding a '' unless' con (>> =) 'può essere fatto con una sezione,' 'qualcosa >> = (' someAction unless') '', 'se someAction' è breve. Se non è breve, penso 'do bool <- qualcosa; a meno che bool $ faccia qualunque cosa sia meglio. –

+1

Puoi usare 'mfilter', che funziona ancora meglio se incorpori il tuo calcolo in' MaybeT'. –

risposta

5

potrei definire una funzione di supporto:

unlessM :: Monad m => m Bool -> m() -> m() 
unlessM b s = b >>= (\t -> unless t s) 

example3 = unlessM (doesFileExist "wombat.txt") $ 
    putStrLn "Guess I should create the file, huh?" 

Sembra che unlessM sarebbe molto utile. Ma il fatto che io non veda nulla come unlessM (o con quella firma di tipo) su Hackage mi fa pensare che ci sia un modo migliore per gestire questa situazione, che non ho ancora scoperto. Cosa fanno i bei ragazzi?

+2

Ecco una versione di questo: http://hackage.haskell.org/packages/archive/cond/0.4.0.2/doc/html/Control-Conditional.html#v:unlessM –

+1

C'è il ['extra'] (https : //hackage.haskell.org/package/extra-1.6/docs/Control-Monad-Extra.html) pacchetto che fornisce anche 'unlessM' e sembra essere mantenuto più attivamente. –

5

Ho utilizzato flip unless per questi casi, ma questi tipi di combinatori possono diventare un po 'rumorosi. Con l'estensione LambdaCase, potresti almeno evitare di usare un nome per il risultato di doesFileExist, anche se ciò comporterebbe la corrispondenza dello schema su True e False, che può sembrare un po 'strano (a seconda se ritieni che if non sia necessario o no).

{-# LANGUAGE LambdaCase #-} 
import System.Directory (doesFileExist) 
import Control.Monad (unless) 

example' = 
    doesFileExist "wombat.txt" >>= 
    flip unless (putStrLn "Guess I should create the file, huh?") 

example'' = 
    doesFileExist "wombat.txt" >>= \ case 
    True -> return() 
    False -> putStrLn "Guess I should create the file, huh?"