I often find myself writing code that looks like this:
import System.Directory (doesFileExist)
import Control.Monad (unless)
example = do
fileExists <- doesFileExist "wombat.txt"
unless fileExists $ putStrLn "Guess I should create the file, huh?"
Perhaps a better way is:
example2 =
doesFileExist "wombat.txt" >>=
(\b -> unless b $ putStrLn "Guess I should create the file, huh?")
What's the best approach here?
A monadic function is a function with a single argument, written to its right. It is one of three possible function valences; the other two are dyadic and niladic. The term prefix function is used outside of APL to describe APL's monadic function syntax.
What is a Monad? A monad is an algebraic structure in category theory, and in Haskell it is used to describe computations as sequences of steps, and to handle side effects such as state and IO. Monads are abstract, and they have many useful concrete instances. Monads provide a way to structure a program.
A proper monad must satisfy the three monad laws: left identity, right identity, and associativity. Together, left identity and right identity are know as simply identity.
In functional programming, a monad is a software design pattern with a structure that combines program fragments (functions) and wraps their return values in a type with additional computation.
I could define a helper function:
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?"
It seems like unlessM
would be very useful. But the fact that I don't see anything like unlessM
(or with that type signature) on Hackage makes me think that there's some better way to handle this situation, one that I haven't discovered yet. What do the cool kids do?
I have made use of flip unless
for such cases, but these types of combinators can get a little bit noisy. With the LambdaCase
extension, you could at least avoid using a name for the result of doesFileExist
, though it would result in having to pattern match on True
and False
, which can look a little strange (depending on if you believe if
is unnecessary or not).
{-# 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?"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With