<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title>libudi</title>
    <description></description>
    <link>http://libudi.javaeye.com</link>
    <language>UTF-8</language>
    <copyright>Copyright 2003-2008, JavaEye.com</copyright>
    <docs>http://blogs.law.harvard.edu/tech/rss</docs>
    <generator>JavaEye - 做最棒的软件开发交流社区</generator>
          <item>
        <title>lysee 官方网站开张营业</title>
        <author>libudi</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://libudi.javaeye.com">libudi</a>&nbsp;
                    链接：<a href="http://libudi.javaeye.com/blog/189155" style="color:red;">http://libudi.javaeye.com/blog/189155</a>&nbsp;
          发表时间: 2008年05月04日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          为保障 Lysee 的健康发展，我于近期创建了 Lysee 的官方网站 <a href="http://www.lysee.net" target="_blank">http://www.lysee.net</a>，从此 Lysee 算是有个正正经经的家了，欢迎感兴趣的朋友们访问。<br /><br /><div class="quote_title">引用</div><div class="quote_div"><img src="http://www.lysee.net/logo.png" /><br />Lysee 是一种小巧、快速、可靠、跨平台的脚本编程语言。它既可以直接嵌入到 Pascal 和 C/C++ 程序中为宿主程序提供强大的脚本处理能力，也可以通过键盘和显示器与程序员进行互动，或者批量执行为其指定的任何 Lysee 程序文件。Lysee 同样适用于网站开发，其代码可以直接嵌入到 HTML 页面中，就象 ASP 和 PHP 所做的那样。如果您是刚刚接触到 Lysee 并想了解它是怎样工作的，请阅读本站为您准备的在线文档、示例代码以及本站提供的其它资源。<br /><br /><strong>安装程序：</strong><br /><br /><ol><li>Windows: <a href="http://www.lysee.net/download/lysee110-1891-x86.exe" target="_blank">http://www.lysee.net/download/lysee110-1891-x86.exe</a></li><li>Linux: <a href="http://www.lysee.net/download/lysee110-1891-x86.tar.gz" target="_blank">http://www.lysee.net/download/lysee110-1891-x86.tar.gz</a></li></ol></div><br />理论上 Lysee 可以在数十种操作系统和 CPU 架构中编译运行，而目前我需要大量不同 CPU 架构、不同操作系统类型的编译主机进行验证，希望有条件的朋友能为 Lysee 提供编译主机和帐户，本人绝对保证不侵犯您的任何权益和隐私，谢谢！
          <br/><br/>
          <span style="color:red;">
            <a href="http://libudi.javaeye.com/blog/189155#comments" style="color:red;">已有 <strong>20</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">Windows7在微软WinHEC 2008上揭开神秘面纱</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sun, 04 May 2008 06:55:48 +0800</pubDate>
        <link>http://libudi.javaeye.com/blog/189155</link>
        <guid>http://libudi.javaeye.com/blog/189155</guid>
      </item>
          <item>
        <title>示例分析CALL/CC</title>
        <author>libudi</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://libudi.javaeye.com">libudi</a>&nbsp;
                    链接：<a href="http://libudi.javaeye.com/blog/128238" style="color:red;">http://libudi.javaeye.com/blog/128238</a>&nbsp;
          发表时间: 2007年09月29日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <strong>说明：此文内容纯属个人看法，无所谓对错，欢迎拍砖！</strong><br /><br />call/cc(call-with-current-continuation)是函数编程的顶级概念，虽然我们用到的场合不是太多，但重要性非比寻常。<br /><br />call/cc的魔力在于迫使运行的程序通过时光隧道返回到从前的某个时刻。<br /><br />从返回的方式看我们可以有多种理解，下面是最常见的两种：<br /><br />1、逐步退回：一步就是一次函数调用。执行call/cc时，程序自动执行函数返回操作（RET），直到返回的位置与call/cc的要求一致。<br /><br />2、直接跳转：程序的指令系统直接切换到call/cc的位置，被抛掉的运行节点和对象留给GC处理。<br /><br />命令式语言（如C/C++/PASCAL）可以很方便的实现第一种返回方式，比如使用异常和长跳转，但由于基于栈运行和缺乏GC支持，很难实现第二种返回方式。我们不在这里讨论语言的分类问题，而是通过一个例子，凭想象来推测一下call/cc背后都发生了些什么。<br /><br /><pre name="code" class="java">
void b(function cc)
{
  = "b";
  cc(); // 返回a()中创建cc对象后的下一条指令位置
}

void a()
{
  callcc cc() { = "a" }; // 创建cc对象，这里是个函数
  b(cc);
}
</pre><br /><br />现在运行函数a()并登记其运行过程：<br /><br /><pre name="code" class="java">
a()开始执行。
|__创建call/cc函数cc()。
|__跳过cc()的返回执行代码。
|__将cc传递到b()函数中加以执行。
...b()开始执行
...|__打印字符'b'
...|__执行cc()。
......cc()开始执行
......|___中断b()回到a()，指令系统指向cc()的返回执行代码。
|__打印字符'a'
|__回到步骤4。
</pre><br /><br />cc在第9步直接中断b()的运行回到a()并将指令系统指向cc()的返回执行代码，这一步是怎么发生的呢？<br /><br />一、可以确定cc至少携带了以下两个信息:<br /><br />1、a()的运行时信息（比如栈基址）。<br />2、cc返回执行代码的地址。<br /><br />我们用结构ccrec来描述它们：<br /><br /><pre name="code" class="java">
// call/cc 信息结构定义
struct ccrec {
  void * addr; // 函数运行时信息的地址
  unsigned long next; // 下一条指令的位置
}
</pre><br /><br />指令系统可以假定为以下设计：<br /><br /><pre name="code" class="java">
// 指令系统结构定义
struct isrec {
  struct ccrec current; // 当前运行时信息
  struct isrec *prior; // 上一级调用的指令系统结构
}

struct isrec *current; // 当前指令系统结构

void *get_call_base() // 提取当前运行时信息
{
  return current->current.addr;
}

unsigned long get_next_instruction() // 返回下一条指令的地址
{
  return current->current.next;
}

void set_next_instruction(unsigned long next) // 设置下一条指定的地址
{
  current->current.next = next;
}
</pre><br /><br />二、callcc创建cc对象后在其内部保存以上两条信息：<br /><br /><pre name="code" class="java">
// callcc 指令的处理过程
void * cc = create_function(); // 创建 cc 函数
struct ccrec * rec = create_new_ccrec(); 
rec->addr = get_call_base(); // 提取当前函数运行时信息
rec->next = get_next_instruction(); // 下一条即将执行的的指令
save_ccrec(cc, rec); // 保存信息到cc对象
</pre><br /><br />三、cc执行时重置了指令系统的状态:<br /><br /><pre name="code" class="java">
// 提取call/cc返回信息

struct ccrec * rec = load_ccrec(cc);

// 执行返回操作

while (rec->addr != get_call_base())
  exec_return(); //==> 它做了什么？

// 设置下一条指令

set_next_instruction(rec->next);
</pre><br /><br />函数exec_return()不应该太复杂，大致的是如下的代码：<br /><br /><pre name="code" class="java">
// 函数返回操作函数
void exec_return()
{
  // 1. 加锁休眠垃圾回收并返回当前指令系统结构
  struct isrec * curr = begin_return(); 

  // 2. 将当前运行时信息登记到垃圾回收系统
  gc_notify(curr);
 
  // 3. 设置指令系统，返回上一级调用
  current = curr->prior; 

  // 4. 完成返回操作后开锁，重新激活垃圾系统
  end_return(); 
}
</pre><br /><br />这样的想象和推测单从理解上说应该是完备的，基于这个理解，我们试着做些更深层次的发挥。
          <br/><br/>
          <span style="color:red;">
            <a href="http://libudi.javaeye.com/blog/128238#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">Windows7在微软WinHEC 2008上揭开神秘面纱</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Sat, 29 Sep 2007 16:12:22 +0800</pubDate>
        <link>http://libudi.javaeye.com/blog/128238</link>
        <guid>http://libudi.javaeye.com/blog/128238</guid>
      </item>
          <item>
        <title>Lysee 的语法定义</title>
        <author>libudi</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://libudi.javaeye.com">libudi</a>&nbsp;
                    链接：<a href="http://libudi.javaeye.com/blog/127777" style="color:red;">http://libudi.javaeye.com/blog/127777</a>&nbsp;
          发表时间: 2007年09月28日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          很高兴今天能发布这个声明：<br /><br />经过不懈努力，Lysee于今晨8:30释出1.1.0.5511版本，新版本初步实现了语法定义，帮助Lysee又向前“<strong>挪了</strong>”一步！<br /><br />首先向Scheme/Lisp、Haskell、Perl、Python还有其它语言表示一下尊敬：<br /><br /><pre name="code" class="java">
