我想要做的是使用中缀fmap(我定义为< ^>)为多种类型工作,如Option和Either(自定义类型)。F#针对多种类型的常见中缀运算符(fmap,applicative,bind等)
考虑:
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
这几乎工程,但只有一个可以在同一时间使用。 任一模块也可以附加到FSharp.Core,但同样你也只能有一个或另一个。
我知道这可以用2个自定义类型完成,比如Either和Maybe(Haskell选项),但是我会坚持使用Option。
欢迎任何和所有建议。
我没有足够的经验来回答您的主要问题,但你是否知道F#的['Choice'型]的(https://msdn.microsoft.com /en-us/visualfsharpdocs/conceptual/core.choice%5B't1,'t2%5D-union-%5Bfsharp%5D)?这是与'Either'等价的内置等价物。或者,如果Left表示“失败”的情况,而Right表示“成功”的情况,那么F#等价物就是['Result'类型](https://github.com/fsharp/fslang-design/blob/master/FSharp -4.1/FS-1004-result-type.md),自F#4.1开始提供。 – rmunn
你可能想看看[F#+](https://github.com/gusty/FSharpPlus),它已经这样做了,尽管''fmap''的运算符是''<< |''( FParsec中使用相同的运算符)。您还将''绑定为''>> =''和应用程序''''和''<*>''。如果你看源代码,你会看到它是如何实现的,这是对@TheInnerLight – Gustavo
@Gustavo答案在下面的答案中解释的技术的改进好点,我已经添加到我的答案。 – TheInnerLight