1. 复合表达式¶

Julia¶

Julia 有两个组件来完成这个： begin 代码块 和 (;) 链。这两个复合表达式组件的值都是最后一个子表达式的值。

In [1]:
z = begin
x = 1
y = 2
x + y
end

Out[1]:
3

In [2]:
z = (x = 1; y = 2; x+y)

Out[2]:
3
In [3]:
begin x = 1; y = 2; x + y end

Out[3]:
3
In [4]:
(x = 1;
y = 2;
x + y)

Out[4]:
3

Python¶

Pyton中使用; 链

In [5]:
x = 1; y = 2; z = x+y
print(z)

3


R¶

R中也使用; 链

x = 1; y = 2; z = x+y print(z)

2. 条件表达式¶

Julia¶

In [1]:
function test(x, y)
if x < y
println("x is less than y")
elseif x > y
println("x is greater than y")
else
println("x is equal to y")
end
end

Out[1]:
test (generic function with 1 method)
In [2]:
test(1,2)

x is less than y


if 代码块是"有渗漏的"，也就是说它们不会引入局部作用域。这意味着在 if 语句中新定义的变量依然可以在 if 代码块之后使用，尽管这些变量没有在 if 语句之前定义过。所以，我们可以将上面的 test 函数定义为

In [3]:
function test(x,y)
if x < y
relation = "less than"
elseif x == y
relation = "equal to"
else
relation = "greater than"
end
println("x is ", relation, " y.")
end

Out[3]:
test (generic function with 1 method)
In [4]:
test(2,1)

x is greater than y.


if 代码块也会返回一个值，这个返回值就是被执行的分支中最后一个被执行的语句的返回值:

In [6]:
x = -3
if x > 0
"positive!"
else
"negative..."
end

Out[6]:
"negative..."

In [7]:
if 1
println("true")
end

TypeError: non-boolean (Int64) used in boolean context

Stacktrace:
[1] top-level scope at In[7]:1

Python¶

In [3]:
def test(x, y):
if x < y:
relation = "less than"
elif x == y:
relation = "equal to"
else:
relation = "greater than"
print("x is ", relation, " y.")

In [4]:
test(2,1)

x is  greater than  y.


R¶

In [19]:
test  <- function(x, y) {
if(x < y) {
relation = "less than"
} else if(x == y) {
relation = "equal to"
} else {
relation = "greater than"
}
cat("x is ", relation, " y.")
}

In [20]:
test(2,1)

x is  greater than  y.

3. 三元运算符¶

Julia¶

In [9]:
test(x, y) = println(x < y ? "x is less than y"    :
x > y ? "x is greater than y" : "x is equal to y")

Out[9]:
test (generic function with 1 method)
In [10]:
test(1,2)

x is less than y

In [11]:
v(x) = (println(x); x)

Out[11]:
v (generic function with 1 method)
In [13]:
1 < 2 ? v("yes") : v("no")

yes

Out[13]:
"yes"

Python¶

Python中没有直接的三元运算符

In [2]:
'True' if 2 > 1 else 'False'

Out[2]:
'True'
In [1]:
'True' if 2 < 1 else 'False'

Out[1]:
'False'

R¶

In [4]:
x <- 2
ifelse(x == 2, print("yes"), print("no"))

[1] "yes"

'yes'
In [9]:
? <- function(x, y)
eval(
sapply(
strsplit(
deparse(substitute(y)),
":"
),
function(e) parse(text = e)
)[[2 - as.logical(x)]])

In [5]:
? <- function(x, y) {
xs <- as.list(substitute(x))
if (xs[[1]] == as.name("<-")) x <- eval(xs[[3]])
r <- eval(sapply(strsplit(deparse(substitute(y)), ":"), function(e) parse(text = e))[[2 - as.logical(x)]])
if (xs[[1]] == as.name("<-")) {
xs[[3]] <- r
eval.parent(as.call(xs))
} else {
r
}
}

In [10]:
TRUE ? x*2 : 0

2
In [8]:
FALSE ? x*2 : 0

0

4. 短路求值¶

Julia¶

• 在表达式 a && b 中，子表达式 b 仅当 a 为 true 的时候才会被执行。
• 在表达式 a || b 中，子表达式 b 仅在 a 为 false 的时候才会被执行。

In [1]:
t(x) = (println(x); true)

f(x) = (println(x); false)

Out[1]:
f (generic function with 1 method)
In [2]:
t(1) && t(2)

1
2

