2009年6月7日星期日

公历农历互转的Ruby实现

网上只能找到公历转换到农历的程序,反过来的Ruby实现似乎没有,所以就自己写了个,取名rbCCal。程序采用查表法,大约能实现公元1900年至2100年间200年的公历和农历互转。

数据部分出自Zhuo Meng的CCAL,该程序用GPL发布,所以rbCCal也用GPL发布。

代码放在Github。其实觉得Google Code会更靠谱些,个人用SVN和Git也不会有太大区别。可这个站是Ruby写的,而且还很漂亮。

另,因为Github只支持ASCII和UTF-8,为了能在网站上显示中文,我只好将代码存成了UTF-8,这样在Windows里直接用就会有问题。需要的话请将代码保存为GBK,或者重载LunarDate类。

下载请往这边走:https://github.com/oTnTh/ccal

require 'ccal'

l = Time.now.to_lunar()
puts l.lyear, l.lmonth, l.lday
puts Time.from_lunar(l.lyear, l.lmonth, l.lday)

l = Date.new(2009, 6, 4).to_lunar()
puts l.to_s()
puts Date.from_lunar(l.lyear, l.lmonth, l.lday)

2009年6月4日星期四

Mobile Over The Cloud

Apple MobileMe和Microsoft MyPhone都只支持特定平台,所以我的手机没法用,features倒是看起来很诱人。

Nokia Ovi用的是SyncML协议,理论上应该很多手机平台都支持。不过同步使用的密码需要以OTA的方式获得,非塞班手机能不能用没试过。支持同步通讯录、日历和记事本,貌似不错,可是服务器经常停机,频繁到影响使用的程度。

Google Sync则SyncML和ActiveSync两种协议都支持,S60上自然是用SyncML。有Google帐户就可以直接使用,能同步通讯录和日历。

因为我还没有忙到需要用计算机管理日程的程度,所以比较关注的只有通讯录一项。Ovi既然是Nokia出的,似乎应该对自家手机支持比较好才对,事实上也不尽然。

我先试了Google Sync,发现其不支持生日和备注字段。接着再试Ovi,生日备注是支持了,可是“手机(家庭)”字段却不会被同步。两家对vCard的支持只是半斤八两,都不算好。

Web端方面,Ovi差Google太多。Ovi的网站虽然比较华丽,但是速度太慢,经常停机,并且功能薄弱——连批量编辑和删除联系人的功能都没有。

个人信息中心这类东西,Google的优势应该比Nokia大很多。毕竟Google有Gmail、Gtalk,除了已经支持的Contacts和Calendar,还有Bookmark、Notebook,有心想做都是现成的。而且用Google,不必担心换了非Nokia非WinMo的手机就没法用。

在Google Sync进一步完善前(或许有得等),跟Ovi搭配着一起用或许是个不错的主意。

另,SyncML协议可以同步的东西其实很多,比如彩信和短信。不过我找了很久,都没有找到一家真正提供彩信同步功能的网站。国内有一家MyTT虽然号称可以支持,但实际上也不行。可以同步短信的倒是有好些,我试过之后发现也就O-Sync尚算可用。可是这家也不支持导出备份,总有一点点担心长期运营的问题。

2009年5月29日星期五

Side-Effect

近来说FP(函数式语言)很好很强大的人越来越多了,只是因为没需求,所以就一直没动力去学。也正是因为这样,我对副作用、引用透明之类的概念总是不甚了了。昨晚忍不住拽了一位童鞋聊了聊,算是有了点收获吧。

首先是引用透明,某童鞋的说法是:引用透明就是可以用函数的返回值代替函数的调用。

我觉得的这样的说法并不完整,于是写了这样一段代码问他:

int x;

int fa(int m, int n) {
  x = m + n;
  return x;
}

int fb(int z) {
  return x + z;
}

他说fa函数不算引用透明,因为用fa的返回值代替函数调用后,整个程序的运行结果会发生变化。可问题是,如果fb从来没调用过,且没有在其他地方读写过全局变量x的值呢?

于是试着总结一下,一个引用透明的函数,似乎应该满足以下三个条件:

  1. 只通过传值调用输入数据;
  2. 只通过返回值输出数据;
  3. 不且不能读取和修改函数外的任何其他数据。

如果一个程序中的所有函数都满足这三个条件,那么就可以保证所有函数的调用都可以用返回值来代替。

而所谓副作用指的是上述第三条。如此,“没有副作用即是不对环境产生影响”是一种没错,但是没说清楚的解释。

那么,“没有副作用即是没有变量的值发生变化”又是怎么一回事?以我的理解,这是一个混乱而错误的说法。

若我对引用透明的阐述没有错,那么所谓副作用就只是指针和作用域的问题。假如C语言中没有指针和全局变量(IO的部分另说),那么也可以说C的函数是引用透明的。

扯出变量,似乎只是命令式语言的习惯性思维作祟,因为在FP里是没有变量这种东西的。

假如在某一门FP里支持这样的语法:“int x=1”,这并非是“把整数1赋值给变量x”,而是“定义符号x代表整数1”,更像数学里的说法。即使有“x=x+1”这样的语法,也并不是“计算表达式并修改变量x的值”,而是“删除符号x与原有值的关系并重新定义一个”,内存中x原指向的1的值并没有发生变化,2被存到另外的地方去了。

事实上,FP中的“x=x+1”更有可能代表的意思是累加,即“x = (x + 1) = ((x + 1) + 1) = ...”

值只能被定义,不能被修改,岂不是又慢又浪费内存?又为什么要强调引用透明?仔细想想,却也不是没有好处的。

引用透明了,垃圾回收就容易了。可以定义无穷表,且定义时不需要计算其值,也就是所谓的延迟计算。编译器可以缓存一部分函数的运算结果,加速程序运行。无副作用,所以对并发友好,更容易发挥多核CPU的计算能力。

连我这种不会FP的人都能想到这么多好处,FP果然是种很天才的东西。

奇怪的是,除了emacs和唐凤的Perl6实现,怎么没见过用FP实现的其他东西?