Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.net F#用于多种类型的通用中缀运算符(fmap、applicative、bind等)_.net_F#_Infix Notation_Infix Operator - Fatal编程技术网

.net F#用于多种类型的通用中缀运算符(fmap、applicative、bind等)

.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 =

我想做的是使用中缀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 = 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