Reputation: 717
So I'm not sure if what I want is in fact a mutable variable, but it's something likened to it.
I essentially want to do this:
case thing of
True -> p <- func
False -> p <- otherFunc
return Record {program=p, otherFields=oF}
Any way I can do something like that? I've made my function return an IO Record, so tried just putting the return in the case statement, but my last line needs to return it, and it doesn't.
Upvotes: 1
Views: 409
Reputation: 54068
You just need to move where the case
occurs:
p <- case thing of
True -> func
False -> otherFunc
return $ Record {program=p, otherFields=oF}
But this is assuming that func
and otherFunc
have the same type, namely IO Program
, where Program
is whatever type p
is.
You have to do it this way because the syntax is defined (more or less) as
case <expr> of
<pattern1> -> <expr1>
<pattern2> -> <expr2>
...
<patternN> -> <exprN>
However, the syntax <pattern> <- <expr>
is not in itself an expression, you can't just bind a name using the <-
syntax to get a complete expression, you have to do something with it afterwards. Think of expressions as something that return a value, any value at all. The <-
syntax does not have a return value, it's extracting a value from a monadic context and assigning it to a name. This is similar to how let x = y
doesn't have a return value, it's just binding a value to a name. x
and y
themselves have return values, but let x = y
does not.
This is why you can't just put p <- func
by itself in a case branch, it would have to have other things with it. However, if your overall case expression has a return value like IO Program
, then you can extract that using <-
.
Pretty much all of this goes for let
bindings as well. If instead your func
and otherFunc
functions have the type Program
, instead of IO Program
, then you could just do
let p = case thing of
True -> func
False -> otherFunc
in Record {program=p, otherFields=oF}
Or more succinctly
Record {program=(if thing then func else otherFunc), otherFields=oF}
You can use if-then-else
with monadic bind as well:
do
p <- if thing then func else otherFunc
return $ Record {program=p, otherFields=oF}
Upvotes: 6
Reputation: 48611
Yup!
let p = case thing of
...
return ...
This is syntax sugar in do
notation (itself syntax sugar) for
let p = case thing of
...
in do
...
return ...
Upvotes: 3