【发布时间】:2018-03-14 05:39:14
【问题描述】:
我对函数式编程很陌生,所以这可能是由于误解而引起的问题,但我无法理解这一点 - 从 OOP 的角度来看,这似乎很明显......
场景: 假设您有一个演员或微服务之类的架构方法,其中消息/请求被发送到一些处理它们并回复的组件。现在假设,其中一个组件存储来自未来请求的请求的一些数据(例如,它计算一个值并将其存储在缓存中,以便下一次发生相同的请求时,不需要计算)。 数据可以保存在内存中。
问题: 您在一般的函数式编程中,尤其是在 f# 中如何处理这种情况?我想静态字典不是一种功能性方法,如果可能的话,我不想包含任何外部的东西,比如数据存储。
或更准确地说: 如果应用程序创建数据将在稍后的处理中再次使用,我们在哪里存储数据?
示例:您有一个应用程序对一些初始数据执行某种任务。首先,您存储初始数据(例如,将其添加到字典中),然后执行第一个基于数据子集进行一些处理的任务,然后执行 添加额外的第二个任务数据等等,直到所有任务都完成...
现在(根据我的理解)基本方法是定义数据并将任务用作某种处理链来转发处理过的数据,例如initial-data -> task-1 -> task-2 -> ... -> done
但这不适合基于消息和异步完成获取/添加数据的架构。
方法:
我最初的方法是这样的
type Record = { }
let private dummyStore = new System.Collections.Concurrent.ConcurrentBag<Record>()
let search comparison =
let matchingRecords = dummyStore |> Seq.where (comparison)
if matchingRecords |> Seq.isEmpty
then EmptyFailedRequest
else Record (matchingRecords |> Seq.head)
let initialize initialData =
initialData |> Seq.iter (dummyStore.Add)
let add newRecord =
dummyStore.Add(newRecord)
封装在一个看起来像 OOP 方法的模块中。
在@Gustavo 要求我提供一个示例并考虑他的建议后,我意识到我可以这样做(上一层到实际调用函数的地方):
let handleMessage message store =
// all the operations from above but now with Seq<Record> -> ... -> Seq<Record>
store
let agent = MailboxProcessor.Start(fun inbox->
let rec messageLoop store = async{
let! msg = inbox.Receive()
let modifiedStore = handleMessage msg store
return! messageLoop modifiedStore
}
messageLoop Seq.empty
)
这很好地回答了我的问题,因为它完全消除了可变性和共享状态。但是当只看第一种方法时,我想不出任何没有函数之外的集合的解决方案
请注意,这个问题在 f# 中是为了解释环境、语法等。我不想要一个可行的解决方案,因为 f# 是多范式,我想为此获得一个功能性的方法。
到目前为止,我已经阅读了我在 SO 上可以找到的所有问题,但它们要么证明了 理论上的可能性,要么在这种情况下使用 collections - 如果重复,请指出我是正确的方向。
【问题讨论】:
-
对于已计算的值具有静态和不可变映射/字典对于函数式编程也是可以的。您只需组合/链接到功能 1.GetFromCache 2.如果缓存不存在计算。选项类型非常适合从 GetFromCache 函数返回
-
您可能还想了解闭包是什么。
标签: f# functional-programming mutable conceptual