.net F#用于多种类型的通用中缀运算符(fmap、applicative、bind等)
我想做的是使用中缀fmap(我已经定义为)来处理多种类型,比如Option和other(自定义类型) 鉴于:.net F#用于多种类型的通用中缀运算符(fmap、applicative、bind等),.net,f#,infix-notation,infix-operator,.net,F#,Infix Notation,Infix Operator,我想做的是使用中缀fmap(我已经定义为)来处理多种类型,比如Option和other(自定义类型) 鉴于: type Either<'a, 'b> = Left of 'a | Right of 'b type one=a的左边| b的右边 在代码中,我希望能够做到: let fO (a : int option) = None let fE (a : Either<string,int>) = Left "dummy" let mO =
type Either<'a, 'b> = Left of 'a | Right of 'b
type one=a的左边| 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
让fO(a:int选项)=无
设fE(a:任一)=左“虚拟”
设mO=1
让我=对1
设testO=f0 m0
让我试试
其中()分别适用于:
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
let()fm=将m与| Some a->Some None匹配
让()fm=将m与| Right a->Right-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 ()
名称空间Microsoft.FSharp.Core
[]
模块选项=
让()fm=将m与| Some a->Some None匹配
[]
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
type one=a的左边| b的右边
静态成员()(f,m)=将m与| Right a->Right Left a匹配
这几乎是可行的,但是一次只能使用一个。
也可以将任意一个模块附加到FSharp.Core,但同样地,您只能有一个或另一个模块
我知道这可以用两种自定义类型来完成,比如说,要么,也许(Haskell选项),但是我想坚持使用选项
欢迎任何建议。这并不是很容易用F#表示的,唯一的方法是使用静态解析的类型参数,通常认为它不是惯用的 对于新的自定义类型,这样做非常容易,但将其改装为现有类型则更为复杂。支持这两个方面又有点困难了 您可以继续的方法是使用为现有类型硬编码的静态方法创建一个区分大小写的联合的帮助器类型:
type Functor = Functor
with
static member FMap (Functor, mapper : 'T -> 'U, opt : Option<'T>) : Option<'U> =
Option.map mapper opt
static member FMap (Functor, mapper : 'T -> 'U, ch : Choice<'T, _>) : Choice<'U, _> =
match ch with
|Choice1Of2 v -> Choice1Of2 (mapper v)
|Choice2Of2 v -> Choice2Of2 v
注意到^b或^a
条件吗?这也为我们提供了一种将这种行为插入自定义类型的方法
type Either<'a, 'b> = Left of 'a | Right of 'b with
static member FMap (Functor, f, m) =
match m with | Right a -> Right <| f a | Left a -> Left a
type one=a的左边| b的右边
静态成员FMap(函子,f,m)=
将m与| Right a->Right Left a匹配
对于运算符窗体,只需定义:
let inline (<^>) f x = fmap f x
let inline()fx=fmap fx
最终定义了以下函数:
val inline fmap :
f:( ^c -> ^d) -> x: ^a -> ^e
when (Functor or ^a) : (static member FMap : Functor * ( ^c -> ^d) * ^a -> ^e)
val inline ( <^> ) :
f:( ^a -> ^b) -> x: ^c -> ^d
when (Functor or ^c) : (static member FMap : Functor * ( ^a -> ^b) * ^c -> ^d)
val内联fmap:
f:(^c->^d)->x:^a->^e
当(函子或^a):(静态成员FMap:函子*(^c->^d)*^a->^e)
val inline():
f:(^a->^b)->x:^c->^d
当(函子或^c):(静态成员FMap:函子*(^a->^b)*^c->^d)
现在,您可以使用
操作符执行此类操作:
let x = (fun x -> x + 1) <^> (Some 1)
let x' = (fun x -> x + 1) <^> (None)
let z<'a> : Either<'a, _> = (fun x -> x + 2) <^> (Right 2)
let z' = (fun x -> x + 2) <^> (Left 5)
让x=(乐趣x->x+1)(一些1)
设x'=(乐趣x->x+1)(无)
设z=(乐趣x->x+2)(右2)
让z'=(有趣的x->x+2)(左5)
您还可以查看许多标准功能抽象的更完整的实现。完整性,最终实现
type Functor = Functor
with
static member FMap (Functor, mapper : 'T -> 'U, opt : Option<'T>) : Option<'U> =
Option.map mapper opt
static member FMap (Functor, mapper : 'T -> 'U, ch : Choice<'T, _>) : Choice<'U, _> =
match ch with
|Choice1Of2 v -> Choice1Of2 (mapper v)
|Choice2Of2 v -> Choice2Of2 v
type Applicative = Applicative
with
static member Apply (Applicative, mapperInContext : Option<('T -> 'U)>, opt : Option<'T>) : Option<'U> =
match mapperInContext with | Some mapper -> Option.map mapper opt | _ -> None
static member Apply (Applicative, mapperInContext : Choice<_,_>, ch : Choice<'T,_>) : Choice<'U,_> =
match mapperInContext with
| Choice1Of2 mapper ->
match ch with
|Choice1Of2 v -> Choice1Of2 (mapper v)
|Choice2Of2 v -> Choice1Of2 v
| Choice2Of2 v -> Choice2Of2 v
let inline fmap (f : ^c -> ^d ) (x : ^a) =
((^b or ^a) : (static member FMap : ^b * ( ^c -> ^d ) * ^a -> ^e ) (Functor, f, x))
let inline applicative (mf : ^f ) (x : ^a) =
((^b or ^a) : (static member Apply : ^b * ^f * ^a -> ^e ) (Applicative, mf, x))
let inline (<^>) f x = fmap f x
let inline (<*>) m x = applicative m x
type Either<'a, 'b> = Left of 'a | Right of 'b with
static member FMap (Functor, f, m) =
match m with | Right a -> Right <| f a | Left a -> Left a
static member Apply (Applicative, fa, x) = match fa with | Right f -> Either<_, _>.FMap(Functor, f, x) | Left e -> Left e
类型函子=函子
具有
静态成员FMap(函子,映射器:'T->'U,opt:Option=
Option.map映射器opt
静态成员FMap(函子,映射器:'T->'U,ch:Choice=
匹配
|选择1OF2 v->选择1OF2(映射器v)
|选择2of2 v->选择2of2 v
类型Applicative=Applicative
具有
静态成员应用(应用程序,映射上下文:选项,选项:选项=
将mapperContext与| Some mapper->Option.map mapper opt | |->None匹配
静态成员应用(应用程序,映射上下文:选择,ch:选择=
将映射上下文与匹配
|Choice1Of2映射器->
匹配
|选择1OF2 v->选择1OF2(映射器v)
|选择2伏->选择1伏
|选择2of2 v->选择2of2 v
让内联fmap(f:^c->^d)(x:^a)=
(^b或^a):(静态成员FMap:^b*(^c->^d)*^a->^e)(函子,f,x))
让内联应用程序(mf:^f)(x:^a)=
(^b或^a):(静态成员应用:^b*^f*^a->^e)(应用的,mf,x))
设inline()fx=fmap fx
让内联()mx=应用的mx
类型或=a的左侧| b的右侧,带有
静态成员FMap(函子,f,m)=
将m与| Right a->Right Left a匹配
静态成员Apply(Applicative,fa,x)=将fa与| Right f->one.FMap(Functor,f,x)| Left e->Left e匹配
我没有足够的经验来回答你的主要问题,但是你知道F#’s吗?它是内置的,相当于。或者如果左表示“失败”,右表示“成功”在这种情况下,F#等价物是从F#4.1开始提供的。您可能想看看哪个已经做到了这一点,尽管fmap
的操作符是=
,而应用程序是
和
。如果您查看源代码,您将看到它是如何实现的,这是对中解释的技术的改进下面的答案是@TheInnerLight@Gustavo好的一点,我已经在我的答案中添加了这一点。Thx真的很有帮助,我正在尝试将这一想法扩展到applicative,但它不太管用。我如何定义让内联fmap(f:^c->^d)(x:^a)=((^b或^a):(应用程序的静态成员FMap:^b*(^c->^d)*^a->^e)(函子,f,x))
?不确定如何编写f:^c->^d
以处理上下文中的函数(可选).My实现似乎可以使用Option和Choice工作,但两者都不能。@在注释中很难提供一个工作的实现,但是自定义的Orther
实现对于apply应该是这样的:static member apply(Applicative,fa,x)=将fa与| Right f->other.FMap(Functor,f,x)匹配| Left e->Left e
为什么必须将函子类型传递给FMap实现。这与解决内联方法约束有关吗?@ThomasDevries是的,我们只是利用type Functor = Functor
with
static member FMap (Functor, mapper : 'T -> 'U, opt : Option<'T>) : Option<'U> =
Option.map mapper opt
static member FMap (Functor, mapper : 'T -> 'U, ch : Choice<'T, _>) : Choice<'U, _> =
match ch with
|Choice1Of2 v -> Choice1Of2 (mapper v)
|Choice2Of2 v -> Choice2Of2 v
type Applicative = Applicative
with
static member Apply (Applicative, mapperInContext : Option<('T -> 'U)>, opt : Option<'T>) : Option<'U> =
match mapperInContext with | Some mapper -> Option.map mapper opt | _ -> None
static member Apply (Applicative, mapperInContext : Choice<_,_>, ch : Choice<'T,_>) : Choice<'U,_> =
match mapperInContext with
| Choice1Of2 mapper ->
match ch with
|Choice1Of2 v -> Choice1Of2 (mapper v)
|Choice2Of2 v -> Choice1Of2 v
| Choice2Of2 v -> Choice2Of2 v
let inline fmap (f : ^c -> ^d ) (x : ^a) =
((^b or ^a) : (static member FMap : ^b * ( ^c -> ^d ) * ^a -> ^e ) (Functor, f, x))
let inline applicative (mf : ^f ) (x : ^a) =
((^b or ^a) : (static member Apply : ^b * ^f * ^a -> ^e ) (Applicative, mf, x))
let inline (<^>) f x = fmap f x
let inline (<*>) m x = applicative m x
type Either<'a, 'b> = Left of 'a | Right of 'b with
static member FMap (Functor, f, m) =
match m with | Right a -> Right <| f a | Left a -> Left a
static member Apply (Applicative, fa, x) = match fa with | Right f -> Either<_, _>.FMap(Functor, f, x) | Left e -> Left e