【发布时间】:2020-05-30 15:04:46
【问题描述】:
我想知道如何在函数式编程中建模关系。
我们以员工为例: 员工可以与 0..n 个同事建立友谊。 友谊总是相互的:如果 A 是 B 的朋友,那么 B 也是 A 的朋友。
我该如何建模?我有 3 个想法(如下所列)。他们每个人都有缺点。
第一次尝试:
type Employee =
{ name : string
friendships : Employee list
}
// My list is mutable because I want to be able to update employees.
// I suppose the same problems would occur with e. g. Elmish.
let mutable employees : Employee list = [ (* ... *) ]
(* Downsides:
Friendships are copies. Changes to an employee would have to be propagated manually.
*)
第二次尝试:
type EmployeeId = int
type Employee =
{ id : EmployeeId
name : string
friendships : EmployeeId list
}
let mutable employees : Employee list = [ (* ... *) ]
(* Downsides:
Friendships are not modeled as mutual.
When the friendship of an employee changes,
the friend's friendships don't change accordingly.
*)
第三次尝试:
type EmployeeId = int
type Friendships = list<EmployeeId * EmployeeId>
type Employee =
{ id : EmployeeId
name : string
}
let mutable employees : Employee list = [ (* ... *) ]
(* Downsides:
After deleting an employee from the list,
employeeFriendships contain invalid "references"
to the deleted Employee.
*)
这可以做得更好吗?谢谢。
【问题讨论】:
-
这类问题的最佳答案很大程度上取决于您希望如何使用这些数据。根据用例,有不同的“正确方法”。例如,如果您想显示社交圈的交互式地图,则拥有一个包含每个友谊的实际员工数据的具体化树可能很有价值。但是,如果您只想查询一个人是否是另一个人的朋友,那么只需在
Employee对象上列出朋友的 ID 就足够了。 -
我只是好奇如何建模。我试图在网上找到解释——结果相当稀疏。阅读建议表示赞赏。
-
1.什么是更好的”? 2.如果你依赖突变,它就不起作用。 3. 无论如何,这个问题实际上与函数式编程没有任何关系。您似乎实际上要求的是如何保持不变量,而不管范式如何,答案往往是封装。对于 Stack Overflow 来说,如何实现这一点将是一个很好的问题,但事实并非如此。范围太广,征求意见。
-
您希望拥有一种模型,该模型可以减少不一致的可能性,同时仍然实用。一种可能性是考虑如何在外部存储/检索数据,因为可以在内部使用相同的范例。在这种特殊情况下,拥有单独的员工和关系列表对我来说很有意义(选项 3)。也许使用
Set<EmployeeId * EmployeeId>并确保始终存储元组以避免重复/歧义。在这种情况下,您指出的不利因素是不可避免的,但并不严重。 -
选项1造成了很多冗余,维护非常困难并且造成不一致的可能性非常高。选项 2 也可能在一名员工与另一名员工的言论之间存在不一致(尽管这会使其更加真实!)。
标签: functional-programming f# modeling