What's the Haskell equivalent pattern for if fall through in imperative languages, like:
function f (arg, result) {
if (arg % 2 == 0) {
result += "a"
}
if (arg % 3 == 0) {
result += "b"
}
if (arg % 5 == 0) {
result += "c"
}
return result
}
if something that has been planned or agreed falls through, it does not happen: The deal fell through when someone made our client a better offer.
Example sentences — Our babysitter fell through so I stayed home with the kids while my wife went to the concert. — The new product launch fell through so I've got to organize it all over again. — Our plans to go to Mexico fell through when my husband had to travel out of town for business.
verbgo under, fail. abort. be lost. break down. collapse.
Informal. To be unsuccessful: choke, fail, fall through.
Instead of using the State
monad, you can also use the Writer
monad and take advantage of String
's Monoid
instance (really [a]
's Monoid
instance):
import Control.Monad.Writer
f :: Int -> String -> String
f arg result = execWriter $ do
tell result
when (arg `mod` 2 == 0) $ tell "a"
when (arg `mod` 3 == 0) $ tell "b"
when (arg `mod` 5 == 0) $ tell "c"
Which I think is pretty succinct, clean, and simple.
One advantage this has over the State
monad is that you can rearrange order in which concatenations happen by just rearranging the lines. So for example, if you wanted to run f 30 "test"
and get out "atestbc"
, all you have to do is swap the first two lines of the do
:
f arg result = execWriter $ do
when (arg `mod` 2 == 0) $ tell "a"
tell result
when (arg `mod` 3 == 0) $ tell "b"
when (arg `mod` 5 == 0) $ tell "c"
Whereas in the State
monad you'd have to change the operation:
f arg = execState $ do
when (arg `mod` 2 == 0) $ modify ("a" ++)
when (arg `mod` 3 == 0) $ modify (++ "b")
when (arg `mod` 5 == 0) $ modify (++ "c")
So instead of having a relationship between execution order and order in the output string, you have to examine the actual operations closely (there's a subtle difference between (++ "a")
and ("a" ++)
), while the Writer
code is very clear at first glance in my opinion.
As @JohnL has pointed out, this is not exactly an efficient solution since concatenation on Haskell Strings
is not very fast, but you could pretty easily use Text
and Builder
to get around this:
{-# LANGUAGE OverloadedStrings #-}
import Data.Text.Lazy (Text)
import qualified Data.Text.Lazy as T
import qualified Data.Text.Lazy.Builder as B
import Control.Monad.Writer
f :: Int -> Text -> Text
f arg result = B.toLazyText . execWriter $ do
tellText result
when (arg `mod` 2 == 0) $ tellText "a"
when (arg `mod` 3 == 0) $ tellText "b"
when (arg `mod` 5 == 0) $ tellText "c"
where tellText = tell . B.fromLazyText
And so there's no real change to the algorithm other than conversion to more efficient types.
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