为何`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
相关产品推荐
相关产品推荐

