在标准ML中压缩和解压缩列表

时间:2015-06-02 20:06:19

标签: sml smlnj

如何创建一个函数来将两个列表压缩并解压缩为标准ML中的tupled列表?

示例:

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]]

3 个答案:

答案 0 :(得分:2)

我弄清楚我做错了什么。 这是代码:

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)]

解压缩稍微困难一些。我们需要map函数来选择压缩列表上的两元素列表的第一个和第二个元素。由于该示例在某种程度上指定了问题,我们将把较长列表的其余部分放入第一个列表中。为了避免较短列表的空尾问题,我们使用附加尾部列表的mapcan函数。

答案 1 :(得分:1)

使用headtail通常不是一个好主意,而是使用模式匹配。您可以按照以下方式更优雅地解压缩解压缩:

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通常分别用于成对列表和对列表。

答案 2 :(得分:0)

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编译器中的Type-Inference强大到足以从case语句和cons语句中推断出术语的类型。之前推导出了投影函数,并且可以解决类型约束的CSP。 IMO,比以前用let语句提供的解决方案更优雅。

Compiler