繁体   English   中英

如何使用 sml 编写 function 将 2 元组列表转换为扁平列表?

[英]How to use sml to write a function to turn a list of 2-tuples to a flattened list?

我遇到了一个问题,需要将元组列表转换为扁平列表,例如:

[(1,2), (3,4), (5,6)] 可以变成 [1,2,3,4,5,6]

我试图写一个 function 像这样:

fun helper2(nil,b) = []
|   helper2(a,nil) = []
|   helper2(a::l1,b::l2) =l1::l2

fun flatten2 [] = []
|   flatten2 ((a,b)::tl) = helper2(a,b)

表明:

val flatten2 = fn : ('a list * 'a list list) list -> 'a list list

当我尝试使用命令flatten2[(1,2),(3,4),(5,6)];运行它时它会给我以下错误信息:

stdIn:1.2-1.29 Error: operator and operand do not agree [overload conflict]
  operator domain: ('Z list * 'Z list list) list
  operand:         ([int ty] * [int ty]) list
  in expression:
    flatten2 ((1,2) :: (3,4) :: (<exp>,<exp>) :: nil)

我的问题是:

  1. 为什么 SML 将 a 和 b 值视为列表,而不仅仅是 a 和 b
  2. 如何修改我的代码,以便 SML 可以将 a 和 b 视为 'a 和 'b 不是列表
  3. 如何使此代码按应有的方式工作?

谢谢

第一个问题:至于为什么类型出现为('a list * 'a list list)这是因为类型推断正在查看这部分代码:

|   helper2(a::l1,b::l2) =l1::l2
                            ^^
                           here

请记住,“cons”( :: )运算符的类型是'a -> 'a list -> 'a list ,它将单个元素粘合到相同类型元素的列表上。 所以 SML 得出结论,无论l1l2是什么,关系是l2l1是什么的列表。

fun helper2(nil,b) = []

a必须是一个列表,因为nil的类型'a list 因此, l2必须是列表列表(某种类型'a )。

问题 2 和 3:我不太确定如何更正编写的代码。 我可能会写这样的东西:

fun helper2 [] accum = List.rev accum
|   helper2 ((a,b)::tl) accum =  helper2 tl (b :: a :: accum);

fun flatten2 list = helper2 list [];

helper2做了所有的脏活。 如果输入列表为空,那么我们就完成了,我们可以返回我们一直在构建的反向累加器 第二种情况是我们实际上将东西添加到累加器中。 我们在列表的头部和尾部进行模式匹配。 这种模式匹配意味着输入具有类型('a * 'a) list (两个元素都是相同类型的元组列表)。 在头部,我们有一个元组,我们分别命名第一个和第二个元素ab 我们在累加器前面加上a然后b并在列表的尾部递归调用helper2 最终,我们将遍历列表中的所有元素,然后只剩下累加器——回想一下,它包含所有元素,但顺序相反。 调用List.rev反转累加器,这就是我们的答案。

当我加载并运行它时,我得到了这个:

- flatten2 [(1,2), (3,4), (5,6)];
val it = [1,2,3,4,5,6] : int list

为什么 SML 将 a 和 b 值视为列表,而不仅仅是 a 和 b

克里斯已经深入回答了这个问题。

您将a作为第一个参数传递给helper2 ,它需要一个列表作为其第一个参数。 并且您将b作为第二个参数传递给helper2 ,它使用它的第二个参数b::l2 ,也是一个列表,作为列表的尾部,其中a是头部。 所以b必须是这些列表的列表。

这没有任何意义,并且很可能是语法混乱的结果:您正在传递您对 flatten2 中单个元素ab的看法,但是当您在flatten2中处理它们时helper2它们现在列出了头部的位置被称为ab 那些不一样ab

如何修改我的代码,以便 SML 可以将 a 和 b 视为 'a 和 'b 不是列表

您可以放弃助手 function 开始:

fun flatten2 []             = []
  | flatten2 ((a,b)::pairs) = a :: b :: flatten2 pairs

有一个助手 function 的目的是为了在递归过程中可以累积结果,因为这个版本的flatten2使用了大量的堆栈空间。 它可以通过一个额外的参数来做到这一点,因此flatten2不需要提及它:

这是克里斯制作的版本。

如何使此代码按应有的方式工作?

您可以通过多种方式制作此代码。 提到了两种使用显式递归的方法。

以下是一些使用高阶函数的替代方案:

(* Equivalent to my first version *)
fun flatten2 pairs =
  foldr (fn ((a,b), acc) => a :: b :: acc) [] pairs

(* Equivalent to Chris'es version *)
fun flatten2 pairs =
  rev (foldl (fn ((a,b), acc) => b :: a :: acc) [] pairs)

(* Yet another alternative *)
fun concatMap f xs =
  List.concat (List.map f xs)

fun flatten2 pairs =
  concatMap (fn (a,b) => [a,b]) pairs

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM