Tcler 的 Python 学习概要:程序语法之命令和函数

大多数时候,对于程序语言的追溯,可以从汇编语言开始。

汇编语言- Assembly Language

程序是要运行在计算机上的,计算机首先是一个硬件系统。从程序的角度看,它主要的“部件”有:

  • CPU里面的寄存器 - 通过寄存器名字进行访问
  • 内存 - 通过内存地址进行访问
  • 各种外部设备 - 映射为特殊的“内存地址”来进行访问

这样一来,对计算机的控制很自然地可以描述为诸如下面这样的描述

#1. 把存放在内存地址61h的数字读取到名字为AL的寄存器里
#2. 让CPU把AL里的数值+1
#3. 把AL里的数值输出到地址为83h的设备端口去

这样的描述,实际上就是对计算机“发号施令”,可以看作是一条条的命令。把这些命令用简短的文字描述,就成了汇编语言。

LDA AL, 61H          ;# 读取61H处的数据到AL寄存器
INC AL               ;# AL寄存器值+1
STA AL, 83H          ;# 把AL寄存器的值输出到地址83H

C 程序 - 函数才是高级的

用汇编写程序太“低级”,有点像小孩过家家。人们需要高级点的东西,比如计算一个三角函数。

double value = sin(x);

这时,函数这个概念就比“命令”这个概念显得有用多了。写程序某种程度上指的就是调用别人写好的函数(库函数)和自己编写函数。

函数的形式习惯上是写成 f(x) 这样。所以,程序语言的语法都集成了这个特点。

Shell 程序

时间顺序上,可以认为是先有了C程序,然后才有了Shell程序。

因为需要利用计算机进行的任务是多种多样的,为每一种任务都开发一个C程序是“不切实际”的,而且很多时候我们可以通过组合使用多个已经有的程序来实现计算任务。

比如,找出目录下面占用磁盘最多的文件,可以通过组合使用finddusort三个已有的程序来实现。

find . -type f | xargs du -k | sort -n

这种描述,就更像是人们针对计算机发出的命令。

从汇编这种“命令”到C语言这种“函数”,再到Shell这种“命令”构成一个螺旋式的层次结构。

脚本语言 Perl/PHP/Python/Node.js

螺旋不会停止。从C语言的函数到Shell脚本的命令,人们又先后发明了其他程序语言来简化程序的开发。粗略地说,按照时间顺序,

  1. Perl - 一只骆驼
  2. PHP - 一只大象
  3. Python - 一条蟒蛇
  4. Node.js - 没有“吉祥物”

这几个先后流行过地脚本语言都沿袭了C的基本理念——调用函数,编写函数。

以命令为主的 Lisp / Tcl

Tcl可以看作是Lisp的一种变种,都是几乎快被遗忘的。

比较一下一个创建文件目录的操作

用C语言也好,Python也好,语法上,基本上都还是函数的样子

dir_name = "test-dir";
mkdir(dir_name);

用Tcl的话,则是“命令”的样子

set dir_name "test-dir"
file mkdir $dir_name

函数好还是命令好?

“函数好还是命令好”这种问题是典型的容易自讨没趣的问题。辩证法会很随意地回答“要辨证地看嘛”。

C或者Python这类语言虽然核心是函数,但是诸如流程控制这样的操作却避免不了命令式的描述。

C语言代码:

if( score<3 ){
  printf("Win\n");
} else {
  printf(Lose\n");
}

Python代码:

if score<3:
  print("Win")
else:
  print("Lose")

上面的if语句显然不是一个函数,而是类似于“命令”的控制语句。

Tcl语言里,则看起来是这个样子:

if {$score<3} {
  puts "Win"
} else {
  puts "Lose"
}

if语句的形式看起来差不多。但在Tcl里,这个if语句实质上只是一个“特殊”的命令(Command)。

另一方面,诸如数学运算这类操作,Tcl也需要用函数来表示

set value [expr {sin($x)}]

函数还是命令?

“和稀泥”式的两者“大同小异”虽然不大容易辩驳。但正如最好不要同时“脚踩两只船”一样,采用什么样的主次关系是对思维模式是有影响的。

函数,强调的是接口。尤其是这些年有些流行的程序语言里的高阶函数。一个函数甚至可以作为另一个函数的参数进行传递。接口的背后是隐藏实现的细节。

命令,则相对来说关注“步骤”更多一些。至于每个步骤实现的细节,那不是发布命令的人要操心的。如同领导安排任务重要的是得到想要的结果,实现细节不是领导要操心的。

接口和命令,细思之下,可能又会觉得好像差不多,都是某种“契约”或“约定”。但应该还是有一些不同,函数的粒度一般更细一些,命令的粒度则要大一些。粒度越大,概念角度来说一般更抽象,约束一般也更模糊一些。导致的结果的话,工程角度看,也许函数式的思维更利于分工细化。

但个人更喜欢Tcl这种命令式的形式多一些。因为这种命令式的描述更贴近我们的语言习惯。在Tcl这类语法思维下,写程序可以跟写文章一样。