pla*_*ist 5 recursion f# record
假设你有以下递归记录类型
type Parent = {
Name : string
Age : int
Children : Child list }
and Child = {
Name : string
Parent : Parent option }
Run Code Online (Sandbox Code Playgroud)
我可以轻松地创建实例
module Builder =
let create name kids =
let rec makeChild kid = { kid with Parent = parent |> Some }
and parent =
{
Name = name
Age = 42
Children = children
}
and children = kids |> List.map makeChild
parent
let createChild name =
{ Child.Name = name; Parent = None }
Run Code Online (Sandbox Code Playgroud)
但当我尝试使用"with"将现有成人"转化"为父母时:
module Builder2 =
let createAdult name age =
{ Parent.Name = name; Age = age; Children = [] }
let create name kids =
let rec makeChild kid = { kid with Parent = parent |> Some }
and parent =
{ (createAdult name 42) with
Children = children
}
and children = kids |> List.map makeChild
parent
let createChild name =
{ Child.Name = name; Parent = None }
Run Code Online (Sandbox Code Playgroud)
我明白了:
错误FS0040:将通过使用延迟引用在运行时检查对定义的对象的此递归引用和其他递归引用的初始化 - 健全性.这是因为您定义了一个或多个递归对象,而不是递归函数.使用'#nowarn"40"'或'--nowarn:40'可以抑制此警告.
并突出显示"父"定义中的"Children = children".
我究竟做错了什么?
编辑:
还有一点:当我将"Builder"(有效)移动到另一个组件(例如测试组件)时,它立即停止工作:
错误FS0261:递归值不能直接分配给递归绑定中"父"类型的非可变字段"Children".考虑使用可变字段.
编辑: 基于我试过的评论
let create name kids =
let rec makeChild kid = { kid with Parent = parent |> Some }
and adult = createAdult name 42
and parent =
{ adult with Children = children }
and children = kids |> List.map makeChild
Run Code Online (Sandbox Code Playgroud)
但仍然没有运气 - 编译器仍然没有看到这个用例与工作类似:(
cartermp 在这里找到并发布了解决方案:
https://github.com/Microsoft/visualfsharp/issues/4201
我在这里发布了一个复制品
https://github.com/plainionist/DevNull/tree/master/src/FSharpCopyRecordRecursive
当然,所提出的解决方案很有魅力