In addition to the question you asked, how to conditionally execute a monadic action without an else
clause, there is another problem with your code. You want to reassign a let-variable inside a conditional clause.
This point has been addressed by the other answers, with correct versions of the code. I will elaborate here. All let-variables are immutable, including inside monads. You can redefine a variable in a monad, but that merely hides the original variable from code further down the same monadic action. The reassignment of someValue
takes place inside a nested monadic action (there's a new do
block) and is not visible outside of the if
.
Conditionally reassigning a let-variable is fundamentally impossible. The compiler needs to know at compile time which value is being referred to. Ways to do this are either to return
a value from the conditional and then assign the variable, like @Aplet123's answer, or run the action in both branches of the conditional on different values, as @Will Ness said.
In reply to the question as stated: you can conditionally run a monadic action (with no else
branch) using the when
function from Control.Monad
. So if your code really had no else
branch, you could write it like this:
someFunc :: Bool -> Int -> State [Int] ()
someFunc b x = do
let someValue = x * x
when b $ do
p <- pop
push $ someValue + p
Of course this makes no sense for pure values, since a value must always be provided. But it does make sense for a monadic action (yielding ()
, or we have the same problem: what is the return value in case of a false conditional?) to be conditionally executed.
Just for curiousity, when
is defined as follows:
when :: (Applicative f) => Bool -> f () -> f ()
when p s = if p then s else pure ()
So pure ()
serves as the 'null' monadic action.
Happy Haskelling!