【发布时间】:2016-10-10 19:48:06
【问题描述】:
我想在我的计算表达式上定义一些自定义运算符,但无法使其工作
type ZipSeq() =
[<CustomOperation("<*>")>]
member this.Apply f s =
f |> Seq.zip s |> Seq.map (fun (y, x) -> x(y))
member this.Return x =
Seq.initInfinite (fun _ -> x)
// (a -> b) -> seq<a> -> seq<b>
[<CustomOperation("<!>")>]
member this.Map f s =
this.Apply (this.Return f) s
let zipSeq = new ZipSeq()
let f (a : float) = a * a
let s = seq { yield 1. }
// seq<b>
let h1 = zipSeq.Map f s
//thinking h1 should be the same as h2
//but compilation error : ` This value is not a function and cannot be applied`
let h2 = zipSeq { return f <!> s }
顺便说一句,将 member this.Map f s ... 更改为 member this.Map (f, s) ... 会出现同样的错误。
【问题讨论】:
-
我认为这不可能。不过,这会很酷。
-
您应该能够通过单独定义这些运算符(即不作为计算构建器的一部分)来实现此语法,并使它们返回一个monad实例,然后可以是
let!-ed或return!-ed. -
您能提出任何替代方案吗?
-
@baio 请尽量减少对 cmets 的编辑。在您编辑了上面的评论后,我的回复不再有意义。
-
在实践中这种情况很少发生。当它打开时,消费者可以控制他们打开哪些模块,哪些不打开,如果他们真的需要同时使用这两个操作符,他们可以轻松地重命名一些操作符。但你是对的:实际上,运营商很少是一个好主意。您应该避免创建自己的运算符,当您确定要这样做时,应该将它们放在单独的模块中。
标签: f# monads custom-operator