了解用户定义的附加列表标准 ml
Understanding user defined append list Standard ml
我无法理解标准 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 或
非零)附加列表。
我对如何使用这些 lists/make 这些列表感到困惑。例如,我必须编写一个定义为的函数:
'a alist -> 'a alist -> 'a alist that appends to append lists.
对于理解此列表定义的任何帮助,我们将不胜感激。
此数据结构表示一个带有树的列表,其中每个内部节点表示其子节点的串联,每个叶子是一个元素。例如,列表 [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
附加这些数据结构非常容易;你只需 link 它们和一个新的 Append
节点。我们可以附加上面的两个例子:
Append (L1, L2)
*
/ \
/ \
* *
/ \ / \
* * * 4
/ \ / \ / \
1 2 3 4 1 *
/ \
2 3
显然,您还必须根据需要将它们包装在 NonNil
中,但我会留给您。
使用普通列表,
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) 因为,正如您所说,它需要销毁列表才能重建它,因为数据结构的头部不再是第一个元素,而是列表最近出现的位置附加。
Im confused on how I would work with these lists/make these lists. For example I have to write a function that is defined as:
'a alist -> 'a alist -> 'a alist
that appends to append lists.
(编辑: 澄清了这一部分。) 您已经有一个构造函数 Append : 'a alistNN * 'a alistNN -> 'a alistNN
可以做到这一点。要制作一个适用于 'a alist 的版本,您必须针对 'a alist 的不同情况进行模式匹配;只有当两个列表都是 NonNil
时,您才能使用 Append
(因为空列表不能表示为 'a alistNN. 任一操作数为Nil
的情况可以单独处理;
fun append Nil ys = ys
| append xs Nil = xs
| append (NonNil xs) (NonNil ys) = NonNil (Append (xs, ys))
如果您想在 'a 列表 前面添加单个元素,即具有签名 '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
的列表时,存在三种情况:列表为空,列表为 non-empty 且包含单个元素,或者列表为 non-empty 并包含其他两个列表的 Append
。在每种情况下,结果都是 NonNil
,因为在列表前添加 x
永远不会得到 Nil
.
前两种情况应该很简单。第三种情况你要考虑把x
放在什么地方sub-listsys
和zs
.
像这样,您可以构建通过在 REPL 中键入 open List;
找到的所有辅助函数。甚至 hd
和 tl
也不是完全微不足道的,因为它们致力于找到第一个元素和列表其余元素之间的分割。一个用于测试目的的有用函数是 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
这里有一个稍微相关的 Whosebug post:Standard ML functor examples
我无法理解标准 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 或 非零)附加列表。
我对如何使用这些 lists/make 这些列表感到困惑。例如,我必须编写一个定义为的函数:
'a alist -> 'a alist -> 'a alist that appends to append lists.
对于理解此列表定义的任何帮助,我们将不胜感激。
此数据结构表示一个带有树的列表,其中每个内部节点表示其子节点的串联,每个叶子是一个元素。例如,列表 [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
附加这些数据结构非常容易;你只需 link 它们和一个新的 Append
节点。我们可以附加上面的两个例子:
Append (L1, L2)
*
/ \
/ \
* *
/ \ / \
* * * 4
/ \ / \ / \
1 2 3 4 1 *
/ \
2 3
显然,您还必须根据需要将它们包装在 NonNil
中,但我会留给您。
使用普通列表,
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) 因为,正如您所说,它需要销毁列表才能重建它,因为数据结构的头部不再是第一个元素,而是列表最近出现的位置附加。
Im confused on how I would work with these lists/make these lists. For example I have to write a function that is defined as:
'a alist -> 'a alist -> 'a alist
that appends to append lists.
(编辑: 澄清了这一部分。) 您已经有一个构造函数 Append : 'a alistNN * 'a alistNN -> 'a alistNN
可以做到这一点。要制作一个适用于 'a alist 的版本,您必须针对 'a alist 的不同情况进行模式匹配;只有当两个列表都是 NonNil
时,您才能使用 Append
(因为空列表不能表示为 'a alistNN. 任一操作数为Nil
的情况可以单独处理;
fun append Nil ys = ys
| append xs Nil = xs
| append (NonNil xs) (NonNil ys) = NonNil (Append (xs, ys))
如果您想在 'a 列表 前面添加单个元素,即具有签名 '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
的列表时,存在三种情况:列表为空,列表为 non-empty 且包含单个元素,或者列表为 non-empty 并包含其他两个列表的 Append
。在每种情况下,结果都是 NonNil
,因为在列表前添加 x
永远不会得到 Nil
.
前两种情况应该很简单。第三种情况你要考虑把x
放在什么地方sub-listsys
和zs
.
像这样,您可以构建通过在 REPL 中键入 open List;
找到的所有辅助函数。甚至 hd
和 tl
也不是完全微不足道的,因为它们致力于找到第一个元素和列表其余元素之间的分割。一个用于测试目的的有用函数是 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
这里有一个稍微相关的 Whosebug post:Standard ML functor examples