F# 如何避免对Actor实例的可变引用
我正试图在F#中获得一些与Akka.NET演员合作的经验。我有这样一个场景,一个演员需要把另一个演员演成他的孩子。第一个参与者将转换每条消息,然后将结果发送给另一个参与者。我使用F# 如何避免对Actor实例的可变引用,f#,immutability,actor,akka.net,F#,Immutability,Actor,Akka.net,我正试图在F#中获得一些与Akka.NET演员合作的经验。我有这样一个场景,一个演员需要把另一个演员演成他的孩子。第一个参与者将转换每条消息,然后将结果发送给另一个参与者。我使用actorOf2函数生成演员。这是我的密码: let actor1 work1 work2 = let mutable actor2Ref = null let imp (mailbox : Actor<'a>) msg = let result = work1 msg if acto
actorOf2
函数生成演员。这是我的密码:
let actor1 work1 work2 =
let mutable actor2Ref = null
let imp (mailbox : Actor<'a>) msg =
let result = work1 msg
if actor2Ref = null then
actor2Ref <- spawn mailbox.Context "decide-actor" (actorOf2 <| work2)
actor2Ref <! result
imp
let actor1Ref = actor1 work1' work2'
|> actorOf2
|> spawn system "my-actor"
让actor1工作1工作2=
设可变actor2Ref=null
让imp(mailbox:Actormailbox.Context
生成一个子角色,在第一次调用之前我没有任何上下文。我看到了,但我不知道如何将其应用于我的函数
在一个更高级的场景中,我需要一个由键划分的子参与者集合。在这个场景中,我使用的是参与者引用字典。是否有更好的(更富F#ish)方法?为了在迭代过程中保持“状态”,您需要显式地进行迭代。这样,您可以传递当前的“状态”作为尾部调用参数。正如您链接的问题中所述:
let actor1 work1 work2 (mailbox : Actor<'a>) =
let rec imp actor2 =
actor {
let! msg = mailbox.Receive()
let result = work1 msg
let actor2 =
match actor2 with
| Some a -> a // Already spawned on a previous iteration
| None -> spawn mailbox.Context "decide-actor" (actorOf2 <| work2)
actor2 <! result
return! imp (Some actor2)
}
imp None
.编辑
如果您担心额外的样板文件,那么没有什么可以阻止您将样板文件作为函数打包(毕竟,
actorOf2
):
让ActorofithState(f:Actor'msg->'状态)(initialState:'状态)邮箱=
让rec imp state=
演员{
let!msg=mailbox.Receive()
让newState=f邮箱状态msg
返回!imp newState
}
imp初始状态
然后:
let actor1 work1 work2 (mailbox : Actor<'a>) actor2 msg =
let result = work1 msg
let actor2 =
match actor2 with
| Some a -> a
| None -> spawn mailbox.Context "decide-actor" (actorOf2 work2)
actor2 <! result
actor2
let actor1Ref =
actor1 work1' work2'
|> actorOfWithState
|> spawn system "my-actor"
让actor1工作1工作2(mailbox:Actor您可以按照这些思路做一些事情,而不存储对子Actor的引用,因为上下文已经在为您做这些了
let actor =
let ar = mailbox.Context.Child(actorName)
if ar.IsNobody() then
spawn mailbox.Context actorName handler
else ar
如果Context.Child查找速度太慢,那么创建一个记忆化函数,使可变性不被其他代码发现将非常容易。是的,我想到了这个选项,但是与我的函数相比,这个带有显式接收和参与者工作流的模板更像样板。而且更难进行单元测试。是的,有些更多的样板文件,但没有它,您就无法维护状态。想想看:如果您的函数不接受任何表示状态的参数,那么它所能做的就是依赖可变环境。我已经更新了答案,以回应您的担忧。
let actor1 work1 work2 (mailbox : Actor<'a>) actor2 msg =
let result = work1 msg
let actor2 =
match actor2 with
| Some a -> a
| None -> spawn mailbox.Context "decide-actor" (actorOf2 work2)
actor2 <! result
actor2
let actor1Ref =
actor1 work1' work2'
|> actorOfWithState
|> spawn system "my-actor"
let actor =
let ar = mailbox.Context.Child(actorName)
if ar.IsNobody() then
spawn mailbox.Context actorName handler
else ar