GithubHelp home page GithubHelp logo

languages's People

Contributors

tiye avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

languages's Issues

"Scheme 是为了研究 Actor 模型是发明的"

最开始是微博上有人指点说 Scheme 是为了 Actor 发明出来的

另外 Scheme 应该是为了研究 Actor 并发模型而发明出来的,不是为了研究面向对象。
详见 Scheme An interpreter for extended lambda calculus - Sussman, Steele - 1975

另外推荐的关于编程语言历史视频我目前还没闲下来看

下午遇到一份 History of the Actor model, 有一段关于 Scheme:

Gerald Sussman and Guy Steele then took an interest in Actors and published a paper on their Scheme interpreter in which they (misleadingly) concluded "we discovered that the 'actors' and the lambda expressions were identical in implementation." The actual situation is that the lambda calculus is capable of expressing some kinds of parallelism but, in general, not the concurrency expressed in the Actor model. On the other hand, the Actor model is capable of expressing all of the parallelism in the lambda calculus.

大意 Scheme 模拟的是广泛的并行, 而不是 Actor 中定义的并行
另外上边提到的两人是 Scheme 的作者, 在 Scheme 的 Wiki 中写了
Wiki 还写了, Scheme 是为研究 Actor 而发明的, 而静态词法域正是从 Actor

Scheme started as an attempt to understand Carl Hewitt's Actor model, for which purpose Steele and Sussman wrote a "tiny Lisp interpreter" using Maclisp and then "added mechanisms for creating actors and sending messages."

另外在 Actor 模型的作者的 Wiki 里也提到了关于 Scheme:

Sussman and Steele developed the Scheme programming language in an effort to gain a better understanding of the Actor model. However, their Scheme interpreter was not capable of fully implementing the Actor model because Actor customers cannot be implemented as lambda calculus continuations and Actors can change their local state in a way that is impossible in the lambda calculus [4][39] A number of programming languages were developed to specifically implement the Actor model, such as ACT-1,[40] SALSA,[41] Caltrop,[42] E[8] and ActorScript.[13] The Actor model also influenced the development of the π-calculus.[43](See Actor model and process calculi history.)

好像是说 Scheme 无法模拟 Actor 模型中 Actor 内部状态的改变无法在 S 表达式表示出来
这么说 Scheme 又应该是不能模拟 Actor 了.. 概念多了真是糊涂了...

我中间想, HTTP 每个服务端客户端, 那么多的, 应该算是 Actor 模型的实现的吧
另外这么多年概念变来变去就像是有些人明明很有名, 可在几百年前已经死去了
搅成一堆, 的确更应该把当下的技术先学好, 不然更糊涂了

服务器的 Shell

本来打算早点做出一个在线的 demo, 但难度我还没能招架
两个编辑的包大概写好了:
http://jiyinyiyong.github.com/cirru-editor/page/
http://jiyinyiyong.github.com/codearea/demo.html
介绍页面需要明天努力下, 我对介绍有雏形了. 但标题描述的 Shell 不清晰

首先对于 Bash 的烦恼, 我想用过的人都有的, 但是这难以改变
在服务器为什么没有图形界面的问题中, 记得有一个答案是图形会浪费服务器性能
我刚回过神的一点是, 服务器其实一直都在和图形打交道, 就是网页
那么完全可以通过 SPDY/Websocket 协议重新设计一个 Shell
就有余地做更好的语言, 作为日常操作 OS 的交互入口

命令行用 Cirru 的界面能用, 这是可以的, 任何脚本都是
此前我遇到的问题是 Shell 当中的 Vim 和 ssh 必然要破坏一致性的
之后启发我的是 Light Table, 在页面新建新的方块, 作为新的功能
于是想起 codearea 可以用在编辑文件的功能上, 替代 Vim
替代 ssh 的工具我还没想, 那超出我能力范围很多了, 暂时不会需要

明天打算做个页面介绍下, 今天一事无成了

来自 JS 作者的幻灯片: The State of JavaScript

http://brendaneich.github.com/Strange-Loop-2012/#/
Brendan Eich / Strange Loop 2012
https://github.com/BrendanEich/Strange-Loop-2012/tree/gh-pages
https://brendaneich.com/2012/10/harmony-of-dreams-come-true/

EcmaScript 6 是什么时候要来呢, 设计了好多 JS 缺失的功能
classimport 是前排的, 还加入了 Symbol Map Set WeakMap 数据结构
另外语法上增强也不少, 还有 JS 被要被定下作为 web 平台的汇编语言了

讨厌上 class 的表示 JS 增加这么些 OO 特性好难懂啊..
HN 上的资源还没看.. 围观: http://news.ycombinator.com/item?id=4630057

编程语言能不能有句子结构?

看过上下文无关文法想起以前一个问题, 编程语言变量类型是否可以成为语法?
首先, 我不喜欢用很多符号构成语法, 因为我们习惯了大量文字少量标点的语言

单说句子结构, 对于 Lisp 系语言, 括号中第一个元素当作函数, 其余参数, 很简单
Lisp 的 (define x 1) 看起来很顺, OOP 的 man.read(words) 类似"主谓宾"的结构
只是通常不进行类型检查, 并且编程语言的类型和自然语言的类型还是不同的
参数的类型检查, 出现在静态语言里, 其意义也只在生成编译结果, 和语义无关

我在想, man.read(words) 例子中, 规定语法的是符号, 而不是 man read words
最初我的想法是, 去掉符号, 把若干变量放在一起, 语句是否能正确地执行?

比如这样定义 man read words 里三个变量的内容

new Man lilei
new String words "say something"
define (Man x) read (String y)
  x.print(y)

那么 lilei read words 就会被检测到类型, 并执行

lilei.print("say somthing")

然后跟上边的定义, 加上一个处理字符串的函数:

define angrily (String a)
  a ++ "!!"

接下来 lilei read angtily words 就被类型识别而执行:

lilei.print("say somthing" ++ "!!")
lilei.print("say somthing!!")

到此为止, 第一个存在的漏洞一个是定义仍然需要符号,
我想当语言本身被设计好, 这是可以避免的, 就像缩进之于花括号
另一个是括号依然存在, 这个问题取决于对符号容忍的程度
换成 define...as... 这样的定义如果能接受, 问题也就不大:

define x read y as Man $ String
  x.print(y)

还有个问题是用 new 生成的 Man, 含义是什么, 如何定义?
我想过用对象作为表达式的头部, 后边用方法和参数的古怪方案,

(object mathod para1 para2 para3)

按一般思路, Man 作为对象, 自带一些方法比如 print
print 的定义可以当作对象的一个方法:

create Man
  define print first rest as $ String String...
    echo(first ++ rest)
  define name "man"

于是调用时用 lilei print "say something" 就好了
这样, 编程语言或许可以让类型承担更为重要的功能
想了之后, 我没有想到如何实现, 以及是否真的有实用的价值
在运行过程检查类型并确定执行顺序应该是一件效率低下的事
不确定是不是能玩的点子..

函数式语言, OO 语言, 有趣是因为有足够简单的思路, 因而能灵活
规定这样的语法之后, 我担心定义数据不会那么方便了..

名称和所指,闭包、参数、数据结构

昨天和九瓜讨论了 #14 (comment) 的问题(http://weibo.com/2797413164/z3KzLhLZ9 ):明显的当调用一多,ID就完全不可行了,因为 ID 相当于一个独立的全局名称域。

然后我就想到了闭包和参数,这也是用于解决重名问题。

想想不同次参数调用肯定不能符号替换的,闭包不同层重名对象也是无法符号替换的,因为它其实是不同的所指。

