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

为何`let fmap f = id >>= (Ok << f)`在F#中可行?

关于F#中用Fish运算符实现Map的类型推导困惑

几小时前我在StackOverflow上提问《如何用F#中的Fish(>>=,Kleisli组合)运算符实现map?》,用户kaefer给出的回答简洁至极,却让我一头雾水:

let fmap f = id >>= (Ok << f)

从类型签名来看,它似乎本不应生效,但实际运行却没问题。我研究了近一小时,大概率是遗漏了F#表达式求值的核心逻辑。

以下是bind、>>=的实现代码:

let bind
    (     f : 'a -> Result<'b,'c>)
    (result :       Result<'a,'c>)
    =
    match result with 
    |    Ok o -> f o
    | Error e -> Error e

let (>>=)
    (f : 'a -> Result<'b,'error>)
    (g : 'b -> Result<'c,'error>)
    =
    f >> (bind g)

我自己尝试了>>=的替代实现:

let (>>>=)
    (f : 'a -> Result<'b,'error>)
    (g : 'b -> Result<'c,'error>)
    x
    =
    match (f x) with
    |    Ok o -> g o
    | Error e -> Error e

在dotnet fsi中的测试调用如下:

(id >>> (Ok << ((+) 2) : int -> Result<int,string>))
((Ok 27) : Result<int,string>)
//=> Ok 29

我最困惑的点在于:为何>>>=以id作为第一个参数时不会报错?我原本脑补的求值逻辑显然不对:

id >>> switch ((+) 2)
          |
          V
(>>>=) id (switch ((+) 2))
          |
          V
    match (id x) with
    |    Ok o -> (Ok << ((+) 2)) o
    | Error e -> Error e

给自己的提示:

(>>>=)                           (>>>=)
  (f : 'a -> Result<'b,'error>)    id
  (g : 'b -> Result<'c,'error>)    (Ok << ((+) 2) : int -> Result<int,string>))
  x                                ((Ok 27) : Result<int,string>)

(……如果一开始看不懂无点函数,一定要转换为带点形式。)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 19:52:31