SML中的模式匹配 - 将列表表示为(x :: y)

时间:2014-01-12 00:43:04

标签: recursion functional-programming pattern-matching sml smlnj

我刚刚开始学习函数式编程,我发现自己对模式匹配的概念感到非常困惑(我正在使用SML)。以下面的表达式为例,在有序列表中插入一个元素:

fun insert (n,nil) = [n]
  | insert (n, L as x::l) =
    if(n < x) then n::L
    else x::(insert(n,l))

如何将列表L表示为x :: l?我知道x指的是列表的第一个元素,l指的是其余部分,但我不知道该怎么称呼这个结构或如何使用它。我已经阅读了很多,但我找到的所有文档都没有提到这一点。这是另一个不使用'as'关键字的示例。

(*returns a list with the sum of each element added of two lists added together*)

fun addLists (nil,L) = L
| addLists (L,nil) = L
| addLists (x::xs,y::ys) =
  (x + y)::(addLists(xs,ys))

感谢您的帮助!

1 个答案:

答案 0 :(得分:5)

这里的insert功能:

fun insert (n,nil) = [n]
  | insert (n, L as x::l) =
    if(n < x) then n::L
    else x::(insert(n,l))

| insert (n, L as x::l)部分是将与之匹配的模式。 L as x::l被称为 as pattern 。它允许我们:

  1. 模式匹配非空列表,其中x是列表的头部,l是列表的尾部
  2. 请参阅名称为x::l
  3. 的整个匹配列表L

    这与做的相似(尽管不完全相同):

      | insert (n, x::l)
    

    除非您这样做,insert函数将变为:

    fun insert (n,nil) = [n]
      | insert (n, x::l) =
        if(n < x) then n::x::l
        else x::(insert(n,l))
    

    因此,使用L as x::l作为非模式模式的一大优势在于它允许我们引用整个列表,而不仅仅是它的头部和尾部,并且在我们需要时避免使用额外的列表构造引用整个列表。请注意,2段代码中唯一的区别是n::Ln::x::l。由于我们在第一个L as x::l函数中使用了模式insert,因此我们可以n::L而不是n::x::l。这样可以避免一次::操作(也称为cons操作)。

    至于此:

    fun addLists (nil,L) = L
    | addLists (L,nil) = L
    | addLists (x::xs,y::ys) =
      (x + y)::(addLists(xs,ys))
    

    对于第二种模式| addLists (x::xs,y::ys),我们无处在其后面的代码中重建列表x::xsy::ys,因此我们不需要作为模式。你可以这样写:

    fun addLists (nil,L) = L
    | addLists (L,nil) = L
    | addLists (ListX as x::xs, ListY as y::ys) =
      (x + y)::(addLists(xs,ys))
    

    并且它仍然可以使用,除了我们在这里没有引用ListXListY,因此这两个模式是不必要的。