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
F# 计算表达式与应用函子的比较_F#_Monads_Computation Expression_Fsharpx - Fatal编程技术网

F# 计算表达式与应用函子的比较

F# 计算表达式与应用函子的比较,f#,monads,computation-expression,fsharpx,F#,Monads,Computation Expression,Fsharpx,不完全确定标题是否描述了它,但我确实了解以下代码: paket.dependencies: source https://www.nuget.org/api/v2 nuget fsharpx.extras nuget mongodb.driver some.fsx: #r @".\packages\MongoDB.Bson\lib\net45\MongoDB.Bson.dll" #r @".\packages\MongoDB.Driver\lib\net45\MongoDB.Driver.dl

不完全确定标题是否描述了它,但我确实了解以下代码:

paket.dependencies:

source https://www.nuget.org/api/v2
nuget fsharpx.extras
nuget mongodb.driver
some.fsx:

#r @".\packages\MongoDB.Bson\lib\net45\MongoDB.Bson.dll"
#r @".\packages\MongoDB.Driver\lib\net45\MongoDB.Driver.dll"
#r @".\packages\MongoDB.Driver.Core\lib\net45\MongoDB.Driver.Core.dll"

#r @".\packages\FSharpX.Extras\lib\net45\FSharpX.Extras.dll"


open MongoDB
open MongoDB.Driver
open MongoDB.Bson 
open MongoDB.Bson.Serialization

open FSharpx.Choice

let private createClient (connectString:string) = MongoClient(connectString)
let CreateClient = protect createClient

let private getDb name (client:IMongoClient) = client.GetDatabase(name)
let GetDB1 name client =
    choose {
        let! c = client
        return! (protect (getDb name) c)
    }

let GetDB2 name (client:Choice<IMongoClient, exn>) =
    protect (getDb name)
    <!> client
#r@.\packages\MongoDB.Bson\lib\net45\MongoDB.Bson.dll
#r@“\packages\MongoDB.Driver\lib\net45\MongoDB.Driver.dll”
#r@“\packages\MongoDB.Driver.Core\lib\net45\MongoDB.Driver.Core.dll”
#r@“\packages\FSharpX.Extras\lib\net45\FSharpX.Extras.dll”
开放MongoDB
打开MongoDB驱动程序
打开MongoDB.Bson
打开MongoDB.Bson.Serialization
打开FSharpx.Choice
让私有createClient(connectString:string)=MongoClient(connectString)
让CreateClient=保护CreateClient
让私有getDb名称(客户端:IMongoClient)=client.GetDatabase(名称)
让GetDB1命名客户端=
选择{
设!c=客户机
return!(protect(getDb name)c)
}
让GetDB2命名(客户机:选择)=
保护(getDb名称)
客户
这个“练习”的要点是编写GetDB2,使其与GetDB1相同,但使用操作符(applicatives?),但目前我还不能回头来管理它

上面的代码可以编译,但是 GetDB1和GetDB2不相等,我显然做了一些不正确的事情

val GetDB1 :
  name:string ->
    client:Choice<#MongoDB.Driver.IMongoClient,exn> ->
      Choice<MongoDB.Driver.IMongoDatabase,exn>

val GetDB2 :
  name:string ->
    client:Choice<MongoDB.Driver.IMongoClient,exn> ->
      Choice<Choice<MongoDB.Driver.IMongoDatabase,exn>,exn>
val GetDB1:
名称:字符串->
客户:选择->
选择
val GetDB2:
名称:字符串->
客户:选择->
选择
我在GetDB2中尝试了几个版本和操作顺序,但我或多或少都会以上面的签名结束

我最初的想法是编写一些小函数来完成它们应该做的事情,然后添加异常处理(protect),然后相应地“wrap”和“unwrap”

这当然也可能不是完全正确的想法

有人能在这里为我指出一些进一步研究、代码示例或其他方面的方向吗?在这一点上,任何类型的评论实际上都是受欢迎的;-)

附录

我认为以下内容应该与上面的内容大致相同,但是没有mongodb依赖项

