Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Feeding a monadic expression into unless or when

Tags:

haskell

monads

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?

like image 367
mhwombat Avatar asked Apr 08 '13 11:04

mhwombat


People also ask

What is a monadic function?

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 in simple terms?

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.

What are the monad laws?

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.

Is monad a design pattern?

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.


2 Answers

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?

like image 186
mhwombat Avatar answered Oct 14 '22 09:10

mhwombat


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?"
like image 40
ScootyPuff Avatar answered Oct 14 '22 08:10

ScootyPuff