Haskell 中的可变变量和 case 语句

Mutable variable and case statement in Haskell

所以我不确定我想要的是否实际上是一个可变变量,但它是类似于它的东西。

我基本上想这样做:

case thing of
    True -> p <- func
    False -> p <- otherFunc
return Record {program=p, otherFields=oF}

我有什么办法可以做这样的事情吗?我已将我的函数 return 设为一个 IO 记录,因此尝试将 return 放在 case 语句中,但我的最后一行需要 return 它,但事实并非如此。

是的!

let p = case thing of
   ...
return ...

这是 do 表示法中的语法糖(本身是语法糖)

let p = case thing of
   ...
  in do
       ...
       return ...

您只需移动 case 出现的位置:

p <- case thing of
        True -> func
        False -> otherFunc
return $ Record {program=p, otherFields=oF}

但这是假设 funcotherFunc 具有相同的类型,即 IO Program,其中 Programp 的任何类型。

你必须这样做,因为语法定义(或多或少)为

case <expr> of
    <pattern1> -> <expr1>
    <pattern2> -> <expr2>
    ...
    <patternN> -> <exprN>

然而,语法 <pattern> <- <expr> 本身并不是一个表达式,你不能仅仅使用 <- 语法绑定一个名称来获得一个完整的表达式,你必须对它做一些事情然后。将表达式视为 return 一个值,任何值。 <- 语法没有 return 值,它从 monadic 上下文中提取一个值并将其分配给一个名称。这类似于 let x = y 没有 return 值的方式,它只是将一个值绑定到一个名称。 xy 本身有 return 值,但 let x = y 没有。

这就是为什么您不能将 p <- func 单独 单独放在 case 分支中的原因,它必须包含其他内容。但是,如果您的整体案例 expression 具有 return 值,例如 IO Program,那么您可以使用 <-.

提取它

几乎所有这些都适用于 let 绑定。相反,如果您的 funcotherFunc 函数具有类型 Program,而不是 IO Program,那么您可以只执行

let p = case thing of
        True -> func
        False -> otherFunc
in Record {program=p, otherFields=oF}

或者更简洁

Record {program=(if thing then func else otherFunc), otherFields=oF}

您也可以将 if-then-else 与 monadic 绑定一起使用:

do
    p <- if thing then func else otherFunc
    return $ Record {program=p, otherFields=oF}