使用计算表达式时,第一个定义有效,但第二个定义不适用于Zero.
这有什么区别:
member o.Zero() = 3
Run Code Online (Sandbox Code Playgroud)
还有这个:
member o.Zero = fun() -> 3
Run Code Online (Sandbox Code Playgroud)
第一个评估到unit -> int第二个评估(unit -> int).有什么不同?
在我试图实现的计算表达式下面.该值包含在元组中,其中元组的第二项是表示沿途日志条目的字符串列表.
type LoggerBuilder() =
member this.Bind(vl : 'a * string list, f) =
let value = vl |> fst
let logs = vl |> snd
let appendLogs logs tpl =
let value = vl |> fst
let log = vl |> snd
(value, logs |> List.append log)
(f value) |> appendLogs logs
member this.Return(x) =
(x, [])
Run Code Online (Sandbox Code Playgroud)
但是,当我运行以下内容时,我没有得到预期的结果.我想知道我错过了哪里.
let log = new LoggerBuilder()
let a = log {
let! a = (1, ["assign 1"])
let! b = (2, ["assign 2"]) …Run Code Online (Sandbox Code Playgroud) 我正在学习F#并且遇到一些绊脚石; 我认为很多是学习功能性思考.
我目前正在学习的一件事是计算表达式,我希望能够定义一个处理某些跟踪状态的计算表达式,例如:
let myOptions = optionListBuilder {
let! opt1 = {name="a";value=10}
let! opt2 = {name="b";value=12}
}
Run Code Online (Sandbox Code Playgroud)
我希望能够拥有它,这样myOptions是一个Option<'T> list,所以每个let!绑定操作有效地使建设者"跟踪"的定义选项,它会沿着.
我不想使用可变状态来执行此操作 - 例如,使用由构建器维护的列表并使用每个bind调用进行更新.
有没有办法让它成为可能?
更新:结果Option<'T> list类型只是代表性的,实际上我可能有一个OptionGroup<'T>类型来包含列表以及一些其他信息 - 正如Daniel在下面提到的,我可以使用列表理解来获得一个简单的列表.
我目前正在研究神话般的fsharpforfunandprofit网站的计算表达系列,我对计算系列的第4课"包装类型"有疑问.我已经尝试了进一步阅读,但有一个重要的概念,我没有抓住.
实际上,我确实理解bind的定义:
member Bind : M<'T> * ('T -> M<'U>) -> M<'U>
Run Code Online (Sandbox Code Playgroud)
但有一件事我不明白是在使用它时在计算表达式中使用它的魔力!:
例如:
let product'' =
dbresult {
let! custId = getCustomerId "Alice"
let! orderId = getLastOrderForCustomer "" // error!
let! productId = getLastProductForOrder orderId
printfn "Product is %s" productId
return productId
}
printfn "%A" product''
Run Code Online (Sandbox Code Playgroud)
getCustomerId"Alice"给我回M <'T>,但是custId 已经是打开过的'T,我无法看到这个魔术怎么工作......
它是隐藏在let中的代码的一部分!Fsharp核心组件内的指令?有人可以向我解释这是怎么回事!从包装中取出T'?
谢谢你的解释
不完全确定标题描述没问题,但我确实有以下代码:
paket.dependencies:
source https://www.nuget.org/api/v2
nuget fsharpx.extras
nuget mongodb.driver
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
这个"excersise"的意思是编写GetDB2,以便它与GetDB1一样,但使用运算符(applicatives?),但我现在无法转过头去管理它.
上面的代码编译,但对于GetDB1和GetDB2签名是不相等的,和Im显然做一些不正确的.
val GetDB1 : …Run Code Online (Sandbox Code Playgroud) 我正在尝试研究如何使用计算构建器来表示延迟的嵌套步骤集.
到目前为止我有以下内容:
type Entry =
| Leaf of string * (unit -> unit)
| Node of string * Entry list * (unit -> unit)
type StepBuilder(desc:string) =
member this.Zero() = Leaf(desc,id)
member this.Bind(v:string, f:unit->string) =
Node(f(), [Leaf(v,id)], id)
member this.Bind(v:Entry, f:unit->Entry) =
match f() with
| Node(label,children,a) -> Node(label, v :: children, a)
| Leaf(label,a) -> Node(label, [v], a)
let step desc = StepBuilder(desc)
let a = step "a" {
do! step "b" {
do! step "c" {
do! step …Run Code Online (Sandbox Code Playgroud) 我在F#中遇到了关于"厄运金字塔"的问题.接受的答案涉及使用Active Patterns,但我的理解是它也可以使用Computation Expressions解决.
如何使用Computation Expressions从此代码中删除"厄运金字塔"?
match a.TryGetValue(key) with
| (true, v) -> v
| _ ->
match b.TryGetValue(key) with
| (true, v) -> v
| _ ->
match c.TryGetValue(key) with
| (true, v) -> v
| _ -> defaultValue
Run Code Online (Sandbox Code Playgroud) 我正在尝试使用免费的monad模式构建用于消息处理的管道,我的代码看起来像这样:
module PipeMonad =
type PipeInstruction<'msgIn, 'msgOut, 'a> =
| HandleAsync of 'msgIn * (Async<'msgOut> -> 'a)
| SendOutAsync of 'msgOut * (Async -> 'a)
let private mapInstruction f = function
| HandleAsync (x, next) -> HandleAsync (x, next >> f)
| SendOutAsync (x, next) -> SendOutAsync (x, next >> f)
type PipeProgram<'msgIn, 'msgOut, 'a> =
| Act of PipeInstruction<'msgIn, 'msgOut, PipeProgram<'msgIn, 'msgOut, 'a>>
| Stop of 'a
let rec bind f = function
| Act x -> x |> …Run Code Online (Sandbox Code Playgroud) f# asynchronous computation-expression async-await free-monad
我希望下面的示例计算表达式和值返回 6。对于某些数字并没有像我期望的那样产生。我缺少获得结果的步骤是什么?谢谢!
type AddBuilder() =
let mutable x = 0
member _.Yield i = x <- x + i
member _.Zero() = 0
member _.Return() = x
let add = AddBuilder()
(* Compiler tells me that each of the numbers in add don't do anything
and suggests putting '|> ignore' in front of each *)
let result = add { 1; 2; 3 }
(* Currently the result is 0 *)
printfn "%i should be 6" result
Run Code Online (Sandbox Code Playgroud)
注意:这只是为了创建我自己的计算表达式来扩展我的学习。Seq.sum将是一个更好的方法。我对这个例子完全忽略了计算表达式的价值并且不利于学习的想法持开放态度。
我正在创建一个用于建模的 DSL,并且我希望能够创建一个Settings具有两个自定义操作的构建器:Buffer和Constraint,它们本身就是计算表达式。原因是该域中的术语严重过载,而计算表达式允许您通过使用自定义操作来提供上下文。
我不知道如何让这种嵌套按预期工作。我在代码示例的底部提供了一个示例,说明了我想要的结果。
type Buffer =
{
Name : string
Capacity : float
}
type Constraint =
{
Name : string
Limit : float
}
[<RequireQualifiedAccess>]
type Setting =
| Buffer of Buffer
| Constraint of Constraint
type BufferBuilder (name: string) =
member _.Yield _ : Buffer = { Name = name; Capacity = 0.0 }
member _.Run x : Buffer = x
[<CustomOperation("Capacity")>]
member _.Capacity (b: Buffer, newCapacity) =
{ b with Capacity …Run Code Online (Sandbox Code Playgroud)