Ocaml编程建议
参考文献:http://caml.inria.fr/resources/doc/guides/guidelines.en.html
.press "space key" as often as necessary
Pseudo spaces law: never hesitate to separate words of your programs with
spaces; the space bar is the easiest key to find on the keyboard, press it as
often as necessary
这样做另外的一个好处就是,让编辑器也更容易实时的理解我正在写什么。
例如,
假如我写
let x=Gr
然后按M-/,那么emacs会说
"No dynamic expansion for 'x=Gr' found "
但是如果我写
let x= Gr
然后案M-/,那么emacs会顺利的把我要写的东西补全为
let x= Graphics
.delimiters
每一个delimiter symbol后面都应该有一个空格。而且操作符的左右都应该是被空格包
围。
.如何写括号?
每个Tuple是应该用括号括起来的,Tuple的元素与元素之间应该用逗号分离,而且每个逗
号之后应该(should)有一个空格。例如
let x=(1, 2, 3);
例外:
.定义一对变量的时候
例如,let (x, y)=(3, 4);;
可以写作
let x, y = (3, 4);;
.同时Match很多个值
例如
match x, y with
| 1, _ -> ...
| x, 1 -> ...
| x, y -> ...
事实上这两种并不是例外。我们只不过是省略了Tuple的构造过程。而把几个变量并行
的处理。
如何写list?
e.g.
x :: l
解释::: 的左右两面都应该有空格,因为它是一个infix操作符(infix operator)。
而与之对应的一个例子是
(x, y, z)
','的右面有空格,而左面没有。因为逗号是一个 delimiter,而不是一个infix操作符
如何写操作符?
操作符的周围也是应该有空格的,但是具体该怎么添加,就要很注意了。因为如果添加在
了不适当的地方,不仅仅再是格式的问题,而是会导致语义的改变。
例如
x + y
加号的左面和右面都应该有空格。
而
x + !y
如果写成x+!y或者x + ! y都是错误的。
此处的加号和叹号(解引用)之间必须用空格分开,否则解释器会把+!当成 一个 多字符的
操作符来看待。
而叹号的右面则不能再有空格。与叹号类似的,'.'也是如此。
一个提醒:空格并不改变操作符的运算优先级。
例如
x * z-1
的实际语义是
(x*z) -1
而不是
x * (z-1)
添加空格的一个原则是:在不改变原语义的情况下,把操作符尽可能的用空格包围起来。
反正空格键很大,那就不要忘记敲空格吧。
如何书写过长的字符串?
列两种大家都比较熟悉的语言作一下比较。
C:
printf("%s","你好,我是孙长明,我十分喜欢C语言.\n"
"为什么呢?因为它简单\n");
sh:
echo "我对sh script的认识仅限于怎么对字符串换行\n\
:-)接下来的一行必须从开头写,不能有缩进\n"
caml:
print_string "caml和sh在这一点上看起来很类似。\n\
都是用同样的方式换行.\n\
不同的在于缩进\n";;
总结一下:
C语言:字符串会被预处理器自动连接,如果两个字符串常量之间出了空白字符外什么都
没有。
sh和ocaml,用\来换行。不同的是,对于caml,如果\出现在一行的末尾,那么下一行的开
头的空白字符都会被忽略。这样主要是为了程序书写的时候便于对齐。
代码编排的风格:
风格的一致性:
尽量用大家常见的方式来编排、对齐你的代码,并且在整个程序中保持一致。
页面的宽度:
由于大部分终端都是每行80个columns。(一个英文字母一般占一个columns,而汉字占两
个).而rfc2822中对邮件的建议也是每行不超过80字符(但是包括末尾的\r\n在内一共
80个)。所以为了阅读和传输方便,建议大家以设置下自己的编辑器,超过78个字符则自
动换行。
页面的高度:
一个函数最好能在一个屏幕内完整的显示,所以一般最好不要超过70行左右。如果你的函
数真的很长,那么请尝试着根据你所要解决的问题,把它分成几个小函数(子问题)来分
别实现。
关于Tab字符:
由于Tab字符(ASCII编码为9)在不同的机器上显示的效果不一样,所以建议大家最好不好
使用。尽量使用空格来分隔对齐文本。
不过如果你是正在使用emacs,那么请不妨多按Tab键,因为emacs的Tab键是用来自
动缩进,而不是插入一个Tab字符。
关于let的使用:
let f x = function
| C ->
| D ->
...;;
let g x =
let tmp =
match x with
| C ->
| x -> 0 in
tmp + 1;;
let 嵌套的时候,要注意缩进。
而使用let in的时候,in要和let写在同一行,并且下一行的第一个字符也要和上行的let对齐。
例如
let x = 3 in
x + 3;;
let x = 3 in
let y = x + 4 in
x+y;;
.关于if...then..else的使用
..多分支
统一的模式是:
if cond1 ...
if cond2 ...
if cond3 ...
如果then后面的表达式比较短的话,那么请尽可能的写成这样
if cond1 then e1 else
if cond2 then e2 else
if cond3 then e3 else
e4
否则,用begin...end把分支里面的语句括起来,并且如果下面还有else的话,把else和
end写在同行,且这行除了end,else之外不要有其它的非空白字符。
例如:
if cond then begin
e1
end else
if cond2 then begin
e2
end else
if cond3 then ...
另外一种建议是把else和else之后的if写在同行,例如
if cond1 ...
else if cond2 ...
else if cond3 ...
因为else if在很多语言中都是一个关键字。
至于如何选择,在于你的喜好。
.单分支
有很多种风格可供你选,选择哪种在于分支表达式的长短以及你的喜好。
如果两个分支的表达式都比较长,可以这么写
if cond then begin
e1
end else begin
e2
end
或者
if cond then
begin
e1
end else begin
e2
end
如果都比较短,可以这么写
if cond then e1 else e2
如果条件分支的表达式比较长,但是 是纯粹的函数式的表达式,没有副作用(side effect),那么请尽
量的使用let...in的方式来换行。
How to program
Always put your handiwork back on the bench,
and then polish it and re-polish it.
写程序的时候尽量不要 复制-粘贴
复制粘贴就意味着程序中有重复的代码,一旦出现了错误就需要到很多个地方去一一的修
改。
另外,重复代码越多,代码量也就越庞大。程序也就也难阅读、维护。
尽量不要在函数体的内部写注释,而是把注释写在函数的开头。
尽量的多使用assert函数。
例如
assert(x==3);;
如果x不等于3,那么系统会抛出一个Assert_failure异常。
对于imperative code组成的代码段,尽量给每一行代码的上方都添加上注释。
用匿名函数代替不必要的let...in,例如
(fun x y -> x + y)
e1 e2
代替
let x = e1
and y = e2 in
x + y
因为前者更易读。