F# 中的list是一个不可变集合,可以包含零个或多个值。列表中的所有值都必须具有相同的类型。由于列表是不可变的,一旦列表被构建出来,它的值就永远不会改变。任何看起来会修改列表的函数或运算符(例如添加一个元素),实际上都会返回一个新的列表。
列表可以这样定义:
let empty = []
let singleValue = [5]
let threeValues = ["a"; "b"; "c"]
向列表中添加元素最常见的方式是使用::(cons)运算符:
let twoToFour = [2; 3; 4]
let oneToFour = 1 :: twoToFour
// => [1; 2; 3; 4]
F# 列表有一个_头部_(第一个元素)和一个_尾部_(第一个元素之后的所有内容)。列表的尾部本身也是一个列表。
列表既可以通过List模块中定义的函数和运算符来操作,也可以使用模式匹配,借助 list 和 cons 模式手动操作:
let describe list =
match list with
| [] -> "Empty list"
| head::tail -> sprintf "Non-empty list with head: %d" head
describe [] // => "Empty list"
describe [1] // => "Non-empty with head: 1"
describe [5; 7; 9] // => "Non-empty with head: 5"
在模式匹配时,你也可以_丢弃_一个值;当你在某个特定分支中_不_关心某个值(也就是说,你不打算_使用_它)时,可以用下划线('_')来表示这一点:
let describe list =
match list with
| [] -> "Empty list"
| [x] -> "List with one item"
| [_; y] -> "List with two items (first item ignored)"
| _ -> "List with many items (all items ignored)"
describe [] // => "Empty list"
describe [1] // => "List with one item"
describe [5; 7] // => "List with two items (first item ignored)"
describe [5; 7; 9] // => "List with many items (all items ignored)"
在模式匹配时,单个'_'应始终放在_最后_;所有不匹配其他分支的值都会由这一分支来处理。
在这个练习中,你将编写代码来记录你想在 Exercism 上学习的编程语言列表。
一共有六个任务,它们都涉及对列表的处理。
为了记录你想学习的语言,你需要创建一个新列表。定义 newList 绑定,让它包含一个新的空列表。
newList
// => []
目前,你有一张纸,上面列出了你想学习的语言:F#、Clojure 和 Haskell。定义 existingList 绑定来表示这个列表。
existingList
// => ["F#"; "Clojure"; "Haskell"]
当你在 Exercism 上探索并发现更多有趣的语言时,你会想把它们加进列表。实现 addLanguage 函数,把一门新语言添加到列表的开头。
addLanguage "TypeScript" ["JavaScript"; "CoffeeScript"]
// => ["TypeScript"; "JavaScript"; "CoffeeScript"]
一门一门地清点语言很不方便。实现 countLanguages 函数,统计列表中有多少门语言。
countLanguages ["C#"; "Racket"; "Rust"; "Ruby"]
// => 4
某天你发现,自己的列表顺序其实是反的!实现 reverseList 函数,把列表反转过来。
reverseList ["Prolog"; "C"; "Idris"; "Assembly"]
// => ["Assembly"; "Idris"; "C"; "Prolog"]
虽然你喜欢所有语言,但 F# 在你心中有特殊的位置。因此,只要满足以下条件,你就会对一个语言列表感到兴奋:
实现 excitingList 函数,检查一个语言列表是否令人兴奋:
excitingList ["Nim"; "F#"]
// => true