【发布时间】:2018-01-25 15:49:19
【问题描述】:
我想做的是使用中缀 fmap(我定义为 )来处理多种类型,例如 Option 和 Either(自定义类型)。
给定:
type Either<'a, 'b> = Left of 'a | Right of 'b
在代码中我希望能够做到:
let fO (a : int option) = None
let fE (a : Either<string,int>) = Left "dummy"
let mO = Some 1
let mE = Right 1
let testO = f0 <^> m0
let testE = fE <^> mE
每个位置 ():
let (<^>) f m = match m with | Some a -> Some <| f a | None -> None
let (<^>) f m = match m with | Right a -> Right <| f a | Left a -> Left a
为了让选项 工作,我扩展了模块:
namespace Microsoft.FSharp.Core
[<AutoOpen>]
module Option =
let (<^>) f m = match m with | Some a -> Some <| f a | None -> None
[<assembly:AutoOpen("Microsoft.FSharp.Core")>]
do ()
对于任何一个:
type Either<'a, 'b> = Left of 'a | Right of 'b with
static member (<^>) (f,m) = match m with | Right a -> Right <| f a | Left a -> Left a
这几乎可以工作,但是一次只能使用一个。 一个 Either 模块也可以附加到 FSharp.Core,但同样你只能拥有一个或另一个。
我知道这可以通过 2 种自定义类型来完成,比如 Either 和 Maybe(Haskell 选项),但我想坚持使用 Option。
欢迎提出任何建议。
【问题讨论】:
-
我没有足够的经验来回答你的主要问题,但你知道 F# 的
Choicetype 吗?它是Either的内置等效项。或者,如果 Left 代表“失败”案例,Right 代表“成功”案例,则 F# 等价物是Resulttype,自 F# 4.1 起可用。 -
您可能想看看 F#+ 已经这样做了,尽管
fmap的运算符是<<|(在 FParsec 中使用相同的运算符)。您还拥有bind和>>=以及应用程序<!>和<*>。如果您查看源代码,您会看到它是如何实现的,这是对@TheInnerLight 下面的答案中解释的技术的改进 -
@Gustavo 好点,我已将其添加到我的答案中。
标签: .net f# infix-notation infix-operator