SML中无法解析的flex记录有什么错误?

时间:2019-02-28 07:42:15

标签: 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}

我有两个职能。第一个功能是反向,即反向列表并返回它。例如,将[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,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)

什么可能导致错误?

1 个答案:

答案 0 :(得分:1)

您收到的错误是由SML编译器无法推断您拥有的元组类型引起的。 #1#2不是函数,而是对任意类型的元组起作用的宏,只要它们具有两个元素即可。因此,解决此问题的快速方法是添加类型注释,

fun getDirectNodes(startNode, Tuples : (int * int) list, list) = ...

但是,由于您发布了很多解决方案,因此我想对此提供一些一般性反馈:

反向

您对reverse的实现存在一些错误:

  1. 在编写if L = [] ...时,您将L强制为equality type, ''a。这似乎很奇怪,因为您只是测试L为空,但是在L = []可以是有效表达式之前,其元素也必须具有相等性才能相等。您可以通过模式匹配或使用函数List.null(使用模式匹配)来解决此问题,以避免相等类型限制。

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

  3. 它递归地使用@,这效率非常低:您的算法为 O(n²),因为{{1 }}花费线性时间来解决每个递归调用,即几何复杂度:

    @

    此时 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] 已使用 O(n)堆栈空间。

    reverse

    此时~> [] @ [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 @ *) 使用了 O(n +(n-1)+ ... + 1)= O(n²)递归调用。

    < / li>
  4. 实际上有一个名为reverse的内置函数。

    它是这样实现的:

    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
    

    使用 heap 内存而不是 stack 内存,以及 O(n)递归调用。

getDirectNodes

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

  1. 同一件事。平等类型适用于wrt。 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]

  2. Tuples = []作为累加结果非常好!我可能会说它更具描述性,就像我称list之类的Tuples来描述其内容而不是其类型。 / p>

  3. 使用edges之类的累加结果是整洁的,这意味着您的函数将一个空列表作为输入。如果呼叫者向其提供非空列表怎么办?暴露这个多余的参数会留出错误的余地,因此请将其隐藏在内部函数中,就像我对list所做的那样。

  4. 使用模式匹配代替rev_helperhd

  5. 您对tl的使用似乎很有意义:您已经体验到reverse最终相反。但是,不要在每次递归调用时都在list上调用reverse,而要在最后一次(当list为空时)进行一次

    < / li>

给出此建议,这是您的代码的变体:

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) 的原因是因为我对代码#2edges的元素进行了模式匹配。这会将fn (x, _) => ...限制为2元组的列表。

运行此:

edges