然后我又想到 McCarthy 所说的无数据结构 (http://weibo.com/1477324593/z3kPWbBpE 这也是我的想法:数据结构是明显的冗余):数据结构很大程度上也是在产生闭包来解决重名问题。名字只能作为相对标识。

我还没找到答案,这里先列出一些线索,终极语言肯定要彻底解决“名称”的问题。

运行时可视化:终极调试

这是我对 Bret Victor 编程** #17 进一步理解:“传统的可视化环境可视化了代码和静态结构,但是我们不需要理解它们,我们需要理解代码在做什么。”

最近我在做一个多人游戏服务器,一个玩家连到服务器要进入大厅再入房间进行游戏,里面涉及大量的状态改变,然后当特殊断线或不可预知情形时就会出现各种bug。这时我就深深感到现在编程的方式是“戴着眼罩”的。

可以用 log 或调试,但这些方法无论哪个都是极其低效的(关注点破坏,额外工作量)。

然后我就想做一个类似实时监视器的东西,将每个大厅里有多少房间,每个房间有多少玩家,有没有进行游戏等每个变量的状态都 render 出来,这样一旦出bug我就会发现并很容易找到原因。
这样的确会彻底解决问题,但这需要额外的工作量,并且一旦代码修改,也需要同时修改这个实时渲染器。

问题就是这个可视化是不通用的。这是现在所有程序的通病:程序的运行是不可见的。

所以我的想法就到了这里:就如同 json 可以表达各种(语言)数据结构,也可以用同样的方式将运行时的程序 render 出来,实现通用程序可视化。

实现这个以后,软件和硬件一样能映射一个可视的机械,这样甚至特斯拉的想象开发也可以用在软件开发上了。

读 Amoeba OS 的 PDF 一些感想..

王垠给的关键词, 我先碰到了一个重名的 OS, 是个云操作系统, 后来看到对的这个
The Amoeba Distributed Operating System: http://www.cs.vu.nl/pub/amoeba/
主页还给了 Orca 的链接, 印象里和 Alan Kay 有关, 弄不清楚了... 跳过
What is Amoeba? 页面的 PDF 我看到一些感兴趣的东西, 打算做个笔记

网页上标的日期是 98 年, 我就当作是 PDF 也是 98 年好了

A description of Amoeba

Roughly speaking, we can divide the history of modern computing into the following eras:

  • 1970s: Timesharing (1 computer with many users)
  • 1980s: Personal computing (1 computer per user)
  • 1990s: Parallel computing (many computers per user)

Until about 1980, computers were huge, expensive, and located in computer centers.
Most organizations had a single large machine.

In the 1980s, prices came down to the point where each user could have his or her
own personal computer or workstation. These machines were often networked together,
so that users could do remote logins on other people’s computers or share files in various
(often ad hoc) ways.

Nowadays some systems have many processors per user, either in the form of a
parallel computer or a large collection of CPUs shared by a small user community. Such
systems are usually called parallel or distributed computer systems.

This development raises the question of what kind of software will be needed for
these new systems. To answer this question, a group under the direction of Prof.
Andrew S. Tanenbaum at the Vrije Universiteit (VU) in Amsterdam (The Netherlands)
has been doing research since 1980 in the area of distributed computer systems. This
research, partly done in cooperation with the Centrum voor Wiskunde en Informatica
(CWI), has resulted in the development of a new distributed operating system, called
Amoeba, designed for an environment consisting of a large number of computers.

The basic design goals of Amoeba are:

  • Distribution—Connecting together many machines
  • Parallelism—Allowing individual jobs to use multiple CPUs easily
  • Transparency—Having the collection of computers act like a single system
  • Performance—Achieving all of the above in an efficient manner

过了 10 多年, 我们这里还是双核, 流行的也是 JS PHP C Java 这类不为并行设计的语言
加上 Haskell, Erlang, Smalltalk,, 真觉得当初的大神们想得真超前..
后边突然看到了关于 Object 的说明:

There are two fundamental concepts in Amoeba: objects and capabilities. All
services and communication are built around them.
An object is conceptually an abstract data type. That is, an object is a data structure
on which certain operations are defined. For example, a directory is an object to which
certain operations can be applied, such as ‘‘enter name’’ and ‘‘look up name.’’

Amoeba primarily supports software objects, but hardware objects also exist. Each
object is managed by a server process to which RPCs can be sent. Each RPC specifies
the object to be used, the operation to be performed, and any parameters to be passed.

When an object is created, the server doing the creation constructs a 128-bit value
called a capability and returns it to the caller. Subsequent operations on the object
require the user to send its capability to the server to both specify the object and prove
the user has permission to manipulate the object. Capabilities are protected
cryptographically to prevent tampering. All objects in the entire system are named and
protected using this one simple, transparent scheme.

然后命令行看起来还是 Unix 风格的, 看起来好像 Bash 啊:

Amoeba provides a large number of utilities modeled after the programs that come
with UNIX. Among others, these include awk, basename, cal, cat, cdiff, chmod, cmp,
comm, compress, cp, cpdir, dd, diff, echo, ex, expr, factor, file, find, fold, fortune, grep,
head, jove, kill, ksh, ln, look, ls, m4, make, mkdir, more, mv, od, pr, prep, printenv, pwd,
quote, rev, rm, rmdir, sed, sh, shar, size, sleep, sort, spell, split, strings, sum, tail, tar,
tee, termcap, test, time, touch, tr, treecmp, true, tset, tsort, tty, uniq, uud, uue, vi, wc,
who, xargs, yacc and many other old favorites. Furthermore, a number of new programs
are provided such as amake, a highly parallel configuration manager.

User Guide

关于历史:

2.1. History

The Amoeba distributed operating system has been in development and use since 1981.
Amoeba was originally designed and implemented at the Vrije Universiteit in Amsterdam,
The Netherlands by Prof. Andrew S. Tanenbaum and two of his Ph.D. students, Sape
Mullender and Robbert van Renesse. From 1986 until 1990 it was developed jointly there
and at the Centre for Mathematics and Computer Science, also in Amsterdam. Since then
development has continued at the Vrije Universiteit. It has passed through several versions,
each experimenting with different file servers, network protocols and remote procedure call
mechanisms. Although Amoeba has reached a point where it seems relatively stable, it is
still undergoing change and so it is important to take note of the various warnings and advice
about the proposed design changes for future releases.

再读设计目标, 更觉得超前了..

2.2. The Amoeba Design Philosophy

Amoeba has been developed with several ideas in mind. The first is that computers are
rapidly becoming cheaper and faster. In one decade we have progressed from many people
sharing one computer to each person having their own computer. As computers continue to
get cheaper it should be possible for each person to have many computers available for
individual use. This is already the case to some extent.

The second relates to the widespread use and increasing performance of computer networks.
The need for a uniform communication mechanism between computers that are both on a
local network or on a wide-area network is already apparent for many applications.
What is needed is the ability to deal with physically distributed hardware while using
logically centralized software. Amoeba allows the connection of large numbers of
computers, on both local and wide-area networks, in a coherent way that is easy to use and
understand.

The basic idea behind Amoeba is to provide the users with the illusion of a single powerful
timesharing system, when in fact the system is implemented on a collection of machines,
potentially distributed across several countries. The chief design goals were to build a
distributed system that would be small, simple to use, scalable to large numbers of
processors, have a degree of fault-tolerance, have very high performance, including the
possibility for parallelism, and above all be usable in a way that is transparent to the users.

再扫了一下后边的使用文档, 还不懂是属于哪个规范, 但看去和 Linux 相似的..

Programming Guide 都在讲 C,, 我没看懂
System Administration Guide 关于安装配置软件和一些命令, 没敢细看

于是觉得当初设计语言设计操作系统的大神们所考虑的真的要远好多...

关于 Digital Philosophy 初步的搜索

早上 Steve Dekorte 的推上 看到这么个链接, 好奇点进去
http://en.wikipedia.org/wiki/Digital_philosophy

英文刚开始没看懂, 之后发现 Gottfried Leibniz, Edward Fredkin, Stephen Wolfram 几个名字
还提到 cellular automata (元胞自动机), 我开始猜到那是什么情况了..
用计算机的思维去理解宇宙之类的

资料不太多, 但可能会深. 标记了先
http://www.digitalphilosophy.org/
http://en.wikipedia.org/wiki/A_New_Kind_of_Science

重写系统

读 "Why Coding Style Matters"

微博上看到@玉伯也叫射雕 分享自@sofish 转自 Why Coding Style Matters 的一段话:

When you start thinking of code as communication with other developers, you start to realize that you’re not simply writing code, you’re crafting code. Your code should clearly communicate its purpose to the casual observer. Keep in mind, your code is destined to be maintained by somebody other than you. You are not just communicating with other members of your team in the present, you’re also communicating with members of your team in the future.

另外又看到了文学编程很流传的一句口号:

“Programs are meant to be read by humans and only incidentally for computers to execute.”
— H. Abelson and G. Sussman (in “Structure and Interpretation of Computer Programs”)

我现在觉得语言就应该为了沟通而设计, 并且更适应大脑思考问题的方式
况且通过编译器, 各种可行的语法无论多文气也不碍机器将其正常运行的
而代码的可读性对 Coder 来说非常重要, 就跟杂志排版广告设计多么重要一样
而且阅读 code 专注程度远超文本, 操作也极频繁, 因而非常值得精致
能力够的话我倒希望在博客和文档上当充斥语法高亮还有细致的结构

其实我有一种想法, 随着机器普及, 会有更多人参与到 coding 当中来
可能的结果是编程语言开始对自然语言渗透, 直到口语中也带上很多编程语言的影子
反过来编程语言借用自然语言的词汇已经是稀松平常的做法

于是我开始抱怨编程语言设计时使用了过多符号, 也过于僵化, 即便是 macro
macro 虽说给出了编译器般操作语言的能力, 可终究还在 Lisp 的语法当中
去掉符号的规则, 甚至自己写出字符串自己执行这用代码怎么做好?

接着还有代码组织的思路, 模式.. 不过我想算法现在依然是比代码规范更伤脑筋的问题
个人其实更期待他人封装好模块, 然后调用, 这样更能保证清晰...
而模块内部的算法.. 我并不清楚怎么更好....

后面作者用了一个很常用的比喻来解释团队协作规范多么重要:

I liken the situation to a group of musicians trying to form a band. Each one comes in believing that their way of doing things is best (their “method” or “process”). The band will struggle so long as everyone is trying to do their own thing. It’s impossible to create good music unless everyone in the band agrees on the tempo, the style and who should take lead during a song. Anyone who has ever heard a high school band perform knows this to be true. Unless everyone is on the same page, you aren’t going to accomplish much.

That’s why I strongly recommend style guides for software development teams. Getting everyone on the same page is difficult, and the style guide is a great place to start. By having everyone write code that looks the same, you can avoid a lot of problems down the road.

我想代码的规范就像在一个群体里说些什么一样, 都经过磨合
记得在微博分享过一个项目, 当时视频演示里两个 coder 实时编辑同一份代码, 没找着..
首先语法要灵活, 其次, 要改变一个人写份的做法, 让编码的人能实时沟通
我认为语法也要像自然语言一般进行磨合和积淀, 甚至将一种用法传播, 才能快速演化
Social Coding 是个好的方向, 只是 repo 和 Git 还每到向往中的通畅
我向往的是整个网络当能是实时的, 就像现世我们是实时的一样

最后开始鼓励使用 IDE:

Don’t be afraid of using tools to help enforce coding style. Web developers have an unprecedented number of tools at their fingertips today, and many of them can help ensure that a coding style guide is being followed. These range from command line tools that are run as part of the build, to plugins that work with text editors.

我在 Linux 下自学养成的习惯是不用 IDE, 因为 IDE 笨重和臃肿
诚然 yinwnag0 说过的解析语法树自动提示匹配会有用, Visual Studio 也有类似功能
可他对编码的约束, 对写小脚本的自由, 还有 OS 运行流畅度, 影响都很大
在 IDE 能消除这些不足之前, 我不想去用

有没有发现语言实现决定语言设计的例子?

今天刚找到一个,就是Scheme的尾递归优化。Scheme的语言标准中强制规定了所有称得上Scheme实现的编译器/解释器都要实现尾递归优化,而尾递归优化可以让所有以尾递归方式编写的代码都获得可以让人满意的,至少是和循环匹敌的迭代的性能。因为有了尾递归优化,所以Scheme语言中就不需要为循环这种控制结构提供任何支持了,例如Scheme不需要将do作为语言核心来实现~

尾递归优化事实上就是编译器的一个实现细节,不管是词法分析、语法分析还是语义分析,都不会得出尾递归优化这么一种东西——最多可以从语义分析中知道某一个调用是尾递归罢了,但是优化不是它的管辖范围,应该交给中间代码生成和目标代码生成之类的来完成。所以,尾递归优化是一个语言实现的细节,不过它却反过来影响了语言核心子集的实现,也就是Scheme的语言核心没有提供循环支持~

一个想法, 分享对于代码的需求

先举一个例子吧, 一个处理日期的函数经常时大家所需要的
比如 JS 的 new Date(), 给出的日期格式并不适合在网站中使用, 因为太长了
通常我们要 20:00 类似的简短的时间格式, 或者其他的细节
因为原生只有简单的 API, 很多人都是在脚本里自己简单得实现一遍, 这并不难的

另一种方案是用一个模块, 提供很方便的 API, 方便开发人员用, 比如 dateable
https://npmjs.org/package/dateable

var dateable = require('dateable');
var str = dateable.format(new Date(), 'MM/DD-YYYY, hh:mm'); // e.g., 03/23-2012, 22:10
dateable.parse(str, 'MM/DD-YYYY, hh:mm') // Returns the original date

我当然是支持这种方案, 因为我觉得同一个问题不值得被解决很多遍
特别是在解决问题并不是为了学会解决类似的问题的方法的时候

更远地说,在提供一个这样的方案之前, 每当遇到一个问题我们就应该这样尝试
我想, 我们应该有个网站, 用网络代码社交的方便来提供这样的解决方案
在这样的网站上有 3 种角色:

  • 遇到问题的人可以发一个贴, 描述这样的问题具体内容
  • 接下来一类人可以描述这个问题在实用中应该采用怎样的 API 定义会更方便
  • 然后又有人可以贡献解决方案, 或者提供解决方案, 甚至编写代码
  • 最后是优秀的方案索引和罗列出来. 以便于别人索引

我的想法, 代码应该更可读, 引用一些模块无所谓, 只要足够方便
而且从一开始寻找一门语言好的 API 就是不容易的事情, 值得花功夫
代码的社交应该有很多的方案才对

我们搭一个论坛用来做编程语言交流好么?

在 Github 的 Issue 里边, 该有不该有的好多功能都有了, 每个人也有了账户,
我一直想能有个论坛, 能在上边扯 Lisp 扯 JS 扯各种关于编程语言的话题,,
其实不为了说服谁或怎么, 但是交换些信息开阔视野,,
也让晚些参与话题的人能更好地找到关键词去学习和理解,
信息有了流动, 论坛才有意义..

我感兴趣的话题主要有 FP, JS, 语法糖, Linux, 设计.. 还有也许叫并发,
那么你的兴趣呢?

Bash 无法让人直视

在论坛上问到一个命令 expand -t 16 - 来扩展 <tab> 长度, 觉得很高深
于是搜出来几篇文章, 看着好玄..

第十一章、认识与学习 BASH
获取 bash 中的历史命令的参数
Bash readline 使用技巧

以前因为 Bash 太难用, 说着气话"Bash 简直不是一门语言", 可它还是语言...
我稍感慰藉的是 Node 平台是有被尝试开发的替代品的, 尽管看起来没希望
我对 Shell 中语言的理解是至少能有 JS 级别的清晰的语法, 而不是到处是坑..
而且在有自动补全的情况下, 命令稍微长一些操作也不会多麻烦
另外基于 Object 存储的属性方案应该是更有序才对

于是我想 Bash 有太多历史因素难以摆脱, 就像 Vim, bla bla bla bla....
实际一点说, 我的确想找一种更好的替代, 甚至自己也在尝试
但想到 Bash 如此强大, 不由得还是唠叨了

之前王垠说在Unix 的缺陷 文章里列举了好多 Bash 的问题
最近看到他微博说要写个操作系统.. (又给删了..) 期待看到新的内容出现

悖论形式化

研究悖论和现在语言逻辑的bug,尝试借助计算机将这些悖论形式化编码运行:List of paradoxes https://en.wikipedia.org/wiki/List_of_paradoxes

谎言者悖论(coffee):

LiarParadox = -> !LiarParadox()

改进:

LiarParadox = -> LiarParadox() == false
ISaidTrue = -> ISaidTrue() == true

作为形式化的翻译,必须同构,这里是:

函数 = 语句
函数执行 = 语句释义
函数返回真假 = 语句的含义是否为真
"==true" = “为真”
"==false" = “为假”

所以每个函数(同构一个陈述句)必须表达一个可能为真或为假事实,所以每个函数必须是返回布尔值。
这只是这个例子的规则,但是无论设为什么规则,都必须是“同构”的。

什么是形式化?

参考WIKI,以及莱布尼兹的演算推论器和弗雷格的概念文字
http://www.philosophypages.com/hy/6i.htm

描述 Cirru 短期计划

技术是我想象力被限制的一个方面, 我渴望那背后的事物, 就开始学技术
到现在我感到带着成见去学非常容易走上岔路, 至少对于学习而言是危险的
相应的, Cirru 我正在写的代码也遇到了编程经验相关的问题, 卡住了
界面部分大概可用, 对应存储成 .json 文件, 然后就是求值器的编写.. 卡住了

模块自动刷新

一个我想做的功能是模块的自动刷新, 想法来自于 Live-Coding, 之前提过

做了一些尝试, 我现在计划跑一个主进程, 用来监视文件管理其他进程, 以及汇总
比如运行文件 A, 主进程 Main 会 fork 一个线程 P(A), 并通过消息与 P(A) 交换数据
其间会因为 import 操作而阻塞, 向 Main 请求文件 B 运行的 S(B), 完成后继续运行
A 运行完成时向 Main 返回整个作用域 S(a), 而 B 在 import 时已经完成这个周期
A 和 B 的作用域在各自运行完成时都在 Main 里存一份基于绝对路径的索引

接下来是文件监视, 检测到文件 B 刷新, Main 会 kill 进程 P(B) 重新 fork P(B)
文件 B 重新加载完成后, 向 Main 发消息, Main 会通知父级的 A 更新
更新的内容是重新对 .json 结果的内容进行求值, 完成后通知 Main, 记录并通知父级
这样保证了每个文件被刷新时全体代码都会被刷新



                       Process

                         Main 
                          |                    Process
                          |
                          V
                        start ---> import -----> P(A)
                          |                       |
                          |                       V
      Process             |  <------------------import B
                          V                      
        P(B) <--------- load B
         |                |
         |                |
         V                |                       |
        run               |                       V
         |                |
         |                |
         V                |                       |
    export S(B) --------> |                       V
                          |
                          V
                      callback A  -----------> wake P(A)
         |                |                       |
         V                |                       |
                          |                      run
                          |                       |
                          |                       V
                          | <----------------- export A
         |                |
         V                |                     
                          |                       |
                          |                       V
   reload event           |
         |                |
         |                |
         V                |                       |
        run               |                       V
         |                |
         |                |
         V                |
    export S(B) --------> |
                          |
                          V
                      update A  ------------>  A restart
                          |                       |
                          |                       |
                          |                       V
                          | <----------------- import B
                          |                       |
                          |                       |
                          V                       V
                     found S(B) ------------>  wake P(A)
                          |                       |
                          |                       |
                          |                      run
                          |                       |
                          |                       |
                          |                       V
                          | <----------------- export A
                          |
                          |
                          |
                          V
                        watching

我的目标是大部分代码不动的同时, 我单个文件重新编写, 能只调试这部分代码
比如 Clojure 依赖 JVM 运行的情况, 让 JVM 环境继续跑, 只是重新刷 Clojure 代码

循环依赖问题

文件开始加载前, Main 会标记其路径, 循环依赖会先得到一个 {} 的空作用域
至少在第一次加载时, 问题不会成为死循环, 然后是向父级更新时有循环依赖的问题
我的思路是对每一次更新使用时间标记, 但目前没有去尝试过

增减模块

另一方面, 想想这样的循环依赖可能形成软件运行时动态增减模块的问题
如果软件能在运行的同时, 对其模块逐个完成替换, 这样也是不错的
在我的模型里, 只要 Main 进程不动, 其他模块刷新过程失败也不会造成全体崩溃
那么比方说往正在运行的程序增加模块做探测, 也应该是可以的

去掉模块我还没有尝试, 也许下刷新 Main 里的索引能做到

对象作为函数

虽然大家都不喜欢面向对象, 可我还过不了那一关, 可能因为写 JS 太依赖其方便
所以因为 Object 和 Function 相似的一点是接受参数返回值或能接受值的 Object
于是我考虑在检测表达式头部的类型, 当为对象时作为对象接受参数


set a
  object
    name (string demo)
    vaue (number 1)

a (string name) ;; returns (string demo) => "demo"

set b
  object
    name (string demo)
    value
      object
        name (string demo)
        value (number 1)

b (string value) (string value) ;; returns 1

如果成的话, __proto__this 等等功能可以模仿 JS 搬上去
相对 Lisp, JS 有了原型链相当于优良两个作用域的维度, 能做出一些功能
尽管同时带来的是更多的混乱.. 但还没看到 FP 中那么晦涩的概念

编程的抽象模型和思考模型

在实践中我发现通常编程的抽象模型最自然地还是类似OOP的方式,这可能这些年OOP被大肆鼓吹的原因,OOP的对象映射为一个物体,然后也就将时间映射到现实时间了,所以OOP的物体随时间变化,相当于计算机世界同步时间的虚拟物体。

虽然通常编程书籍的OOP模式我基本已经不肖一顾了,但是发现实践时还是很自然的使用了类OOP的思维方式。我用Clojure尝试过写一个简单的程序就发现函数式很难操作变量,一个关键是引用的问题,函数式实际上应该永远是新变量而没有引用。加上Clojure本身设计的混乱,所以我还是选择了Coffee来做Flow。

想了解下大家编程实践时通常用什么抽象模型思考?

黑客帝国里字符流特效怎样实现?

那天分享了 @MaskRay 微博上 上一条微博, 发现于是安装了 cmatrix 命令
自己屏幕上这回看得仔细了一点, 就想模仿一个, 并且内容用中文替换
至于替换的内容, 我想用 txt 格式的 宋词 , 本来以为长度会比较合适
当天尝试了下, 发现 DOM 操作比较慢, 就放下没做了

下午细看了下, 原来其中的字符本身并不移动, 那 DOM 操作会稍微轻松一些..
我希望是句子在输出时上下相邻字词如果本来相连, 可以保持;
而且每一条纵向的线上不能限定在同时只有一段数据在跑
我拿刚学会的 OO 的思路去套了, 还没写出来... 有没有人来试试?

编程语言是语言还是工具?

写了个争论都没多少意义的话题.. 可我实在开始困扰了
其实比较介意自己编程能力低, 当我真开始用 JS 写对别人实用的东西, 问题明显了
不知道进步还是退步, 我对代码的观念开始变化, 让我不安

首先我喜欢控制自己的代码, 清晰简洁, 让我即便菜鸟, 也能掌握每个细节
就好比写博客有人用 Wordpress, 而我要等自己能设计部署笔记应用才会安心开写
面对学习别人项目的难度和定制代码的难度, 我选择放弃
或者说面对别人的**和我自己的想法, 我选择的是后者

重要的是, 比如学会运用一个框架, 就能获得很高的效率
比如会用 PS 而对代码实现一无所知, 比如学会 Windows 桌面应用而不管代码
我用 Bootstrap 写了界面, 再看复杂的属性, 可的确比我手写的好
虽然其实我享受了好久 Linux 还有 JS, 又完全不懂底层的 C/C++

或者这样说, JS 将自己封装成抽象成人们不用懂底层的一门语言
就像语言, 基于听觉和声带, 还有大脑, 我们完全不用理会频谱怎样
当站在一个这样自由的平台, 我就在上面奔跑而不担心跌倒
对应是 class 的 OO 语法, 引申出好多让人不安的概念

我猛然发现用语言描绘想象, 对比探索发挥工具的用途, 几乎是两回事
比如 Bootstrap 我翻开文档不好上手, 遇到界面预想的元素不知道如何实现
后来我尝试看浏览文档上的组件, 看哪个能用在我的应用里, 之后只管抄代码
我想强调, 因为是两种思路, 后者让我吃惊

再说 OO, 遇到应用里 UI 上的重复, 我开始体会到 OO 能节省命名空间和简化代码

show = (args...) -> console.log.apply console, args

host = 'http://up:8000'
concat = (path) -> host + path
class Page
  login_link: '/json/login'
  login_url: concat @login_link

  reply_link: '/json/reply'
  reply_url: concat @reply_link

  login_handler = (json) -> show 'login:', json
  set_login_hanler = (f) -> @login_handler = f
  get_login: (name, passwd) ->
    json =
      name: name
      passwd: passwd
    $.post @reply_url, json, login_handler

  reply_handler = (json) -> show 'reply:', json
  set_reply_hanler = (f) -> @reply_hanler = f
  get_login: (text) ->
    json = text: text
    $.getJSON @reply_url, json, login_handler

pipe = new Page

原先我用对象当表来做容器的, 相当丑陋:

show = (args...) -> console.log.apply console, args

server = {}
server.host: 'http://up:8000'

server.login_link: '/json/login'
server.login_url: concat @login_link

server.reply_link: '/json/reply'
server.reply_url: server.host + server.reply_link

server.login_handler = (json) -> show 'login:', json
server.get_login: (name, passwd) ->
  json =
    name: name
    passwd: passwd
  $.post server.reply_url, json, login_handler

server.reply_handler = (json) -> show 'reply:', json
server.get_login: (text) ->
  json = text: text
  $.getJSON server.reply_url, json, login_handler

server

写了 OO 觉得不安, 又换成了闭包

change = do ->
  obj = {}

  host = 'http://up:3001'
  concat = (path) -> host + path

  reply_url = concat '/json/reply'
  login_url = concat '/json/login'

  obj.reply_handler = (json) -> show 'reply', json
  obj.get_reply = (text) ->
    json = text: text
    $.post reply_url, json, obj.reply_handler

  obj.login_handler = (json) -> show 'login:', json
  obj.get_login = (name, passwd) ->
    json =
      name: name
      passwd: passwd
    $.post login_url, json, obj.login_handler
  obj

我并不确定我想要的, 而我期待的只是能有个 obj 对象能调用啊

obj.set_login_handler = (json) -> show 'got login'
obj.set_reply_handler = (json) -> show 'got reply'
obj.get_login 'user', 'passwd'
obj.get_reply 'hello'

我不乐意自己限制于工具, 也不想我能同时能用超过一种工具
只是最后我想有种工具, 能用来抹去更多重复, 即便增加一点点不确定吧
考虑到变量的索引是沿着局部作用域索引全局作用域的, 我只是简单地想要写:

scope A
  host = 'http://up:3001'
  concat = (path) -> host + path

  list_url = concat '/json/list'
  song_url = concat '/json/song'
  reply_url = concat '/json/reply'
  login_url = concat '/json/login'

  scope B
    list_handler = (json) -> show 'got list:', json
    get_list = -> $.getJSON list_url, list_handler

    song_hander = (json) -> show 'got song', json
    get_song = (song) ->
      show 'song'
      json =
        song: song
      $.post song_url, json, song_hander

    reply_handler = (json) -> show 'reply', json
    get_reply = (text) ->
      json = text: text
      $.post reply_url, json, obj.reply_handler

    login_handler = (json) -> show 'login:', json
    get_login = (name, passwd) ->
      json =
        name: name
        passwd: passwd
      $.post login_url, json, login_handler

  <- B

obj = make A

想不管对错, 我只是想更直白更好懂的结构展示出来, 削减重复
甚至只是把作用域串联一下, 再消除一些缩进

scope A
  host = 'http://up:3001'
  concat = (path) -> host + path

  list_url = concat '/json/list'
  song_url = concat '/json/song'
  reply_url = concat '/json/reply'
  login_url = concat '/json/login'

scope B << A
  list_handler = (json) -> show 'got list:', json
  get_list = -> $.getJSON list_url, list_handler

  song_hander = (json) -> show 'got song', json
  get_song = (song) ->
    show 'song'
    json =
      song: song
    $.post song_url, json, song_hander

  reply_handler = (json) -> show 'reply', json
  get_reply = (text) ->
    json = text: text
    $.post reply_url, json, obj.reply_handler

  login_handler = (json) -> show 'login:', json
  get_login = (name, passwd) ->
    json =
      name: name
      passwd: passwd
    $.post login_url, json, login_handler

obj = make B

后边合适人是怎么想的, 而不是 JS 里应有的写法

语言意味着用语言思考, 如果用了框架, 就要去探索领会他人的框架
我明白, 设计框架的大神一般都比我精明地多, 我只是不安
微博上看到的担心说, 人的成熟只是被世故磨平棱角更加柔和, 而非丰满
我也想到学会用更多工具, 之后就用工具的角度思考着, 在其基础上再做创新
我不安于磨损的本性, 一天天思维被他人的**主宰的, 那种所谓的长大

一直我想我还小, 接触编程也比网上好多敬佩的同辈晚很多
很任性不想在成长的途中继续丢失些什么, 或者说作为成长的代价
我弄清楚了, 如果我不学会用时下成熟的 Ajax 练习大网站我未来将一事无成
如果用等工具链美好了才敢奔跑, 就永远无法奔跑, 道理不能不懂
恐怕也要胆量才能度过大学剩下的时间.. 能跑题... 拖人开解...

虽说出于能力不足才有这样的困惑.. 但我想能挺严重..
比如昨天气不过又去看 Qt 的绑定. 看 Lua 几个例子明明很清晰的从做什么
https://github.com/mkottman/lqt/wiki/Examples
换了 Pyhon 文档多些, 再看到四溢的 __init__self, 顿时慌了
http://zetcode.com/tutorials/pyqt4/eventsandsignals/
这不是我所期待的编程的样子.. 但不学会就不能写 QT, 更不能重新设计终端
需要独立出 ssh 和 Vim 之类 presudo window, 否则像 nshell 就遗留问题了
就不能用设计用脚本运行的更方便的 Shell, 就永远受困....

... 这是我在想的... 嗯.. 想多了

Python for Humans

晚上看到了 Python for Humans 的幻灯片, 中间一些句子感触挺深的.

HTTP should be as simple as a print statement.

There should be one -- and perfectably only one -- obvious way to do it.

中间看到了 Hitchhiker 单词, 记得 _why 当时有个演讲和这个相关的
The Hitchhiker’s Guide to Python!

于是看到了文档上关于各方面的 Python 的教程和文档, 比较喜欢的
所谓高级语言就是为了方便人操作机器而出现的, 未来早点来吧

在 Osi 上创建了分论坛

网址是 http://ost.io/coffee-js/languages , 几乎就是自动生成的
主题全是黑色的, 功能比较精简, 还好支持 Markdown.. 当然速度也比较快
明明更新了网址, 控制台就是没有刷新的意思. 怎么做到的...

前台后台代码分离的, 不知道有没有机会学会自己做一遍前台..
https://github.com/paulmillr/ostio/
https://github.com/paulmillr/ostio-api/
顺带瞟了下 Brunch, 这个前端框架把我要的 LiveScript, Jade, Stylus 全覆盖了有没有...
晚上再看看.. 等有水平了再自己写论坛

http://ost.io/ 首页上说这是为了替代邮件列表而设计的, 邮件列表太丑了
我的想法也是, 邮件不支持 Markdown, 搜索刘浏览功能不佳, 唉
用法就是用 Github 账户登录, 接着个人主页会有 Sync Github Repos 字样
如果加入的 Team 也公开的话, 就能点进去找到对应的 Team 的 Repo
点击之后, 能看到列表, 后边就知道怎么做了...

单元测试和BDD在语言中的原生(内建)支持?

面向结果编程还在研究早期,先忽略。现在的主流广义的函数式(包括OOP的)语言都有单元测试的需要。

我的问题是:BDD和单元测试的支持是通过外部框架实现好?还是作为语言系统内建的机制更好?

见过第一个内建单元测试系统的语言就是D语言。

笔记: 写一个 Lua Rock

昨天在犹豫要不要用 Lua 写一个遍 Cirru, 趁断网看了 rocks 的文档
中间走了很久弯路, 另外也暂时放弃用 MoonScript 写 Cirru 的念头
Lua 语言有很多我在 JS 中得不到的特性, 但用来做原型还是继续 Node 吧
看看 Go 我是学不会的, 只能期待别人在原型基础上增强 Cirru 了
也许一辈子困在 JS 里出不去了我

这里会记录一些写 Rocks 的要点, 因为我发现文档不够友好
官方的文档写的很简练精确, 大概是 Lua 一贯的作风
一份是创建 Rock 的过程, .rockspec 的例子在里边也出现了
http://luarocks.org/en/Creating_a_rock
再就是 Rockspec 具体参数的意思, 手册里详细做了说明
http://luarocks.org/en/Rockspec_format
另外 Rockspec 有 MoonScript 和各种 Rock 的例子可以参考
https://github.com/leafo/moonscript/blob/master/moonscript-dev-1.rockspec
http://luarocks.org/repositories/rocks/

Luarocks 是 Lua 一种包管理工具, NPM 与之相似度很大
Lua 另外有 LuaDist, 从模块上说不如 rocks 多, 我也没具体了解
Lua 用 require 加文件名进行引用, 得到一个 table, 具体参看
http://lua-users.org/wiki/ModulesTutorial
和 Node 不同的是 Node 中 exports 作为对象返回
而 Lua 将文件中没有指定为 local 的变量返回
另外 MoonScript 中通过手动 export 声明将要返回的数据

最终成功的版本

尝试了很久才成功的, 基本满足需求了, 看文件树:

➤➤ tree
.
|-- cirru-1.0-1.rockspec
`-- src
    |-- cli.lua
    `-- eval.lua

1 directory, 3 files

然后是 Rockspec, 注意文件名的格式, 需要有 -1 这样表示 Reversion,
本地安装主要是 build 部分, source 部分大概在仓库上用到

package = "cirru"
version = "1.0-1"
source = {
  url = "http://jiyinyiyong.github.com/cirru.lua"
}
description = {
  summary = "Cirru is a toy language.",
  detailed = [[
    with merely several syntax rules.
  ]],
  homepage = "http://jiyinyiyong.github.com/cirru.lua",
  license = "MIT"
}
dependencies = {
  "lua >= 5.1"
}

build = {
  type = "builtin",
  modules = {
    ["cirru.eval"] = "src/eval.lua"
  },
  install = {
    bin = {cirru = "src/cli.lua"}
  }
}

buildin 是指 Lua 或 C 模块, 此外这里可以是 make, 我就算了
modules 是模块, 可以是 C 和 Lua, 可以被外边引用
install 是命令, 最终会安装一个 cirru 命令到 /usr/bin/
看下 src/cli.lua 具体的文件内容:

#!/usr/bin/env luajit

eval = require "cirru.eval"
eval.foo()

还有 src/eval.lua, 注意表明模块的名字:

module("cirru.eval", package.seeall)
function foo() print("Hello World!") end

然后运行 sudo luarocks make 将其安装, 就有了 cirru 命令
这里的 cirru 命令执行时会打印一个 Hello world 字符串

关于 Luarocks 仓库

一般 sudo luarocks install lpeg 这样即可安装来自仓库的模块
或者 luarocks install lpeg --local 安装模块到 ~/.luarocks/
如果是后者, 那就要修改 $PATH 变量使命令能被获取到

luarocks 我没看到上传模块的命令
大概上传只需要一个 .rockspec 文件就能成功了
前几天看到 MoonScript 作者上线了一个 MoonRocks 网站
修改了 config.lua 文件之后就可以使用了

➤➤ cat /etc/luarocks/config.lua 
rocks_trees = {
   home..[[/.luarocks]],
   [[/usr]]
}
rocks_servers = {
  "http://rocks.moonscript.org/",
  "http://www.luarocks.org/repositories/rocks"
}

http://rocks.moonscript.org/
但我在微博上还有 Google 看了下, 用 Rocks 的人似乎不多
弄不懂怎么回事, 对我显然不是什么好的事情
或者 Lua 就是那么一门沉静的语法, 不会去做什么激进热闹的事情

对比一下 Go

Golang 的模块跟 Lua 又不同了, 弄明白了还是蛮简单的
先要指定一个 $GOPATH 所有代码和文件都放到那里:

➤➤ c $GOPATH
bin/  pkg/  src/

还要设置 $GOBIN 这样一个变量, 可以用在 $PATH 的索引位置

➤➤ go env
GOARCH="amd64"
GOBIN="/bin"
GOCHAR="6"
GOEXE=""
GOGCCFLAGS="-g -O2 -fPIC -m64 -pthread"
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/chen/kit/golang"
GOROOT="/usr/lib/go"
GOTOOLDIR="/usr/lib/go/pkg/tool/linux_amd64"
CGO_ENABLED="1"

代码存储在 $GOPATH/src 目录下, 比如 $GOPATH/src/my/go-demo

go install my/go-demo

运行命令后就在 $GOPATH/bin 或者 $GOPATH/pkg 下生成文件了
大概取决于源码里声明的是 package main 或者什么之类

Golang 模块以 Github 或其他网站网址这样的方式安装
Rocks 有类似, 就是写在 source 参数里可能会自动抓取
而 NPM 的话则是 git clone 然后 npm install, 也挺不错
通过在代码托管网站方代码已经是常态了, 想来也是趋势
但 Node 有一套很顺手的工具, 可能是 Python Ruby 那学的, 也算优势


网络没好, 先贴这里

未来的网络是一座城市

在前一个 Issue 里串了, 开一个新帖..
关于网络城市的设想, 我早一些也在博文里写过, 还有几篇追溯到 10 年的文章:
http://jiyinyiyong.blog.163.com/blog/static/64699876201011311192898/
http://jiyinyiyong.blog.163.com/blog/static/646998762010102712950932/
我的观点是网页像现世的分形一样一个包含一个, 只不过看不到, 但技术层面是存在的
这个模型更丰富, 因而我希望这个可以模拟现世的城市布局, 还有一些对于代码来说实用的结构
构想中的内容相当于重新发明一遍浏览器, 所以还只停留在想象

自动解方程的语言功能

如题。
Mathematica和各类CAS系统的Solve函数通常是这个功能:
具体是调:

Solve[{x+y==3}, {x}]

就会得到:

x=3-y

的表达式或函数(反正可以轻易转换)(函数也就是:x(y):3-y)。

我想到的好处就是用这个来编写需要大量数学模型运算的软件就太方便了:比如图形引擎、物理引擎、各种模拟运算等等。

只需写一次标准的数学模型的方程,然后只用设定输入输出变量即可。

反观现在的主流编程语言,一个个还停留在lisp的阴影里,完全的手工汇编语言,没有一定点根本的进步。

找了下开源方面的很好的实现是这个:https://github.com/emerge/blog/issues/11 ,我打算参考它实现Equa(Flow2)的自动解方程。

多种语言的对比: 实现一个API,API内部有两个http接口A,B并发调用,如果都在200ms内返回,则合并结果输出,如果B比A慢,且B耗时超过200ms,则丢弃B调用只返回A结果

微博上@骆逸 起的头:

根据我的服务器端经验,我很怀疑node.js的价值。node的并发模型基于回调函数,而这是种公认的落后的模型,在实现稍微复杂点的业务逻辑时就会遇到很多问题。再加上JS在语言和包管理方面的种种短板,所以我觉得它只适合用来做些轻量级的应用比如聊天。@淘宝褚霸 @朴灵,你们怎么看?CC @老师木

后来到了[@hugozhuhttp][hugozhuhttp] 的回复:

Go语言的actor并发模式更容易使用和理解,一点都不绕,比如要实现一个API,API内部有两个http接口A,B并发调用,如果都在200ms内返回,则合并结果输出,如果B比A慢,且B耗时超过200ms,则丢弃B调用只返回A结果;用Go很容易实现这个逻辑,50行应该可以搞定;但Node.JS在不引入框架情况下我不知道怎么搞

@hugozhu 的 Go 语言实现: https://gist.github.com/4364389

func callA() string {
    time.Sleep(time.Millisecond * 300)
    return "Hello A"
}

func callB() string {
    time.Sleep(time.Millisecond * 100)
    return "Hello B"
}

func callC() string {
    time.Sleep(time.Millisecond * 200)
    return "Hello C"
}

func main() {
    a_is_done := make(chan bool)
    b_is_done := make(chan bool)
    go func() {
        log.Println(callA())
        a_is_done <- true
    }()
    go func() {
        log.Println(callB())
        go func() {
            log.Println(callC())
        }()
        b_is_done <- true
    }()
    t := time.Now()
    <-a_is_done //wait for A to finish or timeout
    select {
    case <-b_is_done:
    case <-time.After(time.Duration(time.Millisecond*200) - time.Now().Sub(t)): //todo: duration <= 0
    }
}

@朴灵 的 JavaScript 实现: https://gist.github.com/4364823

var callA = function (callback) {
  setTimeout(function () {
    callback(null, {name: "a", data: "I am result A"});
  }, Math.round(Math.random() * 300));
};

var callB = function (callback) {
  setTimeout(function () {
    callback(null, {name: "b", data: Math.round(Math.random() * 300)) % 2 === 0});
  }, Math.round(Math.random() * 300));
};

