gpt4 book ai didi

f# - 类型扩展中的重载运算符

转载 作者:行者123 更新时间:2023-12-03 23:23:39 29 4
gpt4 key购买 nike

好的,所以我基本上是在尝试将绑定(bind)运算符添加到选项类型中,似乎我尝试的所有内容都有一些不明显的警告,阻止我这样做。我怀疑这与 .NET 类型系统的限制有关,并且可能与无法在用户代码中实现类型类的原因相同。

无论如何,我已经尝试了几件事。

首先,我尝试了以下

let (>>=) m f = ???

意识到我想根据 m 的类型做不同的事情. F# 不允许函数重载,但 .NET 确实允许方法重载,所以尝试第二个:
type Mon<'a> =
static member Bind(m : Option<'a>, f : ('a -> Option<'b>)) =
match m with
| None -> None
| Some x -> f x
static member Bind(m : List<'a>, f : ('a -> List<'b>)) =
List.map f m |> List.concat

let (>>=) m f = Mon.Bind(m, f)

没有骰子。无法根据先前给定的类型信息选择唯一的重载。添加类型注释。

我尝试使运算符内联,但它仍然给出相同的错误。

然后我想我可以制作 >>=运算符类型的成员。我很确定这会起作用,但我认为我不能在现有类型上破解它。您可以使用 type Option<'a> with 扩展现有类型但是您不能将运算符作为扩展名。

这是我对这段代码的最后一次尝试:
type Option<'a> with
static member (>>=) (m : Option<'a>, f : ('a -> Option<'b>)) =
match m with
| None -> None
| Some x -> f x

“扩展成员不能提供运算符重载。考虑将运算符定义为类型定义的一部分。”惊人的。

我还有其他选择吗?我可以在单独的模块中为不同的 monad 定义单独的函数,但如果你想在同一个文件中使用多个版本,这听起来很糟糕。

最佳答案

您可以将 .NET 重载解析与内联/静态约束相结合,以获得所需的行为。

这是一步一步explanation这是您特定场景的一个小型工作示例:

type MonadBind = MonadBind with
static member (?<-) (MonadBind, m:Option<'a>, _:Option<'b>) =
fun (f:_->Option<'b>) ->
match m with
| None -> None
| Some x -> f x
static member (?<-) (MonadBind, m:List<'a>, _:List<'b>) =
fun (f:_->List<'b>) ->
List.map f m |> List.concat

let inline (>>=) m f : 'R = ( (?<-) MonadBind m Unchecked.defaultof<'R>) f

[2; 1] >>= (fun x -> [string x; string (x+2)]) // List<string> = ["2"; "4"; "1"; "3"]
Some 2 >>= (fun x -> Some (string x)) // Option<string> = Some "2"

您还可以“手动”指定约束,但使用运算符时会自动推断它们。

我们在 FsControl 中使用了这种技术的改进(没有运算符)。定义 Monad、Functor、Arrow 和其他抽象。

另请注意,您可以直接使用 Option.bindList.collect对于两个绑定(bind)定义。

关于f# - 类型扩展中的重载运算符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25642150/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com