【问题标题】:Understanding user defined append list Standard ml了解用户定义的附加列表标准ml
【发布时间】:2018-08-13 19:53:40
【问题描述】:

我无法理解标准 ML 中列表的这种实现。这是它的定义方式:

追加列表是列表抽象数据类型的(简单)实现,它使构建成本低(O(1)),但销毁成本高(O(n))。 'a alistNN 和 'a alist 类型定义如下:

 datatype 'a alistNN = Sing of 'a | Append of 'a alistNN * 'a alistNN
 datatype 'a alist = Nil | NonNil of 'a alistNN

'a alistNN 类型表示“非 nil”附加列表,而 'a alist 类型表示任意(nil 或 非零)附加列表。

我对如何处理这些列表/制作这些列表感到困惑。例如,我必须编写一个定义为的函数:

'a alist -> 'a alist -> 'a alist that appends to append lists. 

在理解此列表定义方面的任何帮助将不胜感激。

【问题讨论】:

    标签: sml ml mosml


    【解决方案1】:

    这个数据结构表示一个带有树的列表,其中每个内部节点表示其子节点的串联,每个叶子节点是一个元素。例如,下面是列表 [1,2,3,4] 的两种可能表示形式:

    val L1 = Append (Append (Sing 1, Sing 2), Append (Sing 3, Sing 4))
    
       *
      / \
     *   *
    / \ / \
    1 2 3 4
    
    val L2 = Append (Append (Sing 1, Append (Sing 2, Sing 3)), Sing 4)
    
        *
       / \
      *   4
     / \
    1   *
       / \
      2   3
    

    附加这些数据结构非常容易;您只需将它们与一个新的Append 节点链接在一起。我们可以附加上面的两个例子:

    Append (L1, L2)
    
            *
          /   \
        /       \
       *         *
      / \       / \
     *   *     *   4
    / \ / \   / \
    1 2 3 4  1   *
                / \
               2   3
    

    显然,您还必须根据需要将这些包装在 NonNil 中,但我将把它留给您。

    【讨论】:

    • 感谢您的帮助!
    • 试过这样实现: fun alistAppend (xs: 'a alist, ys: 'a alist): 'a alist = case xs of Nil => ys |NonNil x => Append (xs,ys );但我得到:未绑定类型构造函数:alist。我是否错误地创建了 NonNil?
    【解决方案2】:

    对于普通列表,

    datatype 'a normal_list = Nil | Cons of 'a * 'a normal_list
    

    您的Cons 运算符添加单个元素是O(1),但添加两个列表是O(n)

    fun append (Nil, ys) = ys
      | append (xs, Nil) = xs
      | append (Cons (x, xs), ys) = Cons (x, append (xs, ys))
    

    有了这些附加列表,

    datatype 'a alistNN = Sing of 'a | Append of 'a alistNN * 'a alistNN
    datatype 'a alist = Nil | NonNil of 'a alistNN
    

    您的 Append 运算符现在是 O(1),但 cons 变得更加困难 O(n),因为你说,它需要破坏列表来重建它,因为数据结构的头部不再是第一个元素,而是最近添加列表的点。

    我对如何处理这些列表/制作这些列表感到困惑。例如,我必须编写一个定义为的函数:

    'a alist -> 'a alist -> 'a alist
    

    附加到附加列表。

    编辑:澄清了本节。)您已经有一个构造函数Append : 'a alistNN * 'a alistNN -> 'a alistNN 可以做到这一点。要制作一个适用于 'a alist 的版本,您必须针对 'a alist 的不同情况进行模式匹配;只有当两个列表都是 NonNil 时,您才能使用 Append(因为空列表不能表示为 'a alistNN。任何一个操作数都是 @987654331 的情况@可以单独处理;

    fun append Nil ys = ys
      | append xs Nil = xs
      | append (NonNil xs) (NonNil ys) = NonNil (Append (xs, ys))
    

    变得更加困难的一件事是,如果您想在 'a alist 前面添加单个元素,即带有签名 'a * 'a alist -> 'a alist 的函数:

    fun cons (x, Nil) = NonNil (...)
      | cons (x, NonNil (Sing y)) = NonNil (...)
      | cons (x, NonNil (Append (ys, zs))) = NonNil (...)
    

    在任何情况下,x 都会被前置。当涉及到您要添加 x 的列表时,存在三种情况:列表为空,列表非空且包含单个元素,或者列表非空且包含 Append 的另外两个列表。在每种情况下,结果都是NonNil,因为在列表前添加x 永远不会给出Nil

    前两种情况应该是直截了当的。第三种情况你必须考虑根据子列表yszsx 放在哪里。

    像这样,您可以通过在 REPL 中键入 open List; 来构建所有辅助功能。即使hdtl 也不是完全无关紧要的,因为它们一心想要找到第一个元素和列表其余部分之间的分割点。用于测试目的的有用函数是toList,签名为'a alist -> 'a list。为这些附加列表制作一个有趣的列表是rev。 :-)

    因为你可能不会制作foldl

    fun foldl f e Nil = e
      | foldl f e (NonNil (Sing x)) = f (x, e)
      | foldl f e (NonNil (Append (xs, ys))) =
          foldl f (foldl f e (NonNil xs)) (NonNil ys)
    

    为了娱乐,您可以使用foldl 实现hd 并抛出异常:

    fun hd xs =
        let exception FoundIt of 'a
        in foldl (fn (x, _) => raise FoundIt x) (fn _ => raise Empty) xs ()
           handle FoundIt x => x
        end
    

    这里有一个稍微相关的 StackOverflow 帖子:Standard ML functor examples

    【讨论】:

      猜你喜欢
      • 2012-04-13
      • 2015-04-05
      • 2021-12-08
      • 2017-11-30
      • 1970-01-01
      • 1970-01-01
      • 2011-05-05
      • 2011-08-01
      • 2011-07-19
      相关资源
      最近更新 更多