var callC = function (callback) {
  setTimeout(function () {
    callback(null, {name: "c", data: "I am result C"});
  }, Math.round(Math.random() * 300));
};

var api = function (callback) {
  var result = {}, start = new Date().getTime();
  var emitter = new EventProxy();
  var done = function () {
    emitter.removeAllListeners();
    callback(result);
  };
  emitter.on('all', function (event, ret) {
    result[ret.name] = ret.data;
  });
  callA(function (a) {
    emitter.emit('a', a);
    // 200ms后,不管b了
    if (new Date().getTime() - start > 200) {
      done();
    }
  });
  callB(function (err, b) {
    // 检查b的返回值
    if (b.hasOwnProperty("b") && b.data) {
      callC(function (err, c) {
        emitter.emit('c', c);
        emitter.emit('b', b);
      });
    } else {
      emitter.emit('b', b);
    }
  });
  // a, b在200ms前完成的case
  emitter.all('a', 'b', done);
};

@hugozhu 的 Java 实现: https://gist.github.com/4364650

public class PriorityTaskExecutor extends ThreadPoolExecutor {

    public PriorityTaskExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
    }

    public <T> List<Future<T>> invokeAllWithPriority(Collection<? extends Callable<T>> tasks,
                                         long timeout, TimeUnit unit)
        throws InterruptedException {
        if (tasks == null || unit == null)
            throw new NullPointerException();
        long nanos = unit.toNanos(timeout);
        List<Future<T>> futures = new ArrayList<Future<T>>(tasks.size());
        boolean done = false;
        try {
            for (Callable<T> t : tasks)
                futures.add(newTaskFor(t));

            long lastTime = System.nanoTime();

            // Interleave time checks and calls to execute in case
            // executor doesn't have any/much parallelism.
            Iterator<Future<T>> it = futures.iterator();
            while (it.hasNext()) {
                execute((Runnable)(it.next()));
                long now = System.nanoTime();
                nanos -= now - lastTime;
                lastTime = now;
                if (nanos <= 0)
                    return futures;
            }

            boolean finishedMasterTask = false;
            for (Future<T> f : futures) {
                if (!f.isDone()) {
                    if (finishedMasterTask) {
                        f.cancel(true);
                        continue;
                    }
                    if (nanos <= 0)
                        return futures;
                    try {
                        f.get(nanos, TimeUnit.NANOSECONDS);
                    } catch (CancellationException ignore) {
                    } catch (ExecutionException ignore) {
                    } catch (TimeoutException toe) {
                        return futures;
                    }
                    long now = System.nanoTime();
                    nanos -= now - lastTime;
                    lastTime = now;
                }
                finishedMasterTask = true; 
            }
            done = true;
            return futures;
        } finally {
            if (!done)
                for (Future<T> f : futures)
                    f.cancel(true);
        }
    }    
}

