如果定义While构建器对象的方法,则可以while在计算表达式中使用-loops .该While方法的签名是:
member b.While (predicate:unit->bool, body:M<'a>) : M<'a>
Run Code Online (Sandbox Code Playgroud)
为了比较,该For方法的签名是:
member b.For (items:seq<'a>, body:unit->M<'a>) : M<'a>
Run Code Online (Sandbox Code Playgroud)
您应该注意到,在While-method中,body是一个简单类型,而不是方法中的函数For.
你可以let在计算表达式中嵌入一些其他语句,比如函数调用,但是那些不可能在while-loop中不可能执行多次.
builder {
while foo() do
printfn "step"
yield bar()
}
Run Code Online (Sandbox Code Playgroud)
为什么while-loop不会被执行多次,而只是重复?为什么与for循环有显着差异?更好的是,是否有一些在计算表达式中使用while循环的策略?
我正在学习F#,但有一件令我困惑的事情是计算表达式(do-notation ??)语法和desugaring.
在haskell中,你有一个非常简单的Monad类型类和desugaring do-notation到bind和return的规则.添加关键字没有任何魔力; 唯一必须匹配的是类型.
在F#中,有许多构建器,关键字和复杂性.
是否有一个很好的解释如何将一个概念映射到另一个概念?
我基本上想知道我的地图
do
x <- monadicComputation
foo x
someOtherMonadicComputation
let y = somePureComputation x
return $ bar y
Run Code Online (Sandbox Code Playgroud)
到F#.
haskell中唯一的关键字是do,(< - )和let.
在之前的一个问题中,我被告知如何重写我的计算表达式,因此它使用尾递归.我重写了我的代码,但仍然得到了StackOverflowException.为了找到问题,我使用状态monad编写了一些小代码(取自此博客条目):
type State<'a, 's> = State of ('s -> 'a * 's)
let runState (State s) initialState = s initialState
let getState = State (fun s -> (s,s))
let putState s = State (fun _ -> ((),s))
type StateBuilder() =
member this.Return a = State (fun s -> (a, s))
member this.Bind(m, k) =
State (fun s -> let (a,s') = runState m s in runState (k a) s')
member this.ReturnFrom a = a
let state …Run Code Online (Sandbox Code Playgroud) 我有以下代码尝试使用通常的MaybeBuilder从网络流中读取可能不完整的数据(例如图像数据):
let image = maybe {
let pos = 2 //Initial position skips 2 bytes of packet ID
let! width, pos = readStreamAsInt 2 pos
let! height, pos = readStreamAsInt 2 pos
let! data, pos = readStream (width*height) pos
advanceInStream pos
return {width = width; height = height; pixels = data}
}
Run Code Online (Sandbox Code Playgroud)
因此,如果数据尚未到达NetworkStream,则readStream [asInt] [numBytes] [offset]函数返回一些[data]或None.读取整个网络数据包时执行advanceInStream函数.
我想知道是否有一些方法可以编写一些自定义计算表达式构建器来隐藏来自其用户的pos,因为它始终是相同的 - 我读取了一些数据并在流中定位并将其作为最后一个参数传递给下一个读取函数.
PS MaybeBuilder使用:
type MaybeBuilder() =
member x.Bind(d,f) = Option.bind f d
member x.Return d = Some d
member x.ReturnFrom d = …Run Code Online (Sandbox Code Playgroud) 我环顾四周,努力想要得到答案; 我确信有一个明显的答案,但我似乎无法找到它; 或者我遇到了与计算表达式一起使用时无法通过的引用限制.
基本上我想使用计算F#工作流程来处理如下定义的lambda.尝试将这些工作流程组合在一起时会出现问题.理想情况下,我想使用let组合Workflow <'Env,'Result>实例!句法.我有点天真的尝试如下:
type Workflow<'Env, 'Result> = Expr<'Env -> 'Result>
type WorkflowSource<'Env, 'Result> = 'Env -> 'Result
type WorkflowBuilder() =
member x.Bind
(workflow: WorkflowSource<'Env, 'OldResult>,
selector: 'OldResult -> WorkflowSource<'Env, 'NewResult>) : WorkflowSource<'Env, 'NewResult> =
(fun env -> (selector (workflow env) env))
member x.Bind
(workflow: Workflow<'Env, 'OldResult>,
selector: 'OldResult -> WorkflowSource<'Env, 'NewResult>)
: Workflow<'Env, 'NewResult> =
<@ (fun env -> (selector ((%workflow) env) env)) @>
// This bind is where the trouble is
member x.Bind
(workflow: WorkflowSource<'Env, 'OldResult>,
selector: …Run Code Online (Sandbox Code Playgroud) 在任何控制流语句中使用af#计算表达式的自定义操作都无法进行类型检查
error FS3086: A custom operation may not be used in conjunction with 'use',
'try/with', 'try/finally', 'if/then/else' or 'match' operators within this
computation expression
Run Code Online (Sandbox Code Playgroud)
为什么不允许这样做?什么是自定义操作,不允许重写此:
expr {
if a then
custom (x)
else
return (y)
}
Run Code Online (Sandbox Code Playgroud)
这样的事情:
expr {
return!
if a then
expr { custom (x) }
else
expr { return (y) }
}
Run Code Online (Sandbox Code Playgroud) 在F#中,我们有计算表达式,它可以在各种计算环境(异步,选项等)中工作时减少样板和嵌套.
我一直在玩F#(也就是计算表达式)中的monads,我写了这个简单的Identity monad:
type Identity<'a> =
| Identity of 'a
type IdentityBuilder() =
member x.Bind (Identity v) f = f(v)
member x.Return v = Identity v
let identity = new IdentityBuilder()
let getInt() = identity { return Int32.Parse(Console.ReadLine()) }
let calcs() = identity {
let! a = getInt() // <- I get an error here
let! b = getInt()
return a + b }
Run Code Online (Sandbox Code Playgroud)
我不明白我在标记的行中得到的错误:
该表达式应该具有Identity <'a>类型,但这里的类型为'b*'c
我认为这没有任何意义,因为getInt()显然是类型的值Identity<'a>.
谁能告诉我我做错了什么?
现在我正在尝试 F# 计算表达式。总体思路是返回控制机制来驱动从计算表达式构建递归函数调用的每一步之后执行的操作。整个例子可以在这里看到。
使用以下示例:
let rec loop () =
actor {
let! msg = m.Receive ()
match msg with
| "stop" -> return 0 // expected result: Return (0)
| "unhandled" -> unhandled // expected result: Unhandled
| x ->
mailbox.Sender() <! x
return! loop () // expected result: (Become(fun m -> loop ()))
}
loop ()
Run Code Online (Sandbox Code Playgroud)
不幸的是,这以编译时错误结束unhandled:在此计算中,自定义操作可能无法与“use”、“try/with”、“try/finally”、“if/then/else”或“match”运算符结合使用表达。
是否可以以任何方式在匹配语句中使用自定义运算符?
我想为我的计算表达式构建器添加对此构造的支持:
let f =
foo {
let! x =
foo {
return 1
}
and! y =
foo {
return 2
}
return x + y
}
Run Code Online (Sandbox Code Playgroud)
编译器说我必须实现Bind2or MergeSource。但是,我在文档中找不到它们。
这些应该有什么签名?你能举一个简单的例子吗?