【发布时间】:2017-08-14 04:55:41
【问题描述】:
如何在标准 ML 中创建一个函数来压缩和解压缩两个列表作为元组列表?
例子:
unzip [[1,4],[2,5],[3,6]] -> [1,2,3] [4,5,6]
zip [1,2,3] [0,2,4] -> [[1,0],[2,2],[3,4]]
【问题讨论】:
-
[1,4]不是元组;它是两个元素的列表。(1,4)是一个元组
如何在标准 ML 中创建一个函数来压缩和解压缩两个列表作为元组列表?
例子:
unzip [[1,4],[2,5],[3,6]] -> [1,2,3] [4,5,6]
zip [1,2,3] [0,2,4] -> [[1,0],[2,2],[3,4]]
【问题讨论】:
[1,4] 不是元组;它是两个元素的列表。 (1,4) 是一个元组
我发现我做错了什么。 代码如下:
fun zip nil nil = nil
| zip nil l = l
| zip l nil = l
| zip (h::t) (k::l) = [h,k]::(zip t l)
fun mapcan(f,nil) = nil | mapcan(f,h::t) = (f h)@(mapcan(f,t))
fun unzip (l) = if (l = nil) then nil else [(map head l),(mapcan tail l)]
解压缩稍微困难一些。我们需要在压缩列表中选择双元素列表的第一个和第二个元素的映射函数。由于该示例对问题的说明有些不足,因此我们将把较长列表的其余部分放入第一个列表中。为避免较短列表出现空尾问题,我们使用附加尾列表的 mapcan 函数。
【讨论】:
zip 解决方案没有输入检查。 nil 案例需要返回nil。另外,为什么要使用列表列表,而不是 2 元组列表,这对于 zip/unzip 来说更传统?
l = nil.
使用head 和tail 通常不是一个好主意,而是使用模式匹配。您可以更优雅地对 unzip 进行编码,如下所示:
fun unzip l =
case l
of nil => (nil, nil)
| (a,b)::tl =>
let val (l1, l2) = unzip tl
in (a::l1, b::l2) end
同样作为上述评论者之一,zip 和 unzip 通常分别适用于列表对和列表对。
【讨论】:
绝对不需要let 语句引入的词法作用域。通过定义投影函数,实际上可以获得更简洁和优雅的表示:
fun fst p =
case p of
(x,_) => x
fun snd p =
case p of
(_,y) => y
fun unzip lp =
case lp of
[] => ([], [])
| (x,y) :: lp' => (x :: (fst (unzip lp')), y :: (snd (unzip lp')))
这有很好的理由,那就是 SML 编译器的类型推断足够强大,可以从 case 语句和 cons 语句中推断出术语的类型。投影函数之前推导出来,类型约束的 CSP 是可解的。 IMO,这远比之前使用 let 声明提出的解决方案更优雅。
【讨论】: