这个递归绑定使用了无效的递归形式混合



下面的代码导致编译器错误,"FS0695:此递归绑定使用了递归形式的无效混合。"

type Parent =
    { ParentName : string
      Children : Child list }
and Child = 
    { ChildName : string 
      Parent : Parent }
let createChild parent childName =
    { ChildName = childName
      Parent = parent }
let createParent parentName childNames =
    let rec children = childNames |> List.map (fun childName -> createChild parent childName)
    and parent = {
        ParentName = parentName
        Children = children
    }
    parent

错误信息是什么意思?我应该如何纠正这个代码?

这段代码的目的是用循环引用初始化f#不可变记录。我试着到处应用这些方法,但都没有成功。

我不熟悉这个错误,它似乎没有被记录在任何地方,但这是我可以在玩了它一点后推测的。

问题似乎在于parent如何被lambda表达式关闭,该表达式本身位于children的定义内。这显然会抛出类型检查器(tc.fs)—我的猜测是因为children绑定本身的右侧包含一个表达式(lambda表达式),该表达式本身包含一个递归引用,但真正的原因可能比这更微妙。注意,如果像这样反转声明:

let createParent parentName childNames =
    let rec parent = {
        ParentName = parentName
        Children = children }
    and children = childNames |> List.map (fun childName -> createChild parent childName)
    parent

您还将在绑定children的行上看到此警告:

警告:将在运行时通过使用延迟引用来检查对所定义对象的此和其他递归引用的初始化合理性。这是因为您正在定义一个或多个递归对象,而不是递归函数。

要解决这个问题,似乎可以将闭包拉出一级:

let createParent parentName childNames =
    let rec makeChild n = createChild parent n 
    and parent = {
        ParentName = parentName
        Children = children }
    and children = childNames |> List.map makeChild
    parent

或者像这样将parent参数curry成createChild方法中的值(注意makeChild必须在parent之后声明):

let createParent parentName childNames =
    let rec parent = {
        ParentName = parentName
        Children = children }
    and makeChild = createChild parent
    and children = childNames |> List.map makeChild
    parent

或者更简单地说:

let createParent parentName childNames =
    let rec parent = {
        ParentName = parentName
        Children = children }
    and children = childNames |> List.map (createChild parent)
    parent

因为两边都需要是函数而不是属性

试试这个:

let createParent parentName childNames =
    let rec children names =
        names |> List.map (fun childName -> createChild (parent ()) childName)
    and parent () = {
        ParentName = parentName
        Children = children childNames
    }
    parent ()

最新更新