SML中未解析flex记录的错误是什么?

SML中未解析flex记录的错误是什么?,sml,smlnj,Sml,Smlnj,我是SML的新手,曾向人们询问我遇到的错误。但是,我找不到问题所在 收到的错误消息是: stdIn:10.1-16.48 Error: unresolved flex record (need to know the names of ALL the fields in this context) type: {1:''Y, 2:''X; ''Z} 我有两个功能。第一个函数是reverse,它将列表反转并返回。例如,将[1,2,3,4]反转为[4,3,2,1]。这个函数绝对没有

我是SML的新手,曾向人们询问我遇到的错误。但是,我找不到问题所在

收到的错误消息是:

stdIn:10.1-16.48 Error: unresolved flex record (need to know the names       
of ALL  the fields in this context)
type: {1:''Y, 2:''X; ''Z}
我有两个功能。第一个函数是reverse,它将列表反转并返回。例如,将[1,2,3,4]反转为[4,3,2,1]。这个函数绝对没有问题

fun reverse(L) =
   if L = nil then nil
   else reverse(tl(L)) @ [hd(L)];
下一个函数是getDirectNode,它接受3个参数:起始节点、包含边的元组列表和空列表。例如,我有一个节点1作为第一个参数。我有一个包含所有边的元组列表。[(1,2)、(1,3)、(2,3)、(2,4)],用于第二个参数。最后,第三个参数将是一个空列表

在getDirectNodes函数中,它将找到第一个数字为1的元组。在这种情况下,它将得到(1,2)和(1,3)。然后,它将把2和3放入空列表并返回。因此,函数将返回[2,3]

以下是我的功能:

  fun getDirectNodes(startNode,Tuples,list) =
     if Tuples = [] 
        then list
     else if #1(hd(Tuples)) = startNode
        then getDirectNodes(startNode,tl(Tuples),reverse(#2(hd(Tuples)) :: list))
     else
        getDirectNodes(startNode, tl(Tuples),list)

什么可能导致此错误?

您得到的错误是由SML编译器无法推断您拥有的元组类型引起的
#1
#2
不是函数,而是可以处理任意类型元组的宏,只要它们有两个元素。所以克服这个问题的一个快速方法是添加类型注释

fun getDirectNodes(startNode, Tuples : (int * int) list, list) = ...
但是,由于您发布了大量解决方案,我想给出一些一般性的反馈:

颠倒 您的
反向执行
有几处错误:

  • 当您编写
    时,如果L=[]…
    ,您将强制
    L
    成为一个。这似乎有些奇怪,因为您只是测试
    L
    是否为空,但在
    L=[]
    可以成为有效表达式之前,它的元素也必须是相等的。您可以通过模式匹配或使用函数
    List.null
    (使用模式匹配)来解决此问题,以避免等式类型限制

  • 它使用
    hd
    tl
    代替模式匹配;这些函数是,这意味着如果使用不当,它们可能在运行时崩溃。您可以通过在空列表和非空列表上使用模式匹配来避免它们

  • 它递归地使用
    @
    ,这是非常低效的:您的算法是O(n²),因为
    @
    的左侧需要线性时间来解析每个递归调用,即几何复杂度:

       reverse [1,2,3,4]
    ~> reverse [2,3,4] @ [1]
    ~> reverse [3,4] @ [2] @ [1]
    ~> reverse [4] @ [3] @ [2] @ [1]
    ~> reverse [] @ [4] @ [3] @ [2] @ [1]
    
    此时,
    reverse
    使用了O(n)堆栈空间

    ~> [] @ [4] @ [3] @ [2] @ [1]
    ~> [4] @ [3] @ [2] @ [1]       (* 1 recursive call in @ *)
    ~> [4,3] @ [2] @ [1]           (* 2 recursive calls in @ *)
    ~> [4,3,2] @ [1]               (* 3 recursive calls in @ *)
    ~> [4,3,2,1]                   (* 4 recursive calls in @ *)
    
    此时,
    reverse
    使用了O(n+(n-1)+…+1)=O(n²)递归调用

  • 实际上有一个内置函数叫做
    rev

    它是这样实现的:

    fun rev xs =
      let fun rev_helper []      xs_bw = xs_bw
            | rev_helper (x::xs) xs_bw = rev_helper xs (x::xs_bw)
      in rev_helper xs [] end
    
    把它称为:

       rev [1,2,3,4]
    ~> rev_helper [1,2,3,4] []
    ~> rev_helper [2,3,4] [1]   (* 1 recursive call *)
    ~> rev_helper [3,4] [2,1]   (* 1 recursive call *)
    ~> rev_helper [4] [3,2,1]   (* 1 recursive call *)
    ~> rev_helper [] [4,3,2,1]  (* 1 recursive call *)
    ~> [4,3,2,1]
    
    它使用堆内存而不是堆栈内存,以及O(n)递归调用

  • getDirectNodes 以下是非详尽的评论列表:

  • 同样的事情发生了。等式类型适用于此处wrt<代码>元组=[]

  • 列表
    作为累积结果是很好的!我可能会称之为更具描述性的东西,就像我会称之为
    Tuples
    类似于
    edges
    的东西来描述它的内容而不是类型一样

  • 虽然使用像
    list
    这样的累积结果很整洁,但这意味着您的函数需要一个空列表作为输入。如果调用方向其提供一个非空列表怎么办?公开这个额外的参数会留下错误的空间,所以将其隐藏在内部函数中,就像我使用
    rev\u helper
    时所做的那样

  • 使用模式匹配而不是
    hd
    tl

  • 您使用
    reverse
    似乎很有意义:您已经体验到
    list
    以反向结束。但是不要在每次递归调用时调用
    list
    上的
    reverse
    ,而是在最末尾执行一次(当
    Tuples
    为空时)

  • 根据此建议,下面是代码的一个变体:

    fun getDirectNodes (startNode, []) = []
      | getDirectNodes (startNode, (x, endNode) :: edges) =
        if x = startNode
        then endNode :: getDirectNodes (startNode, edges)
        else getDirectNodes (startNode, edges)
    
    以及一个变体,它使用一个内部尾部递归函数,并在末尾使用一个
    rev

    fun getDirectNodes (startNode, edges) =
        let fun helper ([], endNodes) = endNodes
              | helper ((x, endNode) :: edges, endNodes) =
                if x = startNode
                then helper (edges, endNode :: endNodes)
                else helper (edges, endNodes)
        in rev (helper (edges, [])) end
    
    下面是我将如何使用高阶函数实现它:

    fun getDirectNodes (startNode, edges) =
        List.map #2 (List.filter (fn (x, _) => x = startNode) edges)
    
    我没有收到警告的原因。我在这里使用
    #2
    ,尽管没有任何类型注释,但这是因为我在代码
    fn(x,))=>…
    中对
    边的元素进行模式匹配。这将
    约束为2元组列表

    运行此:

    - getDirectNodes (1, [(1,2),(1,3),(2,3),(2,4)]);
    > val it = [2, 3] : int list