You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Haskell do表达式中b <- (+10)的绑定对象及函数单子相关问题

关于Haskell do表达式中函数单子的绑定问题

先贴出问题中的代码:

addStuff :: Int -> Int
addStuff = do
    a <- (*2)
    b <- (+10)
    return (a+b)

1. b <- (+10)中b绑定的是什么?

这段代码里的单子是函数单子(Reader Monad),因为addStuff的类型是Int -> Int,而函数类型(->) r本身是Monad的一个实例。

在Reader Monad的do表达式里,x <- f的逻辑是:把当前do表达式接收的共享输入参数传给函数f,再把f的返回值绑定给x。具体到b <- (+10),就是把addStuff接收到的那个Int参数传给(+10)(等价于\x -> x+10),得到的计算结果会被绑定给b。

比如调用addStuff 5时:

  • a <- (*2) 是把5传给(*2),得到10绑定给a
  • b <- (+10) 是把5传给(+10),得到15绑定给b
  • 最后return (a+b)返回10+15=25,和直接写\x -> x*2 + x+10的结果完全一致。

2. 函数作为单子时,是否不该用“提取和包裹”的视角?

没错,Maybe、List这类单子用“提取包裹值”的视角很直观,但函数单子(Reader)的核心逻辑完全不同。它的重点不是“解开包裹取内部值”,而是共享一个输入上下文:整个do表达式里的所有函数都会接收同一个输入参数,<-在这里的作用是“用当前共享输入执行这个函数,把结果绑定给变量”,和从容器里取值的逻辑完全无关。

你可以把Reader Monad理解成“依赖某个共享环境(输入参数)的计算”,do表达式就是把多个依赖同一环境的计算串联起来,每个<-都是在这个环境下完成一步计算并暂存结果,全程不用手动传递那个共享参数。

3. 函数对应的单子上下文是什么?

函数类型r -> a作为单子时,它的上下文是**“需要一个类型为r的输入值,才能产出结果a”**。换句话说,这个单子里的“值”不是直接的a,而是一个“等待输入r才能生成a的计算过程”。Reader Monad的作用就是让你能把多个这样的计算组合起来,它们自动共享同一个输入r,不用反复手动传递。

比如这段addStuff的do表达式,本质是把三个依赖Int输入的计算组合:先算输入乘2,再算输入加10,最后把两个结果相加——整个过程中输入参数只需要传一次,Monad会帮你自动完成参数的传递工作。


内容的提问来源于stack exchange,提问作者Skab

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 19:36:01