Подача монадического выражения до или после

Я часто нахожу, что пишу код, который выглядит так:

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

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

Возможно, лучший способ:

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

Какой лучший подход здесь?

Ответ 1

Я мог бы определить вспомогательную функцию:

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?"

Кажется, что unlessM было бы очень полезно. Но тот факт, что я не вижу ничего подобного unlessM (или с этим типом подписи) в Hackage, заставляет меня думать, что есть лучший способ справиться с этой ситуацией, которую я еще не обнаружил. Что делают крутые дети?

Ответ 2

Я использовал flip unless для таких случаев, но эти типы комбинаторов могут немного шуметь. С расширением LambdaCase вы могли бы, по крайней мере, избежать использования имени для результата doesFileExist, хотя это привело бы к сопоставлению шаблонов на True и False, что может показаться немного странным (в зависимости от если вы считаете, что if не требуется или нет).

{-# 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?"