syntax void thanks(%(you) AND %(he))
{
  = "thanks!", you, "and", he;
}

thanks "scheme/lisp" AND "haskell, python, perl and others";
</pre><br /><br />“<strong>syntax</strong>”是为Lysee新定义的关键字，用于向语法分析器提示有必要在后续的代码中检测并使用新定义的语法。<br /><br />用“<strong>syntax</strong>”定义的语法只是一个再普通不过的函数，下面是前面定义的“thanks”语法的伪代码:<br /><br /><pre name="code" class="java">
public variant main(variant ARGS)
{
     PUSH_FUNC main::thanks //==> 将函数thanks压栈
     PUSH_STR scheme/lisp
     PUSH_STR "haskell, python, perl and others"
     CALL [3]
     POP
     RETURN
}

syntax void thanks(%(you) AND %(he)) //==> public void thanks(variant you he)
{
     PUSH_STR thanks!
     PUSH_VARB you
     PUSH_STR and
     PUSH_VARB he
     PRINT [4]
}
</pre><br /><br />原理:<br /><br />编译器将函数定义中<strong>%(ID)</strong>和<strong>%{ID}</strong>格式中的标识符登记为<strong>variant</strong>类型的参数，其它符号作为占位符被抛掉。<br /><br /><strong>%(ID)</strong> - 表示直接计算<strong>%(ID)</strong>所在位置的表达式，仅将结果传递给新函数。<br /><strong>%{ID}</strong> - 表示在编译时将<strong>%{ID}</strong>对应位置上的表达式转换为闭包。<br /><br />下面定义一个略微复杂的语法，实现<strong>Pascal</strong>中的<strong>repeat ... until</strong>循环：<br /><br /><pre name="code" class="java">
// 定义 repeat .. until 语法

syntax void repeat(%(STATEMENT) until %{FALSE})
{
  do { STATEMENT() } while (not FALSE());
}

// 使用

int guess, magic = 5;
repeat { 
  guess = sys::random(10);
  = guess, eol;
} until (guess == magic);
 
// 输出

7
0
3
4
2
5

</pre><br /><br />看到这儿，研究FP的朋友们应该可以会心的笑了，看看下面的伪代码就更清楚了<br /> <br /><pre name="code" class="java">
public variant main(variant ARGS)
{
     VARB guess: int
     VARB magic: int
     PUSH_INT 5
     SAVE_TO magic
     POP
     PUSH_FUNC main::repeat //==> repeat ... until
     PUSH_SUBF main::main.1 //==> STATEMENT
     PUSH_SUBF main::main.2 //==> FALSE
     CALL [3]
     POP
     RETURN
}

public variant main.1() //==> STATEMENT
{
     PUSH_FUNC sys::random
     PUSH_INT 10
     CALL [2]
     SAVE_TO guess
     POP
     PUSH_VARB guess
     PUSH EOL
     PRINT [2]
     RETURN
}

public variant main.2() //==> FALSE
{
     PUSH_VARB guess
     PUSH_VARB magic
     CALC ==
     RETURN [1]
}

syntax void repeat(%(STATEMENT) until %{FALSE})
{
0000:PUSH_VARB STATEMENT //==> main.1
     CALL [1]
     POP
     PUSH_VARB FALSE //==> main.2
     CALL [1]
     CALC NOT
     JMPT 0000: POP
}
</pre><br /><br />再举一个常见的<strong>for_each</strong>语法定义，真是很简单:<br /><br /><pre name="code" class="java">
syntax void for_each(%(LIST): %(PROC)) // 要求LIST必须支持each操作
{
  LIST.each(PROC);
}

// 调用

for_each strlist("hello\nworld\n!"): {|string item| = item, eol}; 

// 输出

hello
world
!
</pre><br /><br />语法定义扎根在函数闭包上，怎么优化函数闭包的生成、使用和释放，如何节省系统资源仍然还是个大问题。<br /><br />总结一下：语法定义是个好东西，但使用的代价可能不菲，特别是过分滥用时会破坏我们已有的代码。
          <br/><br/>
          <span style="color:red;">
            <a href="http://libudi.javaeye.com/blog/127777#comments" style="color:red;">已有 <strong>3</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">Windows7在微软WinHEC 2008上揭开神秘面纱</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 28 Sep 2007 09:30:04 +0800</pubDate>
        <link>http://libudi.javaeye.com/blog/127777</link>
        <guid>http://libudi.javaeye.com/blog/127777</guid>
      </item>
          <item>
        <title>模式匹配的实现和使用</title>
        <author>libudi</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://libudi.javaeye.com">libudi</a>&nbsp;
                    链接：<a href="http://libudi.javaeye.com/blog/127516" style="color:red;">http://libudi.javaeye.com/blog/127516</a>&nbsp;
          发表时间: 2007年09月27日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          模式匹配是个老概念了，它并不是函数式编程的必须内容，但函数式语言通常都实现了模式匹配，而大部分的命令式语言都空缺了这一块儿，所以给大家留下的印象就是模式匹配只在函数式编程中出现。<br /><br />下面是一个常规的Fib编码：<br /><br /><pre name="code" class="java">
public int fib(int n)
{
  if (n &lt; 2) return 1;
  return fib(n - 2) + fib(n - 1);
}

// 伪代码
public int fib(int n)
{
     PUSH_VARB n
     PUSH_INT 2
     CALC &lt;
     JMPF 0006: POP
     PUSH_INT 1
     RETURN [1]
0006:PUSH_FUNC main::fib
     PUSH_VARB n
     PUSH_INT 2
     CALC -
     CALL [2]
     PUSH_FUNC main::fib
     PUSH_VARB n
     PUSH_INT 1
     CALC -
     CALL [2]
     CALC +
     RETURN [1]
     RETURN
}
</pre><br /><br />再看一下模式匹配的写法：<br /><br /><pre name="code" class="java">
public int fib(int n ? n &lt; 2) // 要求: n &lt; 2
{
  return 1;
}

public int fib(int n) 
{
  return fib(n - 2) + fib(n - 1);
}