#r @".\packages\FSharpX.Extras\lib\net45\FSharpX.Extras.dll"

type DataBase = 
    {
        Name: string
    }

type Client = 
    {
        connectString: string
    } with member this.GetDatabase name = {
                        Name = name
                    }

open FSharpx.Choice
let private createClient (connectString:string) = {
  connectString= connectString
}

let CreateClient = protect createClient

let private getDb name (client:Client) = client.GetDatabase name

let GetDB1 name client =
    choose {
        let! c = client
        return! (protect (getDb name) c)
    }

let GetDB2 name client =
    protect (getDb name)
    <!> client
#r@.\packages\FSharpX.Extras\lib\net45\FSharpX.Extras.dll
类型数据库=
{
名称:string
}
类型客户端=
{
连接字符串:字符串
}使用成员this.GetDatabase名称={
Name=Name
}
打开FSharpx.Choice
让私有createClient(connectString:string)={
connectString=connectString
}
让CreateClient=保护CreateClient
让私有getDb名称(客户端:client)=client.GetDatabase名称
让GetDB1命名客户端=
选择{
设!c=客户机
return!(protect(getDb name)c)
}
让GetDB2命名客户端=
保护(getDb名称)
客户

您在这里得到的是类型的复合,因为您使用了
操作符,即
map
。定义如下:

let map f = function
    | Choice1Of2 value = Choice1Of2 (f value)
    | Choice2Of2 fail  = Choice2Of2 fail
let bind f = function
    | Choice1Of2 value = f value
    | Choice2Of2 fail  = Choice2Of2 fail
let protect f x =
    try
        Choice1Of2 (f x)
    with
        exn -> Choice2Of2 exn
它具有签名
('T->'U)->Choice->Choice
,即函数
f
用作
Choice
类型内的映射。例如:

map (sprintf "%d")
具有类型
选项
。这对于应用不使用
选项
类型的函数很有用-只有一个可能的故障点,并且在调用
映射
之前发生

但是,您的下一个函数将生成一个
选项
类型,但它将使用一个非
选项
类型。这意味着您希望错误通过传播-如果值中存在错误,请选择该值。如果该值很好,但函数中有错误,则使用该值。如果一切都成功了,就用它。这要求两种错误类型相同,对您来说是(
exn

这是对绑定操作的描述,定义如下:

let map f = function
    | Choice1Of2 value = Choice1Of2 (f value)
    | Choice2Of2 fail  = Choice2Of2 fail
let bind f = function
    | Choice1Of2 value = f value
    | Choice2Of2 fail  = Choice2Of2 fail
let protect f x =
    try
        Choice1Of2 (f x)
    with
        exn -> Choice2Of2 exn
签名
('T->Choice)->Choice->Choice

请注意,
bind
map
非常相似,只是后者将结果提升到
选项1of2
-映射函数总是成功的

在FSharpX中,您可以通过
|>
-like操作符
>=
'T->Choice
访问
绑定
,因为
映射
选项
中工作 不过,你想要的是

let GetDB name client =
    bind (protect (getDb name)) client
或者以操作员的形式

let GetDB name client = client >>= protect (getDb name)

通常,如果映射函数具有签名
'T->'U
,则需要
map
。如果它有
'T->Choice
,您需要
bind

您可以将其表示为一个?我不想为了研究这个问题而去摆弄MongoDB……顺便说一句,在F#
中,Haskell的
经常被用来代替,后者在F#中不是合法的操作员。它只是Haskell中
map
fmap
)的中缀版本。@MarkSeemann-hehe。事实上是MCVE。或者说:不需要在这里摆弄mongos;-)如果pakets已安装到位,则上述操作将在未安装任何mongodb或未进行任何修改的情况下运行。但是我会尝试对bone MCVE做更多的工作…我想你需要类似于
(=我明白了。我不知道我是否能给出有用的解释,但是
>=
只是“只是”标准绑定操作符,它与
返回
/
一起定义了一个单子。在F#计算表达式中。