【问题标题】:Syntax error in creating a list from a tree in SML从 SML 中的树创建列表时的语法错误
【发布时间】:2017-03-28 20:05:02
【问题描述】:

我有以下两种数据类型:

datatype leaf = Slist of string list | Real of real | nil;
datatype 'a tree = Empty |  Node of leaf * 'a tree * 'a tree * 'a tree;

下面的代码遍历所有长度为 1/2 的树,并形成叶子中值的列表。

fun list12(Empty:'a tree) = nil
  | list12(Node(leaf leaf1, 'a tree a1, 'a tree a2, 'a tree a3)) =
    if (not(a1 = Empty) andalso not(a2 = Empty) andalso not(a3 = Empty))
    then list12(a1)::list12(a2)::list12(a3)
    else leaf1::list12(a1)::list12(a2)::list12(a3);

问题是,我遇到语法错误,例如

stdIn:94.59-94.66 Error: syntax error: deleting  TYVAR ID
stdIn:94.71-94.78 Error: syntax error: deleting  TYVAR ID
stdIn:94.83-94.93 Error: syntax error: deleting  TYVAR ID ID
stdIn:94.93-94.97 Error: syntax error: deleting  RPAREN RPAREN EQUALOP
stdIn:94.98-94.102 Error: syntax error: deleting  IF LPAREN
stdIn:94.109-94.116 Error: syntax error: deleting  EQUALOP ID

代码本身并不复杂。基本情况是如果它为空,则返回 null。 如果它没有三个节点,那么我添加叶子的值并递归调用节点上的函数。如果是这样,我只是递归调用节点上的函数而不添加叶子。

它可以工作,因为它是空的,它通过将 nil 添加到列表中来结束搜索,这什么都不做。

我也尝试过其他情况比如使用and而不是andalso,以及其他版本的代码比如

  | list12(Node(leaf1, Empty, Empty, Empty)) = nil
  | list12(Node(leaf2, a1, Empty, Empty)) = leaf2::list12(a1);
  | list12(Node(leaf3, b1, b2, Empty)) = leaf3::list12(b1)::list12(b2);
  | list12(Node(leaf4, c1, c2, c3)) = list12(c1)::list12(c2)::list12(c3);

但我发现上面的情况并不符合所有情况。

知道为什么会出现语法错误吗?


旁注,为什么1.0 = 2.0 不起作用,但在摘要中它说它适用于真实?它似乎只适用于整数,>< 等也不起作用。

【问题讨论】:

    标签: recursion tree sml


    【解决方案1】:

    语法错误:

    1. 您无法重新绑定nil。它是内置列表类型的保留关键字(即nil = [])。
    2. 您不能为 'a tree t1 之类的类型添加前缀。您可以推断类型(通过不指定它并让类型检查器猜测它),或者使用正确的语法对其进行注释 (t1 : 'a tree)。

    假设我们消除了语法错误,通过删除类型注释来更多地依赖推理,并添加一些格式,这就是您的代码的样子:

    datatype leaf = Slist of string list | Real of real | Nil;
    datatype 'a tree = Empty | Node of leaf * 'a tree * 'a tree * 'a tree;
    
    fun list12 Empty = []
      | list12 (Node(leaf1, a1, a2, a3)) =
        if (not(a1 = Empty) andalso not(a2 = Empty) andalso not(a3 = Empty))
        then list12(a1)::list12(a2)::list12(a3)
        else leaf1::list12(a1)::list12(a2)::list12(a3);
    

    类型错误:

    !     then list12(a1)::list12(a2)::list12(a3)
    !          ^^^^^^^^^^
    ! Type clash: expression of type
    !   'a list
    ! cannot have type
    !   'a
    ! because of circularity
    

    查看op:: : 'a * 'a list -> 'a list 的类型,以及您对list12(a1)::list12(a2) 的使用,类型检查器必须找到一些'a,例如'a = 'a list。这就像找到一个x 这样x = x + 1。显然,无论list12 返回什么,你都有相同的东西在两边。

    一个肮脏而低效的技巧是使用@ 运算符(附加)。一种更简洁的方法是在树上折叠,使折叠的函数可以访问整个节点(如in this StackOverflow post from the other day):

    fun para f e Empty = e
      | para f e0 (t0 as Node (x, t1, t2, t3)) =
        let val e1 = f (e0, t0)
            val e2 = para f e1 t1
            val e3 = para f e2 t2
            val e4 = para f e3 t3
        in e4 end
    
    fun isNode (Node _) = true
      | isNode Empty = false
    
    fun list12 t =
        let fun extract (xs, Empty) = xs
              | extract (xs, Node (x, t1, t2, t3)) =
                if isNode t1 andalso isNode t2 andalso isNode t3
                then x::xs
                else xs
        in para extract [] t end
    

    您可以将其折叠成一个函数 - 这种方式将遍历逻辑分离为 para 并将累积逻辑分离为 list12 的辅助函数。

    比较reals

    为什么 1.0 = 2.0 不起作用,但在摘要中它说它适用于实数?

    我不知道你指的是什么摘要。这个问题在这里得到了回答:Why can't I compare reals in Standard ML?(这个答案最初是放在这里的,但是因为它是一个单独的问题,所以被移到了那里。)

    【讨论】:

      猜你喜欢
      • 2011-08-15
      • 2013-01-31
      • 2017-11-20
      • 2012-08-14
      • 1970-01-01
      • 1970-01-01
      • 2014-03-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多