// 伪代码
public int fib(int n)
{
     PUSH_VARB n
     PUSH_INT 2
     CALC &lt;
     JMPF 0007: POP
     PUSH_INT 1
     RETURN [1]
     RETURN
0007:PUSH_FUNC main::fib
     PUSH_VARB n
     PUSH_INT 2
     CALC -
     CALL [2]
     PUSH_FUNC main::fib
     PUSH_VARB n
     PUSH_INT 1
     CALC -
     CALL [2]
     CALC +
     RETURN [1]
     RETURN
}
</pre><br /><br />对比两种编码的伪代码可以看出编译器对模式匹配函数自动添加了检测执行代码并进行了函数合并。一切就是这么简单。<br /><br />模式匹配通常用于替代函数功能级的复杂分支语句，比如嵌套的<strong>if</strong>语句或<strong>switch</strong>语句。它的优点是在语法上实现了代码分离，有新的编码要求时只需增加新匹配模式或者删改已有的匹配模式即可，程序员无须维护一个复杂的分支函数。<br /><br />下面举一个使用模式匹配的简单例子：<br /><br /><pre name="code" class="java">
&lt;html>
&lt;head>
&lt;title>查看&lt;/title>
&lt;/head>
&lt;body>
&lt;% ==> begin CGI
public void display(string table id_field content_field click_field ID)
{
  // 显示内容

  = sys::db().selectStr(@"SELECT %(content_field) FROM %(table) 
    WHERE %(id_field)='%(ID)'").html();

  // 增加点击量

  sys::db().execSQL(@"UPDATE %(table) SET %(click_field)=%(click_field)+1
    WHERE %(id_field)='%(ID)'");
}

// 建立模式匹配
 
public void view(string cate ID ? cate == "news") // 新闻
{
  display("news", "news_ID", "news_content", "news_clicks", ID);
}
 
public void view(string cate ID ? cate == "file") // 文章
{
  display("files", "file_ID", "file_content", "file_view_count", ID);
}
 
public void view(string cate ID ? cate == "msg")  // 消息
{
  display("msgs", "msg_ID", "msg_content", "msg_clicks", ID);
}
 
// 执行模式匹配

view(${request.cate}, ${request.ID}); 
==> END CGI %>
&lt;/body>
&lt;/html> 
</pre><br /><br />是否使用模式匹配是个习惯问题，也是个经验问题，有时只是老板个人的问题。<br /><br />从技术上讲，条件越复杂，模式匹配就越有用，这点是可以肯定的。
          <br/><br/>
          <span style="color:red;">
            <a href="http://libudi.javaeye.com/blog/127516#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">Windows7在微软WinHEC 2008上揭开神秘面纱</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 27 Sep 2007 11:04:53 +0800</pubDate>
        <link>http://libudi.javaeye.com/blog/127516</link>
        <guid>http://libudi.javaeye.com/blog/127516</guid>
      </item>
          <item>
        <title>Lysee 的运算符</title>
        <author>libudi</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://libudi.javaeye.com">libudi</a>&nbsp;
                    链接：<a href="http://libudi.javaeye.com/blog/123752" style="color:red;">http://libudi.javaeye.com/blog/123752</a>&nbsp;
          发表时间: 2007年09月14日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          Lysee 表达式中的运算符按优先级排列分为以下几种:<br /><br /><pre name="code" class="java">
NEG   : -   |  NOT : not | BNOT: ~  | FMT : @  |          |        | 单目  : 最高
MUL   : *   |  DIV : /   | IDIV: \  | MOD : %  |          |        | 乘除模:  1
ADD   : +   |  DEC : -   |          |          |          |        | 加减  :  2
BXOR  : ^   |  BAND: &   | BOR : |  | BSHL: &lt;&lt; | BSHR: >> |        | 位运算:  3
MKPAIR:     |  IS  : is  | AS  : as |          |          |        | 测试  :  4
EQ    : ==  |  NE  : !=  | LT  : &lt;  | LE  : &lt;= | GT  : >  | GE: >= | 比较  :  5
AND   : and |  OR  : or  |          |          |          |        | 关系  : 最低
</pre><br /><br /><strong>1、单目运算符：</strong><br /><br />单目运算符的级别最高，包括：<br /><br />&nbsp;&nbsp;&nbsp; A、NEG : 负数运算<br />&nbsp;&nbsp;&nbsp; B、NOT : 逻辑取反<br />&nbsp;&nbsp;&nbsp; C、BNOT: 位运算取反<br />&nbsp;&nbsp;&nbsp; D、FMT : 字符串格式化<br /><br /><pre name="code" class="java">
// 代码
 
int dummy = 10;

println(  - dummy);  // NEG
println(not dummy);  // NOT
println(  ~ dummy);  // BNOT
= @"dummy=%(dummy)"; // FMT

// 输出

-10
0
-11
dummy=10
</pre><br /><br /><strong>2、算术运算符：</strong>
          <br/><br/>
          <span style="color:red;">
            <a href="http://libudi.javaeye.com/blog/123752#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">Windows7在微软WinHEC 2008上揭开神秘面纱</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 14 Sep 2007 11:31:44 +0800</pubDate>
        <link>http://libudi.javaeye.com/blog/123752</link>
        <guid>http://libudi.javaeye.com/blog/123752</guid>
      </item>
          <item>
        <title>Lysee 的打印输出</title>
        <author>libudi</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://libudi.javaeye.com">libudi</a>&nbsp;
                    链接：<a href="http://libudi.javaeye.com/blog/123355" style="color:red;">http://libudi.javaeye.com/blog/123355</a>&nbsp;
          发表时间: 2007年09月12日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          Lysee 写标准输出有以下三种方式：<br /><br /><strong>1、使用输出操作符“=”：</strong><br /><br />调用格式： = v1, v2, ..., vn;<br /><br /><pre name="code" class="java">
// 代码
 
= "\"RTFSC!\"", "stands for", "\"Read The F**king Source Code!\"";

// 输出
 
"RTFSC!" stands for "Read The F**ing Source Code!"
</pre><br /><br />“=”输出时自动在逗号分隔的变量间加入一个空格。<br /><br /><strong>2、使用sys::print()函数：</strong><br /><br />函数原型：public void sys::<strong>print</strong>(string Str)<br /><br /><pre name="code" class="java">
// 代码
 
10.times {|int i| print(i + 1 + " ") };

// 输出
 
1 2 3 4 5 6 7 8 9 10
</pre><br /><br /><strong>3、使用sys::println()函数：</strong><br /><br />函数原型：public void sys::<strong>println</strong>(string Str)<br /><br /><pre name="code" class="java">
// 代码
 
10.times {|int i| println(i + 1 + " ") };

// 输出
 
1
2
3
4
5
6
7
8
9
10
</pre><br /><br />看出println与print的区别没有？
          <br/><br/>
          <span style="color:red;">
            <a href="http://libudi.javaeye.com/blog/123355#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">Windows7在微软WinHEC 2008上揭开神秘面纱</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 12 Sep 2007 17:31:49 +0800</pubDate>
        <link>http://libudi.javaeye.com/blog/123355</link>
        <guid>http://libudi.javaeye.com/blog/123355</guid>
      </item>
          <item>
        <title>Lysee 的标识符</title>
        <author>libudi</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://libudi.javaeye.com">libudi</a>&nbsp;
                    链接：<a href="http://libudi.javaeye.com/blog/123339" style="color:red;">http://libudi.javaeye.com/blog/123339</a>&nbsp;
          发表时间: 2007年09月12日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          Lysee 的标识符分以下两种:<br /><br /><strong>1、常规标识符：</strong><br /><br />遵循C/C++/Java标准，整个标识符由字符['a'..'z', 'A..'Z', '0'..'9']和下划线'_'构成且第一个字符不能是数字。<br /><br />示例：max<br /><br /><pre name="code" class="java">
// 代码

public variant max(variant v1 v2)
{
  return v1 > v2 ? v1 : v2;
}

= max(1, 2), eol;
= max("hello", "world"), eol;

// 结果
 
2
world
</pre><br /><br /><strong>关键字</strong>和<strong>保留字</strong>属于常规标识符的范围。<br /><br />示例：<strong>true false</strong><br /><br /><pre name="code" class="java">
// 代码

bool loop = true;
while (loop) {
  int x = sys::random(10);
  = @"%(x) ";
  if (x == 5) loop = false;
}

// 结果
 
4 2 0 2 6 2 5
</pre><br /><br /><strong>2、环境变量名：</strong><br /><br />格式为“${命名}”，其中命名遵守常规标识符的要求。<br /><br />示例：${PATH}<br /><br /><pre name="code" class="java">
// 代码
 
= ${PATH}.replace(";", eol);

// 结果
 
C:\Develop\Perl\site\bin
C:\Develop\Perl\bin
C:\WINDOWS
C:\WINDOWS\System32\Wbem
c:\develop\lysee\bin
C:\Program Files\Haskell\bin
C:\Develop\ghc-6.6.1\bin
C:\Develop\dmd\bin
C:\Develop\dm\bin
</pre><br /><br />环境变量名还可以使用类似“${域名.命名}”的格式，在CGI页面生成的过程中经常用到。<br /><br />示例：${cookie.LID}<br /><br /><pre name="code" class="java">
{%
public string usr_loginID = "";
public string usr_name = "";

public void checkLoginfo()
{
  string LID = ${cookie.LID}.trim();
  if (LID) {
    dataset ds = openSQL(@"SELECT * FROM bbuser WHERE usr_cookie='%(LID)'");
    if (not ds.eof) {
      usr_loginID = LID;
      usr_name = ds.usr_name.asStr();
    } 
    ds = nil;
  }                                  
}

checkLoginfo();
%}
&lt;script language="javascript">
var usr_loginID = "{%=usr_loginID%}";
var usr_name = "{%=usr_name%}";

document.cookie = "LID=" + usr_loginID;

&lt;/script>
</pre>
          <br/><br/>
          <span style="color:red;">
            <a href="http://libudi.javaeye.com/blog/123339#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">Windows7在微软WinHEC 2008上揭开神秘面纱</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 12 Sep 2007 16:48:46 +0800</pubDate>
        <link>http://libudi.javaeye.com/blog/123339</link>
        <guid>http://libudi.javaeye.com/blog/123339</guid>
      </item>
          <item>
        <title>Lysee 开发</title>
        <author>libudi</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://libudi.javaeye.com">libudi</a>&nbsp;
                    链接：<a href="http://libudi.javaeye.com/blog/122608" style="color:red;">http://libudi.javaeye.com/blog/122608</a>&nbsp;
          发表时间: 2007年09月10日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          Lysee核心代码中的日志提醒我2003年2月26日是Lysee的生日，而准备工作早在1999年就已经开始了。<br /><br />2000年我转业后回到郑州，找到了一份专职软件开发的工作，为政府机关提供数据处理服务，我的面比较窄，基本用Delphi和C包打天下，数据库则使用MSSQL和FireBird。<br /><br />2001年碰到了Mr.Chen并一直合作到现在。Chen比我大两三岁，擅长Python、MySQL、TCL/TK和HTTP，是一等一的高手。 Chen的爱好是不断杂耍各种能够工作的文本文件，并讲解里面用到的数据字典、反射、绑定和其他一些当时在我看来可有可无的概念。在多年的工作中，我积累了自己专有的类库，久经考验，经过扩展和调整基本可以适应各种现实工作的要求，开发效率与Chen的Python不相上下，在那种情况下很自然的认为脚本只是调剂生活的小玩具。为了与Chen配合，我买了本《Python 2.1 宝典》 ，但看了十几页就放下了，因为我感觉到自己有可能在已有的类库基础上创建一个新的脚本引擎并实现Python大部分的功能，并获得两个更有价值的收获：<br /><br />&nbsp;&nbsp;&nbsp; 1、经验：自己能够实现的必然是自己掌握的。<br />&nbsp;&nbsp;&nbsp; 2、工具：一个可以复用的脚本引擎，能做什么就不用说了。<br /><br />没什么说的，干吧！<br /><br />2007年9月我儿子上二年级了，晚上让我给他出30道口算题，于是花几分钟写了几句代码，实现了儿子的需求：&nbsp;<img src="/images/smiles/icon_lol.gif"/><br /><br /><pre name="code" class="java">
30.times {
  do {
    int a = sys::random(100);
    int b = sys::random(100);
    int c = sys::random(100);
    int d = a+b-c;
  }
  while(d&lt;1 or d > 99);
  = a, "+", b, "-", c, "=", eol;
};
sys::readln();
</pre><br /><br />首次释出的Lysee只是一个标准的命令式脚本引擎，除了有函数，其他一切基本都于FP无关。而2007年的Lysee已经部分实现了垃圾回收、closure、yield、curry和模式匹配，除了字符串，所有可执行对象都已统一到函数这一层次。<br /><br />我准备对Lysee的开发进行一次总结，并以系列文章的形式进行发表。
          <br/><br/>
          <span style="color:red;">
            <a href="http://libudi.javaeye.com/blog/122608#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">Windows7在微软WinHEC 2008上揭开神秘面纱</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 10 Sep 2007 16:39:00 +0800</pubDate>
        <link>http://libudi.javaeye.com/blog/122608</link>
        <guid>http://libudi.javaeye.com/blog/122608</guid>
      </item>
          <item>
        <title>转:书呆子的报复</title>
        <author>libudi</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://libudi.javaeye.com">libudi</a>&nbsp;
                    链接：<a href="http://libudi.javaeye.com/blog/122531" style="color:red;">http://libudi.javaeye.com/blog/122531</a>&nbsp;
          发表时间: 2007年09月10日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          原文链接:http://flyingapplet.spaces.live.com/blog/cns!F682AFBD82F7E261!375.entry<br /><br /><strong>书呆子的报复[译]</strong><br /><br />[译注]本文译自Paul Graham的文章“Revenge of the Nerds”。由于译者对Lisp一窍不通，所以不保证完全理解原作者的观点，更不保证能够全面准确地表达其观点。如果你觉得上面这段话有点白痴，看原文吧。<br /><br />书呆子的报复<br /><br />2002年5月<br /><br />“我们争取的是C++程序员。我们已经成功地把很多人从转向Lisp的半路上给拉过来了。”<br />- Guy Steele，Java规范作者之一<br /><br />软件行业里一直有两股力量在争斗：酷想法的学院派和同样可怕的酷头发的老板。每个人都知道酷头发的老板指哪些人，对吧？我想大多数做技术的不仅认识这个卡通人物，而且知道自己公司里面哪些人可以和这个卡通人物对号入座。<br /><br />那些酷头发的老板们的身上神奇地结合了两种品质，这两种品质各自都很常见，但很少同时出现在同一个人身上：（1）对技术完全彻底一窍不通；（2）对技术有很强的主见。<br /><br />比方说，你要写一个软件，酷头发的老板完全不懂软件，对编程语言也一无所知，但是他就是知道你应该有什么编程语言来开发。真的，他觉得你应该用Java开发。<br /><br />他为什么这样想呢？让我们研究一下酷头发的老板的大脑的思维方式，他是这样想的：Java是标准，肯定是标准，因为天天都可以在媒体上看到。既然是标准，用它就不会给自己带来麻烦。同时市面上总是有很多Java程序员，所以如果我手下的程序员辞职了（不知道什么在捣鬼，我手下的程序员老有人辞职），我很容易找到人替代他们。<br /><br />嗯，听起来不是完全没有道理。但是，这种思路基于一个隐含的假定，而且这个假定不成立。酷头发的老板们相信所有的编程语言都是基本等价的。如果真是这样他就对了，如果所有编程语言都是等价的，当然用大家都在用的语言。<br /><br />但是所有的语言都不是等价的，其实不用分析语言之间的具体差异就可以证明这一点。如果1992年你问酷头发的老板应该有什么语言开发软件，他会同样毫不犹豫地告诉你答案。应该用C++开发软件。如果语言都是等价的，酷头发的老板的观点为什么会改变呢。更进一步讲，开发Java的人们还有什么必要创造一门新语言呢。<br /><br />通常情况下，如果你创造一门新的语言，那肯定是因为它可以在某些方面优于已有的方法。实际上，Gosling在第一版Java白皮书中明确指出设计Java是为了解决C++语言的一些问题。所以现在你知道了：不是所有语言都是等价的。如果你顺着酷头发的老板的思路看到Java，然后沿着 Java的历史看到其来源，你就会发现自相矛盾之处了。<br /><br />那么谁对谁错呢？是James Gosling，还是酷头发的老板？不用说当然Gosling是对的。对于某些问题，有的语言确实比其它语言好。下面我们来看一些有意思的问题。Java被设计得在某些问题上比C++好。哪些问题呢？什么情况下Java好，什么情况下C++好？有没有某些场景下其它的语言比它们俩都好？<br /><br />一旦你开始考虑这个问题，你就要面临一系列头痛的事情。假如酷头发的老板要全面思考这个问题，那会让他的脑袋炸开。而只要他继续认定所有的语言都是等价的，他就可以选择最流行的，流行实际上是一个关于时尚的问题，所以就连他也差不多能找到正确答案。但如果语言是有差别的，那么他就要解决两个联立方程，在两件他都不懂的事情之间找到最佳平衡：评估二十多种可用的语言对于要解决的问题的适宜度；分析对每个语言找到合适的库和程序员等等的可能性。如果这就是推开门之后要面临的问题，酷头发的老板不愿意打开这扇门就一点都不奇怪了。<br /><br />所有编程语言都等价这一信念的缺点是它不正确。不过它的优点是它可以让你的生活简单很多。我想这就是这个信念如此流行的主要原因。它是个令人舒服的想法。<br /><br />我们知道Java一定好极了，因为它就是那个最新最酷的编程语言。对不对？如果你从远处看编程语言的世界，似乎Java是最新的东西。（如果距离足够远，你唯一能看到的就是Sun花钱买的巨大的闪光的广告牌。）但如果走近了看，你会发现酷有很多种维度。在黑客圈子里，有个叫Perl的语言被大家公认比Java要酷多了。比如Slashdot就是用Perl生成的。你不太可能发现那帮人用Java Server Pages。还有一个更新的叫Python的语言，它的使用者认为Perl比较土。还有更多别的的语言。<br /><br />如果按Java，Perl，Python这个顺序考察这三个语言，你会发现一个有趣的模式，至少Lisp黑客会发现这个模式。每个语言都更象Lisp。Python甚至复制了一些很多Lisp黑客们认为是错误的特征。简单的Lisp程序可以一行一行地翻译成为Python。现在是2002 年，编程语言终于追赶上1958年代了。<br />追赶数学<br /><br />我是说Lisp最早是John McCarthy于1958年发明的，现在流行的编程语言只不过追赶上了他当时发展的一些想法。<br /><br />这怎么可能呢？难道计算机技术不是变化很快的东西吗？比方说，1958年的计算机是冰箱大小的庞然大物[1]，而计算能力跟现在的手表差不多。怎么可能那么老的技术还值得关注，更不用说优于最新的技术发展了？<br /><br />我来告诉你怎么回事。这是因为Lisp并不是要设计成一门编程语言，至少不是现在意义上的编程语言。今天我们所说的编程语言是指我们用来告诉计算机怎么做的东西。McCarthy后来确实倾向于开发这种意义上的编程语言，不过最终的Lisp是基于他当时作的理论研究—关于定义图灵机的一种更方便的替代品的努力。正如McCarthy后来所说的，<br /><br />展示Lisp比图灵机更精巧的另一种方式是写一个比通用图灵机描述更简洁更易于理解的通用Lisp函数。这就是Lisp函数eval……，它的功能是计算Lisp表达式的值……。实现eval需要发明一种可以把Lisp函数表示为Lisp数据的表示法，这个表示法被设计用于纸上表达，根本没有想过用于在实践中表达Lisp程序。<br /><br />后来发生了一件事情，1958年某个时候，McCarthy的一个研究生Steve Russell看到eval的定义后意识到如果把它翻译成为机器语言，他就得到了一个Lisp解释器[2]。<br /><br />这在当时是个大意外。后来McCarthy在一次访谈中是这样说的：<br /><br />Steve Russell说我们为什么不编程实现这个eval函数呢……，我对他说，嚯嚯，你把理论和实践混淆了，这个eval是用来读的，不是用来计算的。但他还是继续做并完成了。也就是说，他把我论文里面的eval函数编译成了[IBM] 704机器语言，修正了错误，然后就到处把它当Lisp解释器推广，当然这确实是Lisp解释器。在那个时刻，Lisp在本质上就变得跟现在的Lisp差不多了……<br /><br />我想在几个星期的时间内McCarthy突然发现他的理论研究转变成为了一门实际的编程语言—比他预想的强大很多的语言。<br /><br />所以对于为什么50年代的语言还没有过时的简单解释就是它不是技术，而是数学，数学是不会陈旧的。对于Lisp的正确的类比不是50年代的硬件，而是类似于快速排序算法这样的东西，60年代发现的快速排序算法现在仍然是最快的通用排序算法。<br /><br />还有一门语言从50年代至今依然生存着，那就是Fortran，它代表了一种截然相反的语言设计方法。Lisp是一种理论，被意外地变成了一门编程语言。Fortran被一开始就要开发成为一门编程语言，但是现在我们认为它是一门非常低级的语言。<br /><br />1956年开发的Fortran I是跟今天的Fortran显著不同的动物。Fortran I基本上是带数学计算的汇编语言，比如里面没有子程序，只有分支。你都可以说今天的Fortran更接近Lisp，而不是Fortran I。<br /><br />Lisp和Fortran就像两颗不同的演化树的主干，一个扎根于数学，另一个扎根于计算机体系结构。这两棵树一直趋于聚合。Lisp一出来就功能强大，在后续的二十年中越来越快。所谓的主流语言一出来就很快，在后续的四十年中逐渐强化功能，终于到现在其中最先进的算比较接近Lisp了。接近，但还是少了一些东西……<br />Lisp的独特之处<br /><br />Lisp刚一出现就包含了九个新思想。有些思想今天大家都习以为常了，另外一些在比较高级的语言中才能看到，还有两个只有在Lisp才有。按照主流语言的接受次序来列出这九个思想就是：<br /><br />&nbsp;&nbsp; <strong>1.条件分支。</strong><br /><br />条件分支是一个if-then-else结构。今天我们对这个已经习以为常了，但是Fortran I没有。它只有条件goto，非常接近底层机器指令。<br /><br />&nbsp;&nbsp; <strong>2.函数类型。</strong><br /><br />在Lisp中，函数也是一个类型，跟整数或者字符串一样。它有文字表示，可以存储到变量中，可以作为参数传递等等。<br /><br />&nbsp;&nbsp; <strong>3.递归。</strong><br /><br />Lisp是第一个支持递归的编程语言。<br /><br />&nbsp;&nbsp; <strong>4.动态类型。</strong><br /><br />在Lisp里面所有的变量实际上都是指针。变量没有类型，值才有，对变量赋值或者绑定变量意味着复制指针，而不是它们指向的内容。<br /><br />&nbsp;&nbsp; <strong>5.垃圾回收。</strong><br /><br />&nbsp;&nbsp; <strong>6.程序由表达式构成。</strong><br /><br />Lisp程序是表达式树，每个表达式返回一个值。这跟Fortran及其后续语言截然不同，这些语言区分表达式和语句。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Fortran I这样区分很自然，因为它没有嵌套语句。所以虽然需要表达式来做数学计算，非表达式结构就没有必要返回任何值了，因为没有办法使用它。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这个限制随着块结构语言的出现而消失了，但是到这个时候为时已晚。表达式和语句之间的划分已经不可改变了。它从Fortran扩散到Algol，又散布到其后续语言。<br /><br />&nbsp;&nbsp; <strong>7.符号类型。</strong><br /><br />符号实际上就是指向存储在hash表里的字符串的指针。这样你可以通过比较指针来判断是否相等，不需要比较每一个字符。<br /><br />&nbsp;&nbsp; <strong>8.代码中使用符号和常量组成的树的表示法。</strong><br /><br />&nbsp;&nbsp; <strong>9.任何时刻都可以使用整个语言。</strong><br /><br />它没有真正地区分读时刻、编译时刻和运行时刻。你可以在读的时候编译或者运行代码，编译时读或者运行代码；以及运行时刻读或者编译代码。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 读时刻运行代码让用户可以修改Lisp的语法；编译时刻运行代码是宏（macro）的基础；运行时刻编译是使得Lisp可以作为象 Emacs这样的程序的扩展语言的基础；运行时刻读使得程序可以使用s-expression进行通讯，这一思想最近以XML的方式被人们重新发现了。<br /><br />Lisp刚出现的时候这些思想不可能在普通编程实践中出现，因为当时的编程实践是由50年代的硬件条件所决定的。随着时间的发展，一代代的主流流行语言逐步向Lisp演化。思想1~5现在已经很普遍了。思想6正开始在主流语言中出现。Python以某种形式包含了第7点，尽管还没有明确的语法。<br /><br />第8点可能是最有意思的一点。思想8和9能够成为Lisp的一部分完全出于偶然，因为Steve Russell实现了一个McCarthy没有预期被实现的东西。然而正是这两个思想导致了Lisp的奇怪的外表和最与众不同的特征。Lisp看起来很奇怪主要不是因为它的语法很奇怪，而是因为它没有语法；其它语言要做语法分析，而Lisp程序被直接表达成为语法树，这些树在后台构造，它由Lisp的数据结构—列表—组成。<br /><br />用语言自身的数据结构来表达语言实际上是一个强大的特性。思想8和9合起来意味着你可以写一个可以写程序的程序。听起来这可能有点奇怪，但是在Lisp里面这是常见的事情。最普遍的做法就是使用宏。<br /><br />“宏”在Lisp里面跟在其它语言里面不是一个意思。Lisp的宏可以象缩写这么简单，也可以象编译器这么复杂。如果你想真正理解Lisp，或者拓展你的语言视野，你应该更多地学习宏。<br /><br />据我所知，（Lisp意义上的）宏只在Lisp里面出现。这部分因为为了实现宏，你可能要把语言弄得看起来象Lisp一样奇怪。这也可能因为如果你加入了这个终极威力，你就不能说你发明了一个新的语言，只能说是一个新的Lisp变体。<br /><br />我这样说主要是开玩笑，不过确实是这样。如果你一定一个语言有car、cdr、cons、quote、cond、atom、eq和把函数表示为列表的表示方法，那么你就可以用这些来构造Lisp的所有其它部分。这实际上是Lisp的根本性质：McCarthy把Lisp做成这个样子就是出于这个目的。<br />语言的作用<br /><br />那么假定Lisp确实在某种程度上代表了主流语言逐步接近的一种极限—这样是否意味着你就应该用它来写软件呢？使用一个不强大的语言有什么损失？有时候不用最先进的创新技术不是更明智的决定吗？语言的普及度本身不也能说明点什么吗？酷头发的老板希望使用比较容易招到程序员的语言难道不对吗？<br /><br />当然有些项目中编程语言的选择无关紧要。原则上，应用的要求越高，使用强大的语言的好处就越多。但是大量的项目的要求一点都不高。多数编程工作就是写一些小的粘合程序，对于这种小程序，你可以使用任何熟悉的，有可以满足需要的库的语言。如果你要把一个Windows应用的数据传给另一个，当然用Visual Basic。<br /><br />你也可以用Lisp写小的集成程序（我用它当桌面计算器），但是Lisp这样的语言真正发挥作用是在另一种极端情况中：你要写复杂程序来解决难题，并面临严酷的竞争。一个很好的例子是航班费用搜索问题，它是ITA Software为Orbitz开发的软件。他们进入的是一个已经被两个大的不易撼动的竞争对手Travelocity和Expedia所统治的市场，然而他们却在技术上羞辱了对手。<br /><br />ITA的应用的核心是200,000行Common Lisp程序，它能搜索的可能性比竞争对手要多出多个数量级，它的竞争对手还在用主机时代的编程技术。（尽管ITA在某种意义上也在使用主机时代的编程语言。）我从来没有看过ITA的代码，不过它的一个顶尖的开发人员说他们使用了很多宏，这一点都不奇怪。<br />向心力<br /><br />我并不是说使用不常用的技术没有代价。酷头发的老板担心这点并不是完全没有道理。但由于不理解风险，他倾向于夸大它们。<br /><br />我可以想象使用不常用的语言可能会出现下面三个问题。你的程序可能和用其它语言开发的程序一起工作起来可能有点问题。你能用的库可能比较少。还有招聘程序员可能有点困难。<br /><br />这些问题有多严重呢？第一个问题的重要性取决于你对整个系统有没有控制。如果你写的软件要能够在远程用户的不开放的烂操作系统（我可没说名字）上运行，用操作系统自己的语言来开发你的应用可能有点优势。但是如果你控制整个系统，而且有所有部分的源码，我猜ITA就是这样的情况，你就可以选择任何语言。如果出现了不兼容的情况，你可以自己解决。<br /><br />在服务器端应用中，你很幸运可以使用最先进的技术，我想这就是Jonathan Erickson所描述的“编程语言复兴”的主要动机。这也是为什么我们能够听到Perl和Python这样的新语言的原因。我们不是因为人们用它们开发Windows应用才听到这些语言的，而是因为人们在服务器上使用它们。鉴于软件正在从桌面迁移到服务器上（这一点连微软都放弃了抵抗），将来不得不使用半吊子技术的压力将越来越小。<br /><br />至于库，它的重要性同样取决于应用。对于要求不高的应用，库的可用性可能比语言本身的威力更重要。哪里是平衡点呢？不好说，不过不管具体位置在哪里，都应该没有达到严肃意义上的应用这个程度。如果一个公司自认为身处软件行业，而他们正在写的软件要成为公司的产品的话，那么它差不多要用若干个黑客花半年时间来开发。在这种规模的项目中语言的威力可能要比方便的已经存在的库的作用重要。<br /><br />酷头发的老板担心的第三个问题，招聘程序员的难度，我认为似是而非。话说回来，你到底要招多少个黑客呢？现在大家公认软件最好由少于十个人的团队开发。这种规模的黑客的招聘对于任何有人听说过的语言都不是件难事。如果你找不到十个Lisp黑客，那么你的公司可能没有处在适合开发软件的城市。<br /><br />实际上，选择更强大的语言可能缩小所需要的团队的规模，这是因为：（1）使用更强大的语言后你可能不需要那么多黑客了；（2）用更先进的语言的黑客往往更聪明。<br /><br />我不是说你就不会受到要求使用被认为是“标准”技术的压力了。在Viaweb（现在的Yahoo Store）的时候，一些风险投资和潜在的买家对我们使用Lisp感到意外。不过他们对于我们的其它做法也不理解，包括使用大众化的Intel机器而不是 Sun这样的“产业级”的机器作为服务器；使用开源的Unix变体FreeBSD而不是Windows NT这样的商业操作系统；忽略当时被认为是电子商务标准的SET（现在都没人记得了）等等。<br /><br />你不能让穿西装的为你做技术决定。我们使用Lisp有没有让一些潜在的买家惊慌呢？嗯，有一点，但是如果我们不使用Lisp，我们就无法写出他们想买的软件。看起来怪异的事情实际上是起因。<br /><br />如果你创办一个创业公司，不要为了取悦于风险投资或者潜在的买家而设计软件。为了取悦用户而设计软件。如果你赢得了用户，其它的东西都会随之而来。如果你不能赢得用户，没有人会关心你的技术选择是多么令人欣慰地正统。<br />平庸的代价<br /><br />使用不太强大的语言会有多少损失？实际上关于这个问题有些数据可以看。<br /><br />威力的最方便的度量方式可能是代码规模。高级语言的最重要的特点是更大的抽象—更大的砖块，所以你用更少的砖块就可以造出同样大小的墙。所以语言越强大，程序就越短（当然不是简单指字符数，而是指独立元素）。<br /><br />强大的语言是如何让你写出更短的程序的呢？如果语言允许的话，一项可以采用的技术是自底向上编程。不要直接用基本语言开发你的应用，而是在基本语言基础上构造一个适用于你的特定的应用的语言，然后用那个语言来写你的程序。这样写出的代码的总和可能比直接用基本语言写整个应用要少很多—实际上，大多数压缩算法就是这样工作的。自底向上的程序也比较容易修改，因为很多情况下语言层根本不需要变动。<br /><br />代码规模很重要，因为写程序所需要的时间主要取决于其长度。如果用另一个语言会使程序长度是现在的三倍的话，它往往也需要三倍长的时间来写—你不能通过招聘更多的人来解决这个问题，因为到达一定规模之后增加新的人手完全是浪费。Fred Brooks在他的著名的《人月神话》一书里描述了这个现象，而且到目前为止我所看到的一切都证实了他的说法。<br /><br />那么用Lisp可以使程序变短多少呢？比方说，我所听到的关于Lisp和C的比率大约是7~10倍。但是最近《New Architect》杂志上一篇关于ITA的文章说“一行Lisp可以取代20行C”，鉴于这篇文章有大量对ITA总裁的引用，我猜他们是从ITA得到这个数字的。如果这样的话我们应该可以相信它：ITA的软件除了Lisp之外也用到了很多C和C++，所以他们是以经验为依据的。<br /><br />我猜想这些倍数不是一成不变的。我觉得当你碰到的问题越难，或者你的程序员越聪明时倍数还会增加。好的黑客可以把工具用得更好。<br /><br />至少最为一个数据点来看，如果你想跟ITA竞争，而又选择用C来写你的软件的话，那么他们的开发速度就比你快二十倍。如果你花一年时间开发出某个功能，他们可能在三个星期内就能复制出来。相反地，如果他们花了三个月时间开发出新东西，你要花5年才能赶上。<br /><br />你知道吗？这还是最好情况。当我们在讨论代码规模比例的时候，我们简单地假定用相对弱的语言也能够把程序写出来。但实际上程序员能做的事情是有限的。如果你试图使用一个过于低级的语言来解决一个难题，你会碰到一个临界点，脑子里面同时要处理太多的东西了。<br /><br />所以我刚才说ITA花三个月开发的东西竞争对手要花五年才能复制的时候，我是说如果不出什么差错的情况下要五年。实际上，从大多数公司的经验来看，任何要花5年时间的开发项目可能都根本无法完成。<br /><br />我承认这是个极端的例子。ITA的黑客们出奇地聪明，而且C是一个相当低级的语言。但是在高度竞争的市场中，两三倍的差距都足以让你永远无法赶上竞争对手。<br />处方<br /><br />对于这种可能性酷头发的老板可能连想都不愿意想。而且他们大多数确实不去想。因为，如果真的发展到那个情况，酷头发的老板不在乎他的公司是否被挤压得很厉害，只要没有人能证明是他的错。对他们个人来说最安全的方案就是随大流。<br /><br />在大规模组织里，用来描述这个方法的词汇叫“行业最佳实践”。它的目的就是保护酷头发的老板不必承担责任：如果他选择的是“行业最佳实践”，而公司失败了，他不应该受到指责。那不是他的选择，是行业的选择。<br /><br />我相信这个术语最初是用于描述会计方法之类的东西。它的意思大概来说就是不要做出格的事情。在会计上这可能是个好主意。“最新式的”和“会计”这两个词跑到一起总不象是好事。但如果你把这个标准运用到技术决策上就错了。<br /><br />技术通常就应该用最新式的。如同Erann Gat所指出来的[5]，在编程语言方面“行业最佳实践”给你带来的不是最佳结果，而只是平均结果。如果你的决定导致你只能以比激进的竞争对手慢的多的速度开发软件，你就是被“最佳实践”误导了。<br /><br />因此现在有两条我认为非常有价值的信息。实际上我是根据自己的亲身经历体会到的。第一条，语言的威力各不相同。第二条，多数经理故意忽略这一点。这两点事实实际上就是赚钱的处方。ITA就是这个处方的活生生的例子。如果你想在软件行业赢，选定一个能找到的最难的问题，选择一个能够得到的最强大的语言，然后就等着你的竞争对手的酷头发的老板们回归平庸吧。<br />附录：威力<br /><br />作为一个所提到的关于语言相对威力的示例，让我们来考虑下面这个问题。我们来写一个函数产生累加器—也就是一个函数接受一个数字n，然后返回一个函数，该函数接受另一个数字i，并返回n和i累加后的结果。<br /><br />（说的是累加，不是加法。累加器要进行累加。）<br /><br />用Common Lisp可以这样实现<br /><br /><pre name="code" class="java">
(defun foo (n)
  (lambda (i) (incf n i)))
</pre><br /><br />用Perl 5，<br /><br /><pre name="code" class="java">
sub foo {
  my ($n) = @_;
  sub {$n += shift}
}
</pre><br /><br />它需要的元素比Lisp多，这是因为在Perl中必须手工抽取参数。<br /><br />Smalltalk的代码比Lisp略微长一点<br /><br /><pre name="code" class="java">
foo: n
  |s|
  s := n.
  ^[:i| s := s+i. ]
</pre><br /><br />因为虽然一般情况下词法变量（lexical variable）可以解决这个问题，但是你不能为一个参数赋值，所以你还是要创建一个新的变量s。<br /><br />Javascript实现又长了一点，由于Javascript区分语句和表达式，你需要显示的return语句来返回值：<br /><br /><pre name="code" class="java">
function foo(n) {
  return function (i) {
    return n += i
  }
}
</pre><br /><br />（公平地说，Perl也做这样的区分，但是典型的Perl风格是省略return。）<br /><br />如果你试图把上述Lisp/Perl/Smalltalk/Javascript代码翻译到Python，你就会碰到一些限制。由于 Python不完全支持词法变量，你必须创建一个数据结构来保存n的值。而且尽管Python确实支持函数类型，它没有文字表示（除非函数体是单个表达式），所以你需要创建一个命名函数来返回。结果就是这样：<br /><br /><pre name="code" class="java">
def foo(n):
  s = [n]
  def bar(i):
    s[0] += i
    return s[0]
  return bar
</pre><br /><br />Python使用者可能合理地问为什么不能简单地写成<br /><br /><pre name="code" class="java">
def foo(n):
  return lambda i: return n += i
</pre><br /><br />或者甚至<br /><br /><pre name="code" class="java">
def foo(n):
  lambda i: n += i
</pre><br /><br />我猜有天他们可能可以。（但如果他们不想等到Python走完向Lisp的演化道路，他们可以……）<br /><br />在面向对象的语言中，你可以通过定义一个类，类中包含一个方法并且为每个外部作用域中的变量定义一个域，来有限度地模拟closure（一个函数，它可以引用包含它的外部作用域中定义的变量）。这要求程序员自己来做那些全面支持词法作用域的语言的编译器所做的代码分析，而且当多个函数引用同一个变量时这种方式就不行了，不过它已经足够处理我们这个简单的问题了。<br /><br />Python专家们似乎认为这是用Python解决这个问题的比较好的方式，可以写成<br /><br /><pre name="code" class="java">
def foo(n):
  class acc:
    def __init__(self, s):
        self.s = s
    def inc(self, i):
        self.s += i
        return self.s
  return acc(n).inc
</pre><br /><br />或者<br /><br /><pre name="code" class="java">
class foo:
  def __init__(self, n):
      self.n = n
  def __call__(self, i):
      self.n += i
      return self.n
</pre><br /><br />我列出这些因为我不希望Python鼓吹者们说我错误地表达了该语言，不过我觉得这两者方式似乎都比第一个版本更复杂。它们做的事情是一样的，都是用一个单独的地方保存累加器，区别不过在于存在一个对象的域里面还是列表的头里面。而且使用特殊的，保留的域名称，特别是__call__，看起来有点拼凑。<br /><br /><strong>在Perl和Python的对抗中，Python黑客们的论点似乎是Python比Perl优雅，但是这个例子显示出威力才是终极优雅：Perl程序更简单（包含更少的元素），尽管其语法难看一点。</strong><br /><br />其它语言怎么样呢？对于本文中提及的其它语言—Fortran、C、C++、Java和Visual Basic—不是很清楚它们能不能解决这个问题。Ken Anderson说下面的代码差不多是你用Java能够得到的最接近的答案了：<br /><br /><pre name="code" class="java">
public interface Inttoint {
  public int call(int i);
}

public static Inttoint foo(final int n) {
  return new Inttoint() {
    int s = n;
    public int call(int i) {
      s = s + i;
      return s;
    }
  };
}
</pre><br /><br />这个没有完全达到要求，因为它只处理整数。跟Java黑客们通过一堆电子邮件后，我只能说为上述代码写一个多态的版本要么极端笨拙，要么不可能。如果有人愿意写一个我倒很乐意看看，不过我自己是没有耐心了。<br /><br />当然，不是说你用其它语言就完全不能解决这个问题。理论上所有的这些语言都是图灵等价的，也就意味着严格来说你可以用任何语言写任何程序。怎么样才能做到这一点呢？对于限制这种情况，用不强大的语言写一个Lisp解释器。<br /><br />听起来像个笑话，但是这在大规模的编程项目中不同程度地多次出现，以至于人们为这种现象起了个名字，Greenspun的第十个规则：<br /><br />任何足够复杂的C或者Fortran程序都包含一个临时拼凑的，非正式规范的，充满错误的，低效的代码来实现半数的Common Lisp功能。<br /><br />如果你要解决一个难题，问题不在于是否选择足够强大的语言，而是选择（1）使用强大的语言；（2）写一个事实上的解释器；（3）把你自己当作人工解释器。我们在Python的例子中已经看见这种情况出现了，在那里面我们实际上就是模拟编译器实现词法变量时生成的代码。<br /><br />这样的实践不但常见，而且已经约定俗成了。例如，在面向对象世界里你总是能听到“模式”[6]。我怀疑这些模式有时候就是上述第（3）种情况，人工编译器在工作，的迹象。当我在我的程序里面看到模式时，我把它当成是问题的征兆。程序应该只映射它要解决的问题。代码中任何其它规律性的东西都是一种所使用的抽象不够强大的征兆，至少对我来说是这样—我在手工生成扩展，我应该写宏来做这样的扩展。<br />注<br /><br />&nbsp;&nbsp; 1.IBM 704的CPU跟冰箱差不多大，但要重很多。CPU重3150磅，4K内存在另一个箱子里，重4000磅。最大的家用冰箱之一，Sub-Zero 690，重656磅。<br />&nbsp;&nbsp; 2.Steve Russell在1962年还写了第一个（数字）计算机游戏Spacewar。<br />&nbsp;&nbsp; 3.如果你想骗酷头发的老板让你用Lisp写软件，你可以试试告诉他那是XML。<br />&nbsp;&nbsp; 4.用其它Lisp方言实现累加器生成器：<br /><br /><pre name="code" class="java">
      Scheme: (define (foo n) (lambda (i) (set! n (+ n i)) n))
      Goo:    (df foo (n) (op incf n_)))
      Arc:    (def foo (n) [++ n -])
</pre><br /><br />&nbsp;&nbsp; 5.Erann Gat在JPL的关于“行业最佳实践”的悲伤的故事启发了我批判这个被广泛滥用的短语。<br />&nbsp;&nbsp; 6.Peter Norvig发现《设计模式》中的23个模式中的16个在Lisp中“不存在或者更简单”。<br />&nbsp;&nbsp; 7.感谢很多人回答我的关于不同语言的问题以及阅读本文草稿，他们是Ken Anderson，Trevor Blackwell，Erann Gat，Dan Giffin，Sarah Harlin，Jeremy Hylton，Robert Morris，Peter Norvig，Guy Steele和Anton van Straaten。它们不应因这里表达的任何观点而受谴责。<br /><br />其它：<br /><br />很多人对本文作了回应，所以我做了另一个页面来处理他们提出的问题：Re: Revenge of the Nerds。<br /><br />本文在LL1邮件列表中引起了广泛而有用的讨论，特别是Anton van Straaten关于语义压缩的邮件。<br /><br />LL1上的一些邮件激发我在Succinctness is Power一文中对语言的威力的主题进行了更深入的探讨。<br /><br />累加器生成器基准页面上包含了大量的关于这个问题的规范实现。[url][/url]
          <br/><br/>
          <span style="color:red;">
            <a href="http://libudi.javaeye.com/blog/122531#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">Windows7在微软WinHEC 2008上揭开神秘面纱</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 10 Sep 2007 11:32:00 +0800</pubDate>
        <link>http://libudi.javaeye.com/blog/122531</link>
        <guid>http://libudi.javaeye.com/blog/122531</guid>
      </item>
          <item>
        <title>探讨生成器的几种实现形式</title>
        <author>libudi</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://libudi.javaeye.com">libudi</a>&nbsp;
                    链接：<a href="http://libudi.javaeye.com/blog/122517" style="color:red;">http://libudi.javaeye.com/blog/122517</a>&nbsp;
          发表时间: 2007年09月10日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          生成器可以看作为程序提供连续输入的流，输入类型通常固定为一种（比如整型），当然也可以是任意多的不同类型，下面探讨几种生成器的实现方法，题目是生成1...N的整形值：<br /><br /><strong>一、大家都会的：</strong><br /><br /><pre name="code" class="java">// 代码

public int seed = 0;

public int generator()
{
  ++ seed;
  return seed;
}

// 使用

10.times { = generator() + " " };

// 结果

1 2 3 4 5 6 7 8 9 10
</pre><br /><br /><strong>二、基于类实现:</strong><br /><br /><pre name="code" class="java">// 代码

public class Generator
{
  public int _seed;
  public int next()
  {
    this._seed = this._seed + 1;
    return this._seed;
  }
}

public Generator generator = Generator();

// 使用

10.times { = generator.next() + " " };

// 结果

1 2 3 4 5 6 7 8 9 10
</pre><br /><br /><strong>三、基于对象实现:</strong><br /><br /><pre name="code" class="java">// 代码

public object generator
{
  public int _seed;
  public int next()
  {
    this._seed = this._seed + 1;
    return this._seed;
  }
}

// 使用

10.times { = generator.next() + " " };

// 结果

1 2 3 4 5 6 7 8 9 10
</pre><br /><br /><strong>四、使用函数闭包:</strong><br /><br /><pre name="code" class="java">// 代码

public function init(int seed)
{
  return { ++ seed; return seed };
}

function generator = init(0);

// 使用

10.times { = generator() + " " };

// 结果

1 2 3 4 5 6 7 8 9 10
</pre><br /><br /><strong>五、使用YIELD:</strong><br /><br /><pre name="code" class="java">// 代码

public int init(int seed)
{
  while(true) {
    ++ seed; 
    return seed 
  };
}

function generator = sys::yield(init, [0]);

// 使用

10.times { = generator() + " " };

// 结果

1 2 3 4 5 6 7 8 9 10
</pre><br /><br /><strong>六、使用CURRY:</strong><br /><br /><pre name="code" class="java">// 代码

public int init(int seed)
{
  return seed + __func__.execTimes;
}

function generator = sys::curry(init, [0]);

// 使用

10.times { = generator() + " " };

// 结果

1 2 3 4 5 6 7 8 9 10
</pre><br /><br /><strong>七、返回不同的类型:</strong><br /><br /><pre name="code" class="java">// 代码

public variant init(string s)
{
  return s;
  return length(s);
  return {|string who| = who, "said:", s, eol};
}

function generator = sys::yield(init, ["hello world"]);

// 使用

= "length \"" + generator() + "\" is " + generator(), eol;
generator()("LYSEE");

// 结果

length "hello world" is 11
LYSEE said: hello world
</pre><br /><br />实现生成器确实很有意思，一时兴起就写了了几种实现形式，哪位老大还知道别的形式，不妨补充一下，谢谢了！
          <br/><br/>
          <span style="color:red;">
            <a href="http://libudi.javaeye.com/blog/122517#comments" style="color:red;">已有 <strong>0</strong> 人发表留言，猛击-&gt;&gt;<strong>这里</strong>&lt;&lt;-参与讨论</a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">Windows7在微软WinHEC 2008上揭开神秘面纱</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 10 Sep 2007 10:44:00 +0800</pubDate>
        <link>http://libudi.javaeye.com/blog/122517</link>
        <guid>http://libudi.javaeye.com/blog/122517</guid>
      </item>
      </channel>
</rss>