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

如何在F#中使用fish(>>=,Kleisli复合)运算符实现map?

用>>=运算符简洁实现Result的map函数

我正在学习Scott Wlaschin的《面向铁路编程》里的单子复合。定义了bind、switch和>>=(fish运算符)之后,文章引入了map来展示如何把单轨函数转成双轨函数:

f: a -> b => f': T<a,c> -> T<b,c>

文章里的map实现是:

let map oneTrackFunction twoTrackInput =
    match twoTrackInput with
    | Success s -> Success (oneTrackFunction s)
    | Failure f -> Failure f

我已经用switch和bind实现了等价的简洁版本:

let map' f = bind (switch f)

但尝试用>>=实现时,只写出了不够简洁的代码:

let map'' f result =
    match result with
        | Ok o -> ((fun _ -> result) >>= (switch f)) o
        | Error e -> Error e

(注:如果result类型是Result<'a,'c>,o可以是任意'a类型值,因为f的输入已经存在作为>>=第一个操作数的闭包里,这是我能想到保持泛型的唯一方式)

请问有没有类似map'的更简洁实现?

测试示例:

map  ((+) 2) ((Ok 27) : Result<int,string>)

用到的bind、switch和>>=实现:

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

let switch
   (f : 'a -> 'b)
   (x : 'a      )
   =
   f x |> Ok

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

简洁实现方案

当然有,你可以利用id函数(恒等函数,即fun x -> x)和>>=组合出和map'风格一致的简洁实现:

let map'' f = id >>= switch f

原理说明

  • >>=的定义是接受两个返回Result的单轨函数,返回一个新的单轨函数:先执行左函数得到Result,再用bind把右函数应用到这个结果上。
  • id作为左操作数,传入任意result后直接返回result本身,等价于fun result -> result。
  • switch f是把单轨函数f转换成返回Result的单轨函数,即fun x -> Ok (f x)。
  • 所以id >>= switch f展开后就是fun result -> bind (switch f) result,和你之前写的map'完全等价,功能和原始map一致。

如果觉得用id不够直观,也可以写成显式的匿名函数形式,但id的写法最简洁:

let map'' f = (fun x -> x) >>= switch f

内容的提问来源于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:13:17