Skip to content

Commit ed52e3c

Browse files
committed
update
1 parent bb10eb6 commit ed52e3c

File tree

2 files changed

+54
-38
lines changed

2 files changed

+54
-38
lines changed

18-comprehensions.md

Lines changed: 32 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,24 @@
11
18-列表速构(Comprehension)
22
========
3-
[生成器和过滤器](#182-%E7%94%9F%E6%88%90%E5%99%A8%E5%92%8C%E8%BF%87%E6%BB%A4%E5%99%A8)<br/>
4-
[比特串生成器](#182-bitstring%E7%94%9F%E6%88%90%E5%99%A8)<br/>
5-
[Into](#183-into)<br/>
63

7-
>Comprehensions翻译成“速构”不知道贴不贴切,这参照了《Erlang/OTP in Action》译者的用辞。
8-
“速构”是函数式语言中常见的概念,它大体上指的是用一套规则(比如从另一个列表,过滤掉一些元素)来生成元素填充新列表。
9-
这个概念我们在中学的数学课上就可能已经接触过,在大学高数中更为常见:如```{ x | x ∈ N }```,指的是这个集合里所有元素是自然数。
10-
该集合是由自然数集合的元素映射生成过来的。相关知识可见[WIKI](http://en.wikipedia.org/wiki/List_comprehension)
4+
> *Comprehensions* 翻译成“速构”不知道贴不贴切,
5+
这参照了《Erlang/OTP in Action》译者的用辞。国内一些Python书(是的,Python也有这个概念)
6+
中翻译为“推导式”、“递推式”。不过这里请不要纠结它翻译成啥,主要是弄明白它是啥。本章
7+
(或者本文)中出现的话,一般翻译成“速构”或是保留英文。
8+
“速构”是函数式语言中常见的概念,它大体上指的是用一套规则(比如从另一个列表,过滤掉一些元素)
9+
来生成元素填充新列表。
10+
这个概念我们在中学的数学课上其实就已经接触过,在大学高数中更为常见:
11+
```{ x | x ∈ N }```,字面上意思是其表示了一个集合,这个集合里所有元素属于自然数N范围
12+
(也就是自然数集合)。
13+
相关知识可见[WIKI](http://en.wikipedia.org/wiki/List_comprehension)
1114

12-
Elixir中,使用枚举类型(如列表)来做循环操作是很常见的。对对象列表进行枚举时,通常要有选择性地过滤掉其中一些元素,还有可能做一些变换。列表速构(comprehensions)就是为此目的诞生的语法糖:把这些常见任务分组,放到特殊的```for```中执行。
15+
Elixir中,使用枚举类型(如列表)来做循环操作是很常见的。对对象列表进行枚举时,
16+
通常要有选择性地过滤掉其中一些元素,还有可能做一些变换。
17+
列表速构(comprehensions)就是为此目的诞生的语法糖:把这些常见任务分组,
18+
放到特殊的```for```中执行。
1319

1420
例如,我们可以这样计算列表中每个元素的平方:
15-
```
21+
```elixir
1622
iex> for n <- [1, 2, 3, 4], do: n * n
1723
[1, 4, 9, 16]
1824
```
@@ -26,33 +32,35 @@ S = { X^2 | X ∈ [1,4], X ∈ N}
2632
一个列表速构由三部分组成:生成器,过滤器和收集器。
2733

2834
##18.2-生成器和过滤器
29-
在上面的例子中,```n <- [1, 2, 3, 4]```就是生成器。它字面意思上生成了即将要在速构中使用的数值。
30-
任何枚举类型都可以传递给生成器表达式的右端:
31-
```
35+
在上面的例子中,```n <- [1, 2, 3, 4]```就是生成器。
36+
它字面意思上生成了即将要在速构中使用的数值。任何枚举类型都可以传递给生成器表达式的右端:
37+
```elixir
3238
iex> for n <- 1..4, do: n * n
3339
[1, 4, 9, 16]
3440
```
3541
这个例子中的生成器是一个__范围__
3642

3743
生成器表达式支持模式匹配,它会忽略所有不匹配的模式。
38-
想象一下如果不用范围而是用一个键值列表,键只有```:good``````:bad```两种,来计算中间被标记成‘good’的元素的平方:
39-
```
44+
想象一下如果不用范围而是用一个键值列表,键只有```:good``````:bad```两种,
45+
来计算中间被标记成‘good’的元素的平方:
46+
```elixir
4047
iex> values = [good: 1, good: 2, bad: 3, good: 4]
4148
iex> for {:good, n} <- values, do: n * n
4249
[1, 4, 16]
4350
```
4451

4552
过滤器能过滤掉某些产生的值。例如我们可以只对奇数进行平方运算:
46-
```
53+
```elixir
4754
iex> require Integer
4855
iex> for n <- 1..4, Integer.odd?(n), do: n * n
4956
[1, 9]
5057
```
5158
过滤器会保留所有判断结果是非nil或非false的值。
5259

5360
总的来说,速构比直接使用枚举或流模块的函数提供了更精确的表述。
54-
不但如此,速构还接受多个生成器和过滤器。下面就是一个例子,代码接受目录列表,删除这些目录下的所有文件:
55-
```
61+
不但如此,速构还接受多个生成器和过滤器。下面就是一个例子,代码接受目录列表,
62+
删除这些目录下的所有文件:
63+
```elixir
5664
for dir <- dirs,
5765
file <- File.ls!(dir),
5866
path = Path.join(dir, file),
@@ -61,12 +69,14 @@ for dir <- dirs,
6169
end
6270
```
6371

64-
需要记住的是,在速构中,变量赋值这种事应在生成器中进行。因为在过滤器或代码块中的赋值操作不会反映到速构外面去。
72+
需要记住的是,在速构中,变量赋值这种事应在生成器中进行。
73+
因为在过滤器或代码块中的赋值操作不会反映到速构外面去。
6574

6675
## 18.2-比特串生成器
6776
速构也支持比特串作为生成器,而且这种生成器在组织处理比特串的流时非常有用。
68-
下面的例子中,程序从二进制数据(表示为<<像素1的R值,像素1的G值,像素1的B值,像素2的R值,像素2的G...>>)中接收一个像素的列表,把它们转换为元组:
69-
```
77+
下面的例子中,程序从二进制数据(表示为<<像素1的R值,像素1的G值,像素1的B值,
78+
像素2的R值,像素2的G...>>)中接收一个像素的列表,把它们转换为元组:
79+
```elixir
7080
iex> pixels = <<213, 45, 132, 64, 76, 32, 76, 0, 0, 234, 32, 15>>
7181
iex> for <<r::8, g::8, b::8 <- pixels>>, do: {r, g, b}
7282
[{213,45,132},{64,76,32},{76,0,0},{234,32,15}]
@@ -77,7 +87,7 @@ iex> for <<r::8, g::8, b::8 <- pixels>>, do: {r, g, b}
7787
在上面的例子中,速构返回一个列表作为结果。
7888
但是,通过使用```:into```选项,速构的结果可以插入到一个不同的数据结构中。
7989
例如,你可以使用比特串生成器加上```:into```来轻松地构成无空格字符串:
80-
```
90+
```elixir
8191
iex> for <<c <- " hello world ">>, c != ?\s, into: "", do: <<c>>
8292
"helloworld"
8393
```
@@ -86,7 +96,7 @@ iex> for <<c <- " hello world ">>, c != ?\s, into: "", do: <<c>>
8696

8797
例如,IO模块提供了流。流既是Enumerable也是Collectable。
8898
你可以使用速构实现一个回声终端,让其返回任何输入的东西的大写形式:
89-
```
99+
```elixir
90100
iex> stream = IO.stream(:stdio, :line)
91101
iex> for line <- stream, into: stream do
92102
...> String.upcase(line) <> "\n"
@@ -95,4 +105,3 @@ iex> for line <- stream, into: stream do
95105

96106
现在在终端中输入任意字符串,你会看到同样的内容以大写形式被打印出来。
97107
不幸的是,这个例子会让你的shell陷入到该速构代码中,只能用Ctrl+C两次来退出。
98-

19-sigils.md

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
19-魔法印(Sigils)
22
==========
3-
[正则表达式](#191-%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F) <br/>
4-
[字符串、字符列表和单词魔法印](#192-%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%AD%97%E7%AC%A6%E5%88%97%E8%A1%A8%E5%92%8C%E5%8D%95%E8%AF%8D%E9%AD%94%E6%B3%95%E5%8D%B0) <br/>
5-
[自定义魔法印](#193-%E8%87%AA%E5%AE%9A%E4%B9%89%E9%AD%94%E6%B3%95%E5%8D%B0) <br/>
63

7-
>看看标题,这个“魔法印”是什么奇葩翻译?Sigil原意是“魔符,图章,印记”,如古代西方魔幻传说中的巫女、魔法师画的封印或者召唤魔鬼的六芒星,中国道士画的咒符,火影里面召唤守护兽的血印等。
4+
>看看标题,这个“魔法印”是什么奇葩翻译?
5+
Sigil原意是“魔符,图章,印记”,
6+
如古代西方魔幻传说中的巫女、魔法师画的封印或者召唤魔鬼的六芒星,
7+
中国道士画的咒符,火影里面召唤守护兽的血印等。
88
在计算机编程领域,Sigil指的是在变量名称上做的标记,用来标明它的作用域或者类型什么的。
9-
例如某语言里面```$var```中的```$```就是这样的东西,表示其为全局变量。
10-
这么看,翻译成“魔法印”还挺带感呢。
9+
例如某语言里面```$var```中的```$```就是这样的东西,表示其为全局变量。
10+
不同的魔法印赋予变量不同的属性,这么看,翻译成“魔法印”还挺带感呢。
11+
本章(或者本文)所有的*sigil*都会翻译成“魔法印”或是采用英文原文。
1112

1213
我们已经学习了Elixir提供的字符串(双引号包裹)和字符列表(单引号包裹)。
1314
但是对于Elixir中所有的*文本描述型数据类型*来说,这些只是冰山一角。其它的,例如*原子*也是一种文本描述型数据类型。
@@ -62,32 +63,34 @@ true
6263
## 19.2-字符串、字符列表和单词魔法印
6364
除了正则表达式,Elixir还提供了三种魔法印。
6465

65-
```~s``` 魔法印用来生成字符串,类似双引号的作用:
66+
魔法印```~s``` 用来生成字符串,类似双引号的作用:
6667
```elixir
6768
iex> ~s(this is a string with "quotes")
6869
"this is a string with \"quotes\""
6970
```
7071
通过这个例子可以看出,如果文本中有双引号,又不想逐个转义,可以用这种魔法印来包裹字符串。
7172

72-
```~c``` 魔法印用来生成字符列表
73+
魔法印```~c``` 用来生成字符列表
7374
```elixir
7475
iex> ~c(this is a string with "quotes")
7576
'this is a string with "quotes"'
7677
```
7778

78-
```~w``` 魔法印用来生成单词,以空格分隔开:
79+
魔法印```~w``` 用来生成单词,以空格分隔开:
7980
```elixir
8081
iex> ~w(foo bar bat)
8182
["foo", "bar", "bat"]
8283
```
8384

84-
```~w``` 魔法印还接受```c``````s``````a```修饰符(分别代表字符列表,字符串和原子)来选择结果的类型:
85+
魔法印```~w``` 还接受```c``````s``````a```修饰符(分别代表字符列表,字符串和原子)
86+
来选择结果的类型:
8587
```elixir
8688
iex> ~w(foo bar bat)a
8789
[:foo, :bar, :bat]
8890
```
8991

90-
除了小写的魔法印,Elixir还支持大写的魔法印。如,```~s``````~S```都返回字符串,前者会解释转义字符而后者不会:
92+
除了小写的魔法印,Elixir还支持大写的魔法印。如,```~s``````~S```都返回字符串,
93+
前者会解释转义字符而后者不会:
9194
```elixir
9295
iex> ~s(String with escape codes \x26 interpolation)
9396
"String with escape codes & interpolation"
@@ -152,7 +155,8 @@ def convert(...)
152155
```
153156

154157
### 19.3-自定义魔法印
155-
本章开头提到过,魔法印是可扩展的。事实上,魔法印```~r/foo/i```等于是用两个参数调用了函数```sigil_r```:
158+
本章开头提到过,魔法印是可扩展的。事实上,魔法印```~r/foo/i```等于是
159+
用两个参数调用了函数```sigil_r```:
156160
```elixir
157161
iex> sigil_r(<<"foo">>, 'i')
158162
~r"foo"i
@@ -163,14 +167,17 @@ iex> h sigil_r
163167
...
164168
```
165169

166-
我们也可以通过实现相应的函数来提供我们自己的魔法印。例如,我们来实现一个```~i(N)```魔法印,返回整数:
170+
我们也可以通过实现相应的函数来提供我们自己的魔法印。例如,我们来实现一个```~i(N)```魔法印,
171+
返回整数:
167172
```elixir
168173
iex> defmodule MySigils do
169174
...> def sigil_i(string, []), do: String.to_integer(string)
170175
...> end
171176
iex> import MySigils
172177
iex> ~i("13")
173178
13
174-
```
175-
魔法印通过宏,可以用来做一些发生在*编译时*的工作。例如,正则表达式在编译时会被编译,而在执行的时候就不必再被编译了。
179+
```
180+
181+
魔法印通过宏,可以用来做一些发生在*编译时*的工作。例如,正则表达式在编译时会被编译,
182+
而在执行的时候就不必再被编译了。
176183
如果你对此主题感兴趣,可以多阅读关于宏的资料,并且阅读Kernel模块中那些魔法印的实现。

0 commit comments

Comments
 (0)