Out[2]:
true
In [3]:
f(1) && t(2)

1

Out[3]:
false
In [4]:
t(1) || f(2)

1

Out[4]:
true
In [5]:
f(1) || f(2)

1
2

Out[5]:
false

In [1]:
function fact(n::Int)
n >=0 || error("n must be non-negative")
n == 0 && return 1
n * fact(n-1)
end

Out[1]:
fact (generic function with 1 method)
In [3]:
fact(5)

Out[3]:
120
In [5]:
fact(-1)

n must be non-negative

Stacktrace:
[1] error(::String) at ./error.jl:33
[2] fact(::Int64) at ./In[1]:2
[3] top-level scope at In[5]:1

Python¶

Python的布尔运算符同Julia、R不同

In [7]:
True & False

Out[7]:
False
In [4]:
False & True

Out[4]:
False
In [6]:
False | False

Out[6]:
False
In [5]:
False | True

Out[5]:
True

R¶

R同Julia一样

In [21]:
TRUE && TRUE

TRUE
In [25]:
TRUE && FALSE

FALSE
In [22]:
FALSE || FALSE

FALSE
In [23]:
FALSE || TRUE

TRUE

5. 重复执行：循环¶

Julia¶

In [1]:
i = 1
while i <= 5
println(i)
global i+=1
end

1
2
3
4
5

In [2]:
i

Out[2]:
6

for 循环与之前 while 循环的一个非常重要区别是作用域，即变量的可见性。如果变量 i 没有在另一个作用域里引入，在 for 循环内，它就只在 for 循环内部可见，在外部和后面均不可见。

In [3]:
for j in 1:5
println(j)
end

1
2
3
4
5

In [4]:
j

UndefVarError: j not defined

Stacktrace:
[1] top-level scope at In[4]:1

In [1]:
i = 1
while true
println(i)
if i >= 5
break
end
global i += 1
end

1
2
3
4
5

In [2]:
for j ∈ 1:1000
println(j)
if j >= 5
break
end
end

1
2
3
4
5


In [1]:
for i = 1:10
if i % 3 != 0
continue
end
println(i)
end

3
6
9


Python¶

In [1]:
j = 1
while j <= 5:
print(j)
j += 1

1
2
3
4
5

In [2]:
j

Out[2]:
6

Python同Julia不同的是，其for 循环与之前 while 循环的一个都具有变量的可见性

In [6]:
for n in range(5):
print(n)

0
1
2
3
4

In [7]:
n

Out[7]:
4
In [1]:
for n in range(100):
print(n)
if n >= 5:
break

0
1
2
3
4
5

In [3]:
for i in range(10):
if i % 3 != 0:
continue
print(i)

0
3
6
9


R¶

In [3]:
i <- 1
while(i <= 5) {
print(i)
i <- i + 1
}

[1] 1
[1] 2
[1] 3
[1] 4
[1] 5

In [4]:
i

6

R同Python一样，其for 循环与之前 while 循环的一个都具有变量的可见性

In [7]:
for(m in 1:5) {
print(m)
}

[1] 1
[1] 2
[1] 3
[1] 4
[1] 5

In [8]:
m

5

break用法Julia、Python和R三种语言用法相同

In [1]:
for(j in 1:5){
print(j)
if(j >= 5){
break
}
}

[1] 1
[1] 2
[1] 3
[1] 4
[1] 5


Julia¶

Julia中使用try/catch 语句可以用来捕获 Exception，并进行异常处理

In [1]:
f(x) = try
sqrt(x)
catch
sqrt(complex(x, 0))
end

Out[1]:
f (generic function with 1 method)
In [2]:
f(1)

Out[2]:
1.0
In [3]:
f(-1)

Out[3]:
0.0 + 1.0im

try/catch 语句允许保存 Exception 到一个变量中。在下面这个做作的例子中，如果 x 是可索引的，则计算 x 的第二项的平方根，否则就假设 x 是一个实数，并返回它的平方根：

In [15]:
sqrt_second(y) = try
sqrt(x[2])
catch y
if isa(y, DomainError)
sqrt(complex(x[2], 0))
elseif isa(y, BoundsError)
sqrt(x)
end
end

Out[15]:
sqrt_second (generic function with 1 method)
In [16]:
sqrt_second([1 4])

In [17]:
show(sqrt_second([1, -4]))

nothing
In [18]:
sqrt_second(9)


finally 子句¶

