1

我正在学习 f#,没有以前的函数式编程背景 - 开始取得进展,但一直坚持这一点。谁能帮我理解 99 个 f# 问题中第 9 个问题的解决方案 - 它们可以在这里找到:[http://fssnip.net/an][1]

基本上我不明白模式匹配在提供的解决方案中是如何工作的。首先什么是 xss?为任何帮助欢呼!

问题 9:将列表元素的连续重复项打包到子列表中。如果列表包含重复的元素,则应将它们放置在单独的子列表中。

例子:

包 ['a'; '一个'; '一个'; '一个'; 'b'; 'C'; 'C'; '一个'; '一个'; 'd'; 'e'; 'e'; 'e'; 'e']

验证它:字符列表列表 = [['a'; '一个'; '一个'; '一个']; ['b']; ['C'; 'C']; ['一个'; '一个']; ['d']; ['e'; 'e'; 'e'; 'e']]

样品溶液;

let pack xs = 
    let collect x = function
        | (y::xs)::xss when x = y -> (x::y::xs)::xss
        | xss -> [x]::xss
    List.foldBack collect xs []
4

2 回答 2

1

(y::xs)::xss匹配列表的(非空)列表,y并且xs是第一个子列表的头部和尾部,并且xss是外部列表的尾部。xss,在第二种情况下,匹配整个列表(是否为空)。

foldBack( ('T -> 'State -> 'State) -> 'T list -> 'State -> 'State) 将累加器参数从后到前穿过列表。

collect是“累加”函数,它基本上是这样写的:如果状态(最初是一个空列表)包含至少一个子列表,该子列表也是非空的,并且当前元素(x)与子列表的头部( )匹配,则y添加x到子列表,否则将新的子列表添加到xss仅由 . 组成的状态 ( ) 中x。每个子列表是一组相等的相邻元素。

于 2013-02-13T22:49:01.487 回答
1

要理解这一点,首先要了解 F# 中列表的表示方式。F# 列表是:

  • 一个空列表写成[]
  • 一个值(头)后跟另一个列表(尾),写成head::tail

因此,例如,如果您编写,[ 1; 2; 3 ]您实际上是在构造一个包含 1 的列表,然后是一个包含 2 的列表,(等等),然后是一个空列表。表达式编译为:

1::(2::(3::[])) 

你可以省略括号,只写1::2::3::[].

模式匹配使用完全相同的语法,但方向相反。您不是在构造列表,而是在分解它们。因此,当您有一个模式x::xs时,这意味着您想要获取第一个元素并将其分配给一个变量x,而剩余的列表应该分配给一个变量xs

该模式(x::xs)::xss有点棘手,因为它适用于列表列表。这意味着您匹配的列表的头部也是一个列表。您可以将代码重写为以下更简单的版本:

let pack xs = 
    let collect x = function
        | head::xss ->    // Decompose into first element (head) and the rest (tail)
          match head with
          | y::xs when x = y -> (x::y::xs)::xss
          | _ -> [x]::xss
        | xss -> [x]::xss
    List.foldBack collect xs []

现在您在代码中有一些重复,但是您可以看到,collect需要x和另一个参数匹配另一个参数head::xss(以获取头/尾),然后还分解head.

于 2013-02-13T22:58:50.583 回答