@淘李福 的 Erlang 实现: https://gist.github.com/4367305

-module(multi_try).
-export([dothese/1]).

dothese(FuncArray) ->
    Me = self(),
    lists:foreach(fun(F) -> spawn(fun() -> F(Me) end) end, FuncArray),
    spawn(fun() -> timer:sleep(1000), Me ! timeout end),
    Result = get_result("",length(FuncArray)),
    io:format("result: ~p~n", [Result]).

get_result(Result, 0) -> 
    Result;

get_result(Result, RemainTimes) ->
  receive
      timeout -> 
          Result;
      Sth -> get_result(Result ++ Sth, RemainTimes - 1)
  end.

@骆逸 的 Python 实现: https://gist.github.com/355a8a80bab0df60b29e

from gevent import sleep, spawn
from random import uniform
from time import time as now


def call_a():
    sleep(.1)
    return 'a'


def call_b():
    sleep(uniform(0, 0.3))
    return 'b'


start = now()
greenlet_a = spawn(call_a)
greenlet_b = spawn(call_b)

# wait for a
greenlet_a.join(timeout=5)

# wait for b
greenlet_b.join(timeout=max(0, .2+start-now()))

# if a or b is not done, the .value is None
print greenlet_a.value, greenlet_b.value

@美味书签-dennis 的 Clojure 实现: https://gist.github.com/4367826

(defn invoke [fs]
  (map #(deref % 200 nil) (map future-call fs)))

@codeplayer 的 Haskell 实现: https://gist.github.com/4367902

import Control.Concurrent (forkIO, threadDelay)
import Control.Concurrent.MVar (MVar, newEmptyMVar, putMVar, takeMVar)
import System.Random (randomRIO)
import System.Timeout (timeout)
import Data.Time.Clock.POSIX (getPOSIXTime)

-- 开一个线程执行 io ,返回等待结果的Action
spawn :: IO a -> IO (IO a)
spawn io = do
    mresult <- newEmptyMVar
    forkIO (io >>= putMVar mresult)
    return (takeMVar mresult)

-- 模拟 a 操作
slow_a :: IO String
slow_a = do
    threadDelay 100000
    return "a"

-- 模拟 b 操作
slow_b :: IO String
slow_b = do
    randomRIO (0, 300000) >>= threadDelay
    return "b"

main :: IO ()
main = do
    -- 启动线程执行 a 和 b,分别设置5秒和200毫秒超时
    geta <- spawn (timeout 5000000 slow_a)
    getb <- spawn (timeout 200000 slow_b)

    -- 等待 a 的结果
    ra <- geta
    -- 等待 b 的结果
    rb <- getb

    -- 结果为 Maybe String,Nothing代表执行超时,Just str表示成功的结果
    print (ra, rb)

--λ /tmp/ ./hugozhu 
--(Just "a",Nothing)
--λ /tmp/ ./hugozhu
--(Just "a",Just "b")
--λ /tmp/ ./hugozhu
--(Just "a",Just "b")
--λ /tmp/ ./hugozhu
--(Just "a",Nothing)

我理解中的 Live Coding

探索 GTK 的时候对 Live Coding 有一些想法, 我结合我看到过的描述下吧
先梳理一下我之前微博上看到过的消息:

简单的理念来自动态语言的解释执行代码, 最早 Lisp, 其后的 Bash, Perl, Haskell 等
现在我们周围的很多语言, 特别壮观的比如浏览器环境都是非常方便和环境交互
但通常 REPL 的设计都是单行, Bash, Python, Coffee 都用特殊语法才能输入多行
而 ELisp 和 Firefox 的 Scratch Pad则在编辑器中集成代码执行, 就像
http://jeditoolkit.com/2012/11/12/interactivate.html
还有@Emerge 推荐过的视频, 用图形显示代码的运行, 但其创意比这里说的要多
www.youtube.com/watch?v=R3MNcA2dpts

在另外 gdb, pry, Chrome 那样的调试工具应该是更好的 Live Coding 的工具
可以在代码运行中某个环境跑测试的代码, 查看代码运行的状态并做修复
个人使用调试工具较少, 导致我倾向于代码本身具备调试功能, 而不是扩展工具
心里还是依赖着有强大的工具发布.. 因为我以为目标就是看清代码执行中的结构
即便大脑去模拟代码执行, 也仅仅是逐个验证数据状态, 借代码本身模拟显然更好

上边的例子主要是代码部分执行, 而不是打大段代码的编写过程
Live Coding 发生的, 通常是在代码编写过程中即时地查看代码的效果
比如 Wiki 上链接的一个用代码编曲的视频, 随时查看编写的效果
http://en.wikipedia.org/wiki/Live_coding
这更合人们创造手工的过程, 一边做一边看一边改, 直到成为一个完整的物件
大概不符合机器生产的流水线模型, 却是通常我们探索和发明的方式

Live Coding 比较清晰的一个例子是 JS 监视文本框的输入, 实时执行代码
这样实现起来比较轻松, 并且在网页上直接展示的例子是比较多的, 比如
http://nodeca.github.com/js-yaml/
而 C 一类编译型, 我见过只有 Circa 能在 C++ 游戏运行过程修改代码
http://circa-lang.org/about/introduction.html
相似还有 JS 代码编辑过程就在边上实时绘制图形的
http://flowingdata.com/2012/03/19/live-coding-implemented/
http://mrdoob.com/projects/htmleditor/
这样更多的例子其实都能用 Bret Victor 大神的想法来串联
http://nornagon.github.com/scrubby/

Bret 的视频当时震撼了我, 他手中的代码能看到形态, 能看到过程
而面对抽象的代码执行过程, 我非常期待能如此看到代码生动地生长起来
http://vimeo.com/36579366
http://worrydream.com/LearnableProgramming/
Light Table 就是受此指引设计的编辑器, 代码将会实时地执行
并结合 IDE 所需的功能, 展示出更多关于代码本身以及运行的信息
http://www.chris-granger.com/2012/05/21/the-future-is-specific/
也赖现代的动态编程语言许多灵活的特性, Chris Granger 给了一个同样动人的例子
http://www.chris-granger.com/2012/02/26/connecting-to-your-creation/

对 Live Coding 那样的调试方式, 我在折腾网页时时时用到
前端调试 CSS 和 jQuery 常要按 F5 刷新, 有了 Node 的协助这都是做动完成的
同样一些 Node 小程序, 用 node-dev 也自动重载, 那都是机械的操作
我观念中的编程就是不断涂抹代码直到完成, 完全消掉编译和重启的工作量
代码不是一蹴而就的, 大脑总是要从各种异常中找到问题的关键所在
当然, 要找到问题所在, 看清代码运行的过程是必不可水

当我被 GTK 那些 C 文档挫败的时候, 我想到去查看代码本身
就像最初学 JS 那样, 去打印对象所含的属性和方法, 作为 API 文档
在我不惯用的 IDE 中, 类似功能是存在的, 只不过那不是代码执行时所展示的
极端的像王垠说的同时解析其 AST 提供补全, 但我没有是用的经验
语法补全和代码真实的执行环境有区别, 我目前倾向于执行

另一个我遇到的问题是找到 API, 但参数类型和功能并不清晰
那么自然我想到要打印 API 同时展示相关的文档, 引导用户使用
Python Clojure 在定义函数时使用 doc string, 在这方面有例子
http://www.python.org/dev/peps/pep-0257/#what-is-a-docstring
http://clojuredocs.org/clojure_core/clojure.repl/doc

其实文档本身也有问题, 动态语言比如 jQuery, 在教学阶段就有各种例子
通过网页上真实可见的例子, 开发者能很快了然插件所要执行的功能
大多语言的文档只是死板写出了输入输出类型, 我认为太过于抽象
我的观念里学习是先模仿, 然后思考. 如果仅靠思考, 那就像机器证明看那么刻板了
人类的大脑擅长于情节, 擅长于想象, 因而我有点反感那种刻板的学习方式

还有一个问题像 Clojure 或者 GTK 程序的重启, 时间上不允许那样调试
http://martinsprogrammingblog.blogspot.com/2012/02/why-is-clojure-so-slow.html
文章开头 REPL 似乎是对此一个不错的解决方案, 因为能减少代码的重载
REPL 不足在无法四处跳转修改代码. 如果要实现, 恐怕要标记源码和内存数据
之后只对涉及修改的部分进行重载, 那样就不再是一遍遍消耗资源了
编写软件是艰难的, 所以我想多花费功夫去改进不会是偏离重点
也不知道现在有什么项目解决了这样的问题呢?

结尾说下 Lisp 吧, 从上次 Chicken 执行速度不如 Node 和 Luajit 我就失落了
http://www.douban.com/group/topic/34481125/
虽说 Scheme 最快要 Gambit 和 Stalin, 可 Chicken 也是编译到 C 的那种速度
其实 JS 和 Lua 说白了是山寨的 Lisp, 我用惯了并不觉得 Lisp 多么出彩
或者说当置身网络想一些东西, Lisp 哪有多少先进? 主要是失望..
也许 FP 价值在于让人看得更远, 然而现代编程语言站在 FP 的肩上也能看到

我不精通 JS, 也不熟练 FP, 写的必然有错误, 上面是我真实的想法

最近看到线程和面向对象一些文章, 想法和疑惑

我一直在学 JS, 多线程和并发没有清晰的概念, 对函数式和 OO 觉得理所当然
网上总是会有人发表的各种声音, 或许还相互冲突
最后只能凭自己松散的根基去搜索, 询问和想象

出于个人对语言的理解, 我期待语言是清晰易用的, 其次才是强大
最初从 Python 看 OO 觉得好复杂, 后来看基于原型的 OO, 才渐渐明白这里对象的概念
基于原型链的 OO 通过 __proto__.bind()
或者 __indexsetmetatable() 改变搜索变量的方式
我相对喜欢原型链这种更直白的方式,

另外不太消化地看了下面的文章...

我一般只是在 Node 和 jQuery 中享受 OO 带来的方便
以致我觉 OO 的好处更多在于有一个类似表的结构, 将操作绑定到了对应的数据上边
我在知乎上解释了问题, 但回答更让我觉得重点不在 OO 上..
http://www.zhihu.com/question/20405888
而且对于 OO 的态度, 我印象很深的说法是
http://www.zhihu.com/question/20275578

面向对象在 WIMP 的环境中是很必要也是很成功的。
原因是 WIMP 环境需要重量的实现继承提供的重用,
WIMP 的对象种类能很好的被单继承模拟,WIMP 的属性和类别容易区分。
而面向对象扩展到 WIMP 之外的环境中就失败了

另外我在学习 MVC 框架时也积累这对于 OO 的困惑,
于是去知乎询问怎样才是纯粹的 OO, 结果反而没有完全信赖的回答
http://www.zhihu.com/question/20185591
这时自然想到去追溯更接近 Alan Kay 的一些说法来理解了
http://blog.csdn.net/turingbook/article/details/1873481

对我而言,面向对象程序设计只意味着
消息发送(messaging),状态处理的局部保存、
保护和隐藏(local retention and protection and hiding of state-process),
还有一切东西的极端迟绑定(extreme late-binding of all things)。
这些在Smalltalk和LISP中都可以实现。可能还有其他系统,但我不知道。

对象就像是生物学里的细胞,或者网络中的一台计算机,
只能够通过消息来通信
(因此消息概念出现很早,但是它在程序设计语言中实际可用却花了较长时间。)

而且来自权威的一些大神的声音反而让我更为困惑
http://www.infoq.com/cn/news/2010/07/objects-smalltalk-erlang

似乎认为Erlang“可能是唯一的面向对象语言。”
因为Erlang具备面向对象编程的三原则:基于消息传递机制,对象分离和多态。
有一点倒是, 随着搜索, "Actor 模型"这个词多次出现在视野当中了
http://www.drdobbs.com/architecture-and-design/interview-with-alan-kay/240003442?pgno=3
Binstock: How do you view the Actor model?
Kay: The first Smalltalk was presented at MIT, and Carl Hewitt and his folks, a few months later, wrote the first Actor paper.
The difference between the two systems is that the Actor model retained more of what I thought were the good features of the object idea,
whereas at PARC, we used Smalltalk to invent personal computing.
It was actually a practical programming language as well as being interesting theoretically.
I don't think there were too many practical systems done in Actors back then.

因为我只是写 JS 的基础, 所以只好继续从网上检索 OO 的信息
关于 Actor 模型我找到了 JeffreyZhao 的博客, 很明白地, 那是关于并行的
http://blog.zhaojie.me/2009/05/a-simple-actor-model-implementation.html

Actor模型为并行而生
Actor模型的理念非常简单:天下万物皆为Actor,Actor之间通过发送消息进行通信。
Actor模型的执行方式有两个特点:

  1. 每个Actor,单线程地依次执行发送给它的消息。
    2 .不同的Actor可以同时执行它们的消息。

也刚好 logickthing 给的关键词里我遇到一个打动甚至让我信服的说法:
http://weibo.com/2701649502/yyigOxs4E

根据 OO 最初发明人的几篇重要论文来看, 对象是一种描述并发性的设施.
他们设计的各种 OO 特性都是为了支持现实世界的并发性,
而后人几乎把并发性给遗弃了,演变成为一种事物关系的模式, 进而夹缠于哲学问题.

到这里就有真的很震撼我的信息出现了, 因为纯函数的就是为了解决并发
学 Haskell 我接看一些博文, 临时先找一篇说到的
http://blog.csdn.net/manyoo/article/details/5405252
编程语言因为不同线程共享状态, 同时修改发生冲突会出错, 因而出现了锁的概念
更高级的 Clojure 是用事务内存, 在少见的冲突时才回滚重新修改, 也是为这个
而函数式语言选择了不修改的状态, 有个 Erlang 和 Haskell,
平常写脚本我受不了纯函数, 后来这样明白这是为并行而设计的
当我看到 OO 最初也是面对同一个问题, 顿时有些吃惊

在 Node 的介绍里我慢慢有点明白上边的说法
http://www.ibm.com/developerworks/cn/web/1201_wangqf_nodejs/

得益于基于事件驱动的编程模型,Node.js 使用单一的 Event loop 线程处理客户请求,
将 I/O 操作分派至各异步处理模块,
既解决了单线程模式下 I/O 阻塞的问题,又避免了多线程模式下资源分配及抢占的问题。

似乎在别的文章我看到了, 因为数据只在一个线程中能够被访问和修改
那么不存在不同进程访问相同数据带来的冲突, 也就适用于并发
而 JS 本身就是单线程, 明显就不会有不同进程破坏数据一致性的问题
到这里关于 OO 我遇到的困惑总算能说清, (自然关于细节还要继续学...)
在很多框架里呈现的很整齐的对象封装, 那种对于 对象过度的信赖也可以解释

从我的角度, 大概不成熟, 的看法, 我觉得 OO 并未在我扮演多正要的角色
首先为了数据和操作排列有序, 我没需要的是 JSON 或者 Lua 中表的结构
有了表, 从另一模块引用的代码清晰地绑定在对应的变量上边, 操作数据的方法也类似
另外借助 __index 之类属性, 我们在需要时也能快速构造出此类结构
关于 OO, 我主要是不想遇到代码就出现 class 之类强行设定我思路的结构
作为还不是码农, 我期待的是代码清晰地展示大脑思考和代码运行的结构,
而不是框架的积习

在学 Node 过程中, 我花了相当长时间去适应带有 CPS 风格的回调
传统同步代码, 比如 ret = prompt() 会阻塞进程, 然后将返回值传给 ret
在 Node 中 fs.readFile('name', 'utf8', cb) 就只有 undefined 这样的返回值了
进而, 我试想在消息的世界当中, 同步代码的返回值将不再常用
如果说一切写得极端了, 全部的颠覆.. 我只是觉得会比较有趣, 当然明显不实用

然后我看到了 CoolShell 上关于线程模型的思考
http://coolshell.cn/articles/4626.html
还有徐昊写的"对象已死?"的文章,
http://www.infoq.com/cn/articles/object-have-dead
开始期待着线程概念早日被更高级的抽象所取代

编程语言的交流和积累, 所想到的

中午和人聊过些东西, 再次明确学 FP 不是为了用 FP 的语言写程序,
而是用从 FP 语言里学来的东西去丰富实际用动态语言开发的技能
我是 JS, 换别人是其他语言. 而我也挺遗憾 FP 语言没有动态语言的方便

之后想到, 编程语言, 作为语言, 她的积累都没有被我们主动去完成
随着学习, 人们积累和丰富了自身的技能, 并且会在博客里留下文档介绍给其他人
或者就是写新的模块, 这对于语言的传播至关重要, 因为 API 凝聚了前人的思考
再往后, 就是发明新的语言, 开辟新的社区, 当然社区还有文档之类会越来越多

同时, 没有人能学会所有语言, 意味着交流不断增多, 语言之间的阻隔却一更快的速度拉大
即便 Lisp 是同一门语言的语法, 模块还不能通用, 反而作为动态语言(还有 JVM 上的语言)做到了
Guile, Chicken, Lua, Node 重用 C/C++ 代码, Clojure, Scala 重用 Java,
还有就是 JS 平台上的方言重用 JS, 还有 GNOME3 通过 Inspection 共享 GLib
当然我个人眼里, 语言如果不通用, 如果不方便, 就是作为语言极为缺陷的一面
同时, 也很少能用强大到成为平台的语言, 所幸现在我们已经有了

为了尝试一些难以直接在现有的语言尝试的功能, 我们于是尝试发明语言
Cirru 是出于这个目的的. 希望语言的表现形式仅限于列表和字符串,
随着尝试, 也能感到增强语言的灵活性会更是混乱的根源, 但也只是开始
我想像语言完成后, 再建社区, 所有代码都能集中发布到同一个网站上来,
在网站里大家在共同的数据表示之上不断探讨调整所有的如何使用语言
我想语言就是语言, 不限于函数式, 不限于面向对象, 那些都是用语言表示的内容

回到现在我们能做到, 语言层面无法做到, 于是重点在于设计各种模块
我初学尝试用一些项目练手, 但几番下来都没有找到有效的积累方式
Lilyturf 和 live-tmpl 是我对于模板引擎的尝试, 总算作为模块沉淀下来了
CoffeeScipt 不是极灵活的语言, Lisp 同样不是, 因为语法解析在所有语言都是死的
网站的开发模式, 在成熟的 MVC 框架里会有沉淀, 但我想那也有僵化的部分

开发中的关窍我还是想不通多少, 因此对于模块特别是框架知之甚少
我现在想, 尽可能地提取出抽象, 以便在各个不同的项目里重用, 应该是对的吧
考完试再去想想这个事情... 找到方向了, 但没摸到路

为什么异步的代码不是语义上被处理成同步的呢?

之前对 Haskell 产生疑问的时候就想过这个问题,,,
我曾经猜 Haskell 有这样的机制, 当代码包含封装的异步计算时, 看作是同步
LiveScript 的例子很说明我的问题, 并且符号借鉴自 Haskell 的:

do
  data <-! $.get 'ajaxtest'
  $ \.result .html data
  processed <-! $.get 'ajaxprocess', data
  $ \.result .append processed

alert 'hi'

语法和同步类似, 没有太多嵌套, 而运行却是异步的,

$.get('ajaxtest', function(data){
  $('.result').html(data);
  $.get('ajaxprocess', data, function(processed){
    $('.result').append(processed);
  });
});
alert('hi');

Haskell 里的 Monad 意思大概也包含了的,
然后问题在于函数复合, 就像 Lisp 早先考虑的函数复合那样:
coffee-js/history-of-lisp@436cb3a#L0R12

我困惑的是: 为什么有异步的函数就不能拿来复合? 而非要写成回调
比方说我用伪代码, procedure 函数是异步的, 但有类似的 return:

def procedure:
  a = task-a() # 2s 
  b = task-b() # 3s 但和 task-a 几乎同时开始
  return (a + b)

def call:
  c = procedure()
  print c
  return "finised"

call()

return 等待异步函数 task-a task-b 完成, 然后再执行 return (a + b)

那么代码的意义就是, 等待需要的数据完成, 然后开始计算, 不管通过同步还是异步
代码的每一次计算都会消耗时间, 虽然长度上会完全不属于同个数量级
但我认为, "计算在所需数据完成时开始"的思路是一致的, 就能有连贯的语法
... 貌似这是数据流计算模型已经说过的:
http://jsjedu.hxu.edu.cn/dxjsjjc/kcnr/wlkj/03architecture/detail/3-3-1.htm

数据流计算模型的操作前提:数据是否齐备。例如计算:y=a+b, 数据齐备的前提就是知道 ab 的值,能一步得出y的值,而计算 y=(a+b)*(c+d), 需要两步,先分别计算 a+b 的值和 c+d 的值,等得到这两个值后,即数据齐备后,再将这两个值相乘来计算 y 的值。这就是数据流计算模型的过程。

于是我想, 这和函数复合的思路没有分别, 为什么通常语言里没有呢,
特别是 Node, 大量采用回调, 而且 Haskell 也有些看不懂,,
是在实现上有难度的么? 或者有其他原因?


加上 Dataflow 的 Wiki 上提到的关于执行过程的描述:

Operations consist of "black boxes" with inputs and outputs, all of which are always explicitly defined. They run as soon as all of their inputs become valid, as opposed to when the program encounters them. Whereas a traditional program essentially consists of a series of statements saying "do this, now do this", a dataflow program is more like a series of workers on an assembly line, who will do their assigned task as soon as the materials arrive. This is why dataflow languages are inherently parallel; the operations have no hidden state to keep track of, and the operations are all "ready" at the same time.

网页的模块化

后端代码模块化容易, 每个脚本里的 require 依据相对路径即可
于是计划在前端的 JS 脚本里引入对应的 require, 进行模块化
SeaJS, [RequireJS][requrejs] 都是在 CommonJS 的大旗下做这方面的事情
在 SeaJS 里我还看到关于静态文件的管理, 但没看到文档
(另外记得有学长写过加载静态文件的范例, 于是自己也尝试了一次)
Component 项目也看到管理静态文件的例子, 可我还不熟

现状的轮廓

现在能用的工具在这篇 The State of Javascript Package Management 里概括了
Twitter 的 [Bower][bowser] 是个兼容多个方案的模块管理工具,
Google 的 Yeoman 是基于 Bower 的封装, 也看不清取向
Bower 的模块检索页面上基本直接指向网站模块自身的
而 SeaJS 有模块加载规范, 命令行工具, 模块列表, 观点很清晰
对应的, 我只都到了 Jam 是转管理 AMD 规范的模块
再者是 TJ 的 Component 项目有干净的模块索引, 就像 Node 的索引
GruntEnder 我基本看不懂, 似乎是更独立的方案

总之我现在摸不清路, 不知道该上哪条船.. 最近的是 SeaJS 是没错..
模块涉及到上传, 目前 Bower 和 Component 是直接以 Github 作为仓库的
这事 Golang 和 LuaRocks 也干, 算是成本最低了
而 Jam 和 SeaJS 则是模仿 Node 发布到中心的仓库, 至少 Jam 是
SeaJS 记得之前看列表里只有官方的模块, 别人能不能上传呢...?
我倾向 Jam 和 Component, 不过具体我都只能等用过以后再说了


好在自己尝试过去做了, 对于中间一些问题多少有点理解
JS 代码的 require 模块时, 下载模块的延时是第一个问题
但我想这永远是从浏览器本身去解决才是正道, 毕竟这是一直以来缺失的
要完成模块化, JS 不是唯一要应付的, 还有页面其他的元素

模块的意义在于, 一次解决问题, 下次遇到时不再重复解决
对应到图形界面上, 就是一个区域里的功能像一个细胞能完全自理
我觉得不止是能用 new 快速生成组建然后 append 上去再加 CSS 之类
像我从前描述过的, 一个页面嵌套一个页面, 再形成复杂的功能
命令行代码引用模块引用的是作用域, 图形的应用自然可以是引用一块界面

Base URL 的混乱

有个问题, 我在一个页面写好了内容引用了资源, 作为模块时
模块的路径是不定的, 但被引用后, 页面 HTML 里资源的 URL 却是写死的
HTML 整个都是这样, 因而任何引用的资源作为模块之后都不方便
能想的办法是用 JS 动态改写 URL, 使用模块时生成对应的 URL
这样, 引用的 CSS, HTML 片段, 图片, 视频, 都能够正确地索引

HTML 不适合模块化, 因为它不认为一个 div 有独立的 Base URL
因而一个 div 不能是单独的页面, 除非是 iframe 嵌入的页面
不过 iframe 的事件捕捉有些古怪, 也不好操作, 这条路大概不通
HTML 要用 JS, 还不如用 JSON 定义一遍, 以 HTML 作为平台运行

想象一下 Wayland

窗口嵌窗口会想到 X11, 而且和 Web 很深的 Server-Client 区分
之前看过一个 Qt5 + Wayland 做的 3D 桌面视频, 我想作为一个例子
一方面, 在桌面的一块区域打开一个应用, 直接是另一个程序的模块
同时, 如果运行桌面后就能浏览网络, 人们还有必须要浏览器的必要吗?
客户端就是一个个 Client, 任意的嵌套, 任意的重组, 那才方便

本地的模块

关于模块, 像 Gem 像 pip 以及 C/C++ 的本地模块, 很正常的事情
而 JS, 浏览器作为客户端, 却没有对常用模块的缓存
比如说, jQuery 是常用模块吧, 也只是的 cache 而已
相对于提供 CDN, 提供本地模块不应该更快才对吗?

浏览器里编辑模块

类比的还有代码的调试, 因为本地编写代码就是在本地调试
浏览器既然能缓存模块, 那么自己编写的模块应该直接存在浏览器内部
有浏览器编写编辑器已经不是什么大不了的事情
想象下报错到行, 然后直接修改代码.. 或者直接在对应元素修改 CSS..
我不太用 IDE, 但直接在运行环境上做修改会有意思

协议的接口

我听过关于 JS 觉得非常有兴趣的一句话是:
对于操控浏览器而言, 或许我们需要的是protocol,而不是language
如此多编译到 JS 的语言, 也如此多到 HTML, 到 CSS 的语言
其他平台缺的开始只是一个点击就能打开的便利, 偏偏 JS 就独占?
语言多了, 上边不少想法就多余了. 主要是写着 coffee, 我也反感 JS.

还是说 Wayland 那个视频里的想法, 我个人非常喜欢
人们买手机无非是更好地浏览网络, 不是为了 OS 或者软件本身
而最终打开屏幕就进入了网络, 就有了强大的操作的界面
虚拟世界的东西就像是积木, 就像是代码操作的数据, 随意搭配
不要逼我再去面对那么多括号的语言了好不好...

数学自动化

关于 Lambda Calculus 的书籍

微博上看到@阅千人而惜知己 推荐的书

如果你想学Lambda演算真的是有两本好书,一个是剑桥的 Lambda-Calculus and combinators,Hindley 写的,就是搞类型推断的那两个老大之一,另一本是 The lambda calculus: its syntax and semantics. 荷兰人写的,参考文献里常常看到这本书Bar84,全书621页好读量又足,全书只用了4个参考文献,越少越有影响力

链接是我找的. 前一本作者名字时对上的, 后一本没具体写作者

中间还搜到一本叫 History of Lambda-calculus and Combinatory Logic
暂时不会去看, 但是先标记一下

Chrome Canary 能监听 TCP 端口了

RSS 上看到的标题是 Web Server in your Browser (Chrome Apps API)
http://news.ycombinator.com/item?id=4632778

https://github.com/GoogleChrome/chrome-app-samples/tree/master/webserver

This sample is a demonstration of Chrome's new networking stack.
Chrome now has the ability to listen on a tcp port AND to accept.
The listen and accept API are currently only available in Canary channel of Chrome

早先的话, Opera 是有开放服务器功能的, 只能共享文件..
后边 Chrome 有出过做 UDP 支持的新闻, 后面 Dart 也是服务端可用的语言
其实看着 V8 在 Node 和 Webkit 两边分裂我巴不得都做一块去..

作用域的索引, 一个想法

一个没有多少依据的想法, 我觉得还是值得记录一下, 因为对我而言够新奇
估计描述上会乱, 我尽量多加例子, 介绍新的概念时往往容易出错的
代码我用 CoffeeScript 写例子, 因为讨论的概念好多都是 JS 里来的

默认的定义:

log = console.log

来源

  • 作用域的概念, 索引的顺序

编程语言作用域, 从局部作用域能索引到上一层的作用域, 这非常有意思
这带来了变量索引的方便. 虽然, 在局部变量还全局变量的语法上会有分歧

a = 0
outer = ->
  b = 1
  inner = ->
    c = 2
    log a, b, c
outer()()

# prints
#0 1 2
  • JS 中的 this__proto__ 形成的索引

__proto__ 是给对象增加一个原型, 当前对象不能访问到 key 时, 从原型索引
this 则能一直指向所运行的对象, 两者搭配

a =
  name: "a"
  read: -> log @name

b = __proto__: a

b.read()

b.name = "yes"
b.read()

# prints
# a
# yes
  • 这样的好处, 索引的方便

这样, 就存在两种变量的索引方案, 同时两者都是链式的, 意味着可以嵌套或者级联
前者方便 JS 里使用闭包, 并且很自然
后者满足简单的 OOP 里共用方法, 共用属性, 这样的需求
OOP 中, 同一个类里的属性和方法相互调用非常方便, 这是我体会到的

我想索引是编程里最关键的操作之一

我理解的编程(废话)是怎样 设计和存储数据 , 然后就是怎样 访问和调用数据
数据组合的方式我按 JS 理解, 有 List 和 Object 足够, 后者我用 Dict 区分一下

Object 我在 JS 中有点像制造组合数据类型的方式
Object 帮助数据完成归类, 避免了散乱. 当然, 这是自然而然的一种结构
并且对于 HTML 标签, 如果不用 Object 组织属性和方法那将难以想象

另一个例子在深度的递归当中, 闭包的层层嵌套有时需要技巧才能正确地索引
我现在写过的代码里体会深的解释器里创建的函数:

fn = (item1, scope) -> (item2) ->
  # log "define fn:", item1
  if item1[0]?
    do ret = (scope, item1) ->
      (arg, out_scope) ->
        child = spawn scope
        value = get arg, out_scope
        key = item1[0]
        child[key] = value
        # log ":::", key, value, child, arg
        if item1[1]? then ret child, item1[1..]
        else
          # log "doing function", child
          get item2, child
  else
    child = spawn scope
    get item2, child

因为要在 scope child out_scope 三个作用域中找到数据, 复杂度更高
当然在递归时, 也只有通过参数传递到闭包进行更多数据的处理了

增加更多的索引方式

体会到索引的作用自然会想到设计一些新的索引方案来增强
我理解中面向对象是近似于作用域一样的设计, 并在基础上做拓展
但怎样设计的索引很难说会给编程带来多方便, 因为没有从实际应用中找到

  • 印象里有一种, 类似于 Lisp 里 Macro

演示的代码, 注意我用了 &a, 代码不能作为正常的 CoffeeScript 运行

a = 0
f1 = -> log &a
f1()

do wrapper = ->
  a = 1
  f1()

# want it print
#0
#1

我定义 &a 索引执行时作用域里改变量的值, 至少有点用途

  • 将嵌套的 Object 模仿文件索引上层目录

比如下面的代码中 ^name.child2.name 就是先索引上层 Object

a =
  name: "level 1"
  child:
    name: "level 2"
    read: -> log ^name.child2.name
  child2:
    name: "level 2 of child2"

a.child.read()

# want it print
# level 2 of child2
  • 相应的还有数组索引上一元素下一元素的方案. 当然这在 DOM 中会有

代码中我写了比较难看的定义 ~(-1).name 表示数组的上一个元素

a = [
  {name: "one"}
  {name: "two"}
  {
    name: "three",
    read: -> log ~(-1).name
  }
]

a[2].read()

# want it print
# two

类似的做法, 具体看编程中用到怎样的索引. 我只能做一些概念的猜想
或者会有设计语言的麻烦, 或者性能, 或是否实用, 都是我不熟悉的

模仿 Lisp 的代码即数据

看到 List 和 Map 能组合出数据, 我回想到从前一个问题:
Lisp 里, code 和 List 都是 sequence 的形式表示, 很奇怪, 是线性的序列
那么有没有对应更高维度或者更灵活的结构呢?

因为到了 Dict, 就想到键值对的形式好像是有趣的另一种描述代码即数据的方式..
又会想到 Object 中 keys 没有单纯顺序的说法, 就像是上面找的古怪结构
于是我在想, "code is data", "function is data" 是否能在这里表现出来
同时其中, 顺序的代码依然作为 List 存在, Object 本身的 keys 却是各自分开的

JS 中, function 必属于一个对象, 其中的 this 指向那个对象, 因而可以视作 method
赋值的概念, 也无非是改写 Object 里的一个 key 而已
作为类比, 我上一段落想象的语言看起来真的存在, 只是看不清具体的样子

我能想到的一些特征是, 每一行的数据都有返回值, 每一行都能被索引到
另外代码可以作为数据传输, 同时其中包含着 Dict, List, Function 以及当然 Value
代码 Dict 的键允许以多线程的方式处理, 而数据通过相互间索引来进行沟通

加上对象与函数的统一

补充些别的想法. 暑假思考 Cirru 时我想对象接受 key 的方式与 Curry 函数接受参数类似
在接收完一个参数之后返回一个值, 或者能继续接收参数的内容. 函数与数据结构类似
结合在一起, 就像 Haskell 中的模式匹配, 能对预定数据直接返回结果

factorial :: (Integral a) => a -> a   
factorial 0 = 1   
factorial n = n * factorial (n - 1) 

借鉴 Lua 的 __index, 那样一个步骤步骤应该是先去找到 key, 否则查找函数来求值

而在我的理解当中就出现很古怪的一套语法了, 定义 : init 开始执行的话

: a 1
: b 2
: f
  : "string" 3
  : x : y
    + x y

: scope-a
  : a 1
  : b 2
  : f
    log (@ a) (@ b)
  : f2 : nil
    @ f

: scope-b
   : --index scope-a

: init
  log (f a b)

  scope-b f
  run (scope-b f2)

Live编程、单元测试、调试和面向结果编程

今年早期的时候Bret Victor做了一个Live编程的演讲 http://vimeo.com/36579366 。事实上Web界很早以前就存在Live编程,比如帮助前端开发的LiveReload。单元测试的持续化实际上也是Live编程,相当于Live编程+单元测试,Ruby界几年前就已存在这种工具。再看游戏开发,“热加载”技术其实就是Live编程的另一个名词,而且这除了程序员还真对美工。只是没有人注意到这个生产力的概念的核心,直到Bret Victor专门将它提了出来。

其实Live编程和单元测试是同一**的发展:即时反馈。

实现Live编程是有技术要求的限制的,需要每个改动实时改变,最好的情况是它不会break正在运行的系统,这就是“热加载”的核心。如果这不能做到,至少它必须能瞬间自动刷新而尽量不破坏状态,Web的LiveReload可以达到这一点。这里的共同点就是系统是“软”的“脚本化”的系统,来避开C/C++的慢速编译。

我自己的开发环境现在第一做的事就是完全Live化,我发现这能带来到目前为止尝试过方法中最高的开发效率提升。

除了Live化,近些年很流行的单元测试也是很有用的技术。用它来写Spec就是行为驱动开发(BDD),在写有Spec的库的时候非常好。但它初始状态不如Live编程有用,因为一开始你通常不会有需要什么库接口(Spec)的正确想法,直到你的第一个App跑起来,但是在少数容易出错的地方,单元测试会让你稳步前进。单元测试作为回归测试也很好,但是当接口变化时它也成了包袱。

调试我现在很少用,因为前两个完善时,传统的调试基本就可避过。非传统的调试就是 Bret Victor 在 Learnable Programming 中说的“可视化” http://worrydream.com/LearnableProgramming/

从另一面考虑单元测试,而不是开发效率和方法,就会发现单元测试将所需要的结果的描述和实现分开了。单元测试和通过单元测试的代码实现就好比高级语言和它编译成的机器语言。实际上人需要只是符合要求的抽象结果的描述,而不是具体的实现细节。当我寻找这种描述可能的样子时,就发现BDD测试就是可能的一种形式。

这里我说的可能就是逻辑编程的**,给定需要结果的约束条件,编译器/解释器给出所有满足结果或一个满足结果。我不知道Prolog在这点上实现了多少(还没时间深入研究),不过从结果看肯定不多。

这个**就是 Result-Oriented Programming (面向结果编程) http://evincarofautumn.blogspot.com/2012/01/yep-programming-is-borked.html http://jonbho.net/2012/01/24/i-want-to-fix-programming/ 。Lisp发明人John McCarthy最后的Elephant2000语言 http://www.douban.com/note/123156245/ 就包含这个意思。国内 http://weibo.com/tertio 的语言应该也是这个意思。

前段时间我因为不满所有现有语言对编程语言作了一会研究,设计了Flow,基本完美达成了预期的任务(融合Lisp和Forth,最简化和最高Meta化),不过它还是没有脱离现有语言最基本的概念:需要设计结构实现(程序由嵌套的闭包/数据结构构成)。这是明显的冗余,所以我知道要成为真正的超越一切现有语言的事物还有更关键的一步。

从原型理解面向对象的尝试..

一直无法体会面向对象设计的意思, 也没有找到能坦白其核心的说明,
也比较担心结果是我无法接受的, 因为想 Python 的代码对我来说太复杂了
之前看到的 Lua 的例子也不能解开疑惑, 想不通有什么设计**.

在我遇到所能理解的例子中, OO 似乎是能在局部维持若干数据, 而且能被复制
比如网页上一个标签有内部的 HTML 内容, 有一个操作内容的函数,
内容是私有的, 函数在逻辑部分是一致的, 然而函数作用域不能满足需求
可如果每次手动传入对象来改变作用域的话, 就不符合减少重复的原则
等有了 class 的概念, 能够私有变量和共享操作, 我觉得还是重复了

像 CoffeeScript 官网的例子:

log = console.log

class Animal
  constructor: (@name) ->

  move: (meters) ->
    log @name + " moved #{meters}m."

class Snake extends Animal
  move: ->
    log "Slithering..."
    super 5

class Horse extends Animal
  move: ->
    log "Galloping..."
    super 45

sam = new Snake "Sammy the Python"
tom = new Horse "Tommy the Palomino"

sam.move()
tom.move()

但我不理解为什么要弄出复杂的 class 出来, 因为那是变量索引的问题
JS 中 __proto__ 就能在对象不存在一个键时查找父对象是否有对应的值,
这实现了了对象继承父对象时, 属性和方法简单的继承关系
接着是随之而来的作用域问题, 到早上想起, this 就是指向当前对象的
于是上边的例子可以改写, this 能一直索引到原型链中想要的对象上

log = console.log

Animal =
  Move: (meter) -> log "#{@name} move #{meter}m"

Snake =
  __proto__: Animal
  name: "Sammy the Python"
  move: ->
    log "Slithering..."
    @Move 5

Horse =
  __proto__: Animal
  name: "Tommy the Palomilo"
  move: ->
    log "Galloping..."
    @Move 45

sam = __proto__: Snake
tom = __proto__: Horse

sam.move()
tom.move()

输出:

Slithering...
Sammy the Python moved 5m.
Galloping...
Tommy the Palomino moved 45m.

按我理解的思路, 编程核心在于定位和操作数据, 还是那种扩展作用域的思路
等接触到复杂的应用模型时, 我很难想象用一个更复杂的概念怎样去保持灵活
猜想搭建复杂一些的界面还是免不了要设计模型和消息相互沟通的
那至少能更清楚关于对象的概念... 希望我没把问题搅得更加复杂

模式匹配范围比较实现方法

发现了这个:Unlike in Haskell, changing the order of the clauses would not change the meaning of the program, because Hope's pattern matching always favors more specific patterns over less specific ones. (https://en.wikipedia.org/wiki/Hope_programming_language
问题是怎么判别“ favors more specific patterns over less specific ones”,当我试图实现这个时就发现没原来想的那么简单。
所以暂时还是用Haskell式的以顺序匹配。
有什么办法么?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.