In [ ]:
f = open("file")
try
# operate on file f
finally
close(f)
end


Python¶

Python中使用try-except-else-finally结构

try：#同Julia和R一样
some code
except:  #捕捉try代码中的异常，并根据异常进一步进行处理，相当于Julia和R中的catch
code
else：  #如果没有异常则执行else
code
finally：
code  #同Julia和R一样

In [14]:
import numpy as np
def div(x, y):
try:
ans = divide(x, y)
except:
print("the input is less than 0")
else:
print(np.ceil(ans))
finally:
print("2018.12.25, MC")

In [13]:
div(2, 0)

the input is less than 0
2018.12.25, MC


R¶

R中的tryCatch除了可以处理报错外，同样可以对错误（由stop产生）、警告（由warning）和消息（由message产生）采取不同的行动。其将条件映射到处理程序（handler），它们是一些以条件作为输入的命名函数。当条件发生时，tryCatch调用名字与任何一个条件类相匹配的第一个处理程序。所有可以应用的内置名字有error, warning, message, interrupt和全部匹配condition。处理程序可以做任何事情，但通常使用它返回一个值或创建一条包含更多信息的错误消息。例如，下面show_condition()函数创建一个可以返回触发条件类型的处理程序：

In [1]:
show_condition <- function(code) {
tryCatch(code,
error = function(c) "error",
warning = function(c) "warning",
message = function(c) "message"
)
}

In [2]:
show_condition(stop("!"))

'error'
In [3]:
show_condition(warning("00"))

'warning'
In [5]:
show_condition(message(":?"))

'message'
In [6]:
# 如果没有异常被捕捉到，tryCatch就直接返回输入值
show_condition(10)

10

In [11]:
read.csv2 <- function(file,...) {
c$message <- paste0(c$message, " (in", file, ")")
stop(c)
})
}


7. Task(协程)¶

Julia¶

Task 是一种允许计算以更灵活的方式被中断或者恢复的流程控制特性。这个特性有时被叫做其它名字，例如，对称协程（symmetric coroutines），轻量级线程（lightweight threads），合作多任务处理（cooperative multitasking），或者单次续延（one-shot continuations）。

Julia 提供了 Channel 机制来解决这个问题。一个 Channel 是一个先进先出的队列，允许多个 Task 对它可以进行读和写。

In [ ]:
function producer(c::Channel)
put!(c, "start")
for n ∈ 1:4
put!(c, 2n)
end
put!(c, "stop")
end

In [17]:
chnl = Channel(producer)

Out[17]:
Channel{Any}(sz_max:0,sz_curr:1)
In [6]:
take!(chnl)

Out[6]:
"start"
In [7]:
take!(chnl)

Out[7]:
2
In [8]:
take!(chnl)

Out[8]:
4
In [18]:
[take!(chnl), take!(chnl), take!(chnl), take!(chnl), take!(chnl), take!(chnl)]

Out[18]:
6-element Array{Any,1}:
"start"
2
4
6
8
"stop" 
In [16]:
take!(chnl)

InvalidStateException("Channel is closed.", :closed)

Stacktrace:
[1] check_channel_state at ./channels.jl:120 [inlined]
[2] take_unbuffered(::Channel{Any}) at ./channels.jl:318
[3] take!(::Channel{Any}) at ./channels.jl:306
[4] top-level scope at In[16]:1

In [11]:
for x in Channel(producer)
println(x)
end

start
2
4
6
8
stop


In [ ]:
function mytask(myarg)
...
end

# or, equivalently


yieldto 功能强大，但大多数 Task 的使用都不会直接调用它。思考为什么会这样。如果你切换当前 Task，你很可能会在某个时候想切换回来。但知道什么时候切换回来和那个 Task 负责切换回来需要大量的协调。例如，put!take! 是阻塞操作，当在渠道环境中使用时，维持状态以记住消费者是谁。不需要人为地记录消费 Task，正是使得 put! 比底层 yieldto 易用的原因。

• current_task 获取当前运行 Task 的索引。
• istaskdone 查询一个 Task 是否退出.
• istaskstarted 查询一个 Task 是否已经开始运行。
• task_local_storage 操纵针对当前 Task 的键值存储。

Taskstate 属性来描述他们的执行状态。Task state 有：

:runnable 正在运行，或者可以被切换到

:waiting 被阻塞，等待一个特定事件

:queued 处在调度器中的运行队列中，即将被重启

:done 成功结束执行

:failed 以一个没被捕获的异常结束