简体   繁体   中英

Mutable variable and case statement in Haskell

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.

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}

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 ...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM