【发布时间】:2014-10-27 19:49:33
【问题描述】:
好的,所以我基本上是在尝试将绑定运算符添加到选项类型中,似乎我尝试的所有内容都有一些不明显的警告,阻止我这样做。我怀疑这与 .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 定义单独的函数,但如果你想在同一个文件中使用多个版本,这听起来很糟糕。
【问题讨论】:
-
@JohnPalmer 哦,对不起。关键是 Bind 方法有多个重载。然后它抛出一个错误。我会在问题中解决它。
-
我认为您的问题是您希望类型构造函数为一般 (>>=) 提供合理的类型(记住 Monad 有种类 * -> *) - 内联的静态约束因此,函数也无济于事 - 所以不,你不走运。
-
我有时将这些运算符包装在一个内部模块中(通常只命名为运算符) - 所以如果我想要这些,我可以
open MyMonad.Operators- 或者必须MyMonad.Operators.>>=:( -
如果你真的很绝望,可以随时修改
Option.fs -
@JohnPalmer +1 - 但为什么呢?
opt >>= (fun x -> ...在我看来并不比opt |> Option.bind (fun x -> ...好多少
标签: f# operator-overloading inline optional