Chinaunix

标题: tcsh,shebang和clojure [打印本页]

作者: starwing83    时间: 2012-10-09 03:28
标题: tcsh,shebang和clojure
本帖最后由 starwing83 于 2012-10-09 03:29 编辑

恩,今天和OwnWaterloo发生了一场争执。争执到后来我好像都没啥自信了,所以想看看大家对于这个问题有什么看法。

@Ager @OwnWaterloo

事情最开始是这样的,OW想用clojure写脚本,使其能独立运行。UNIX上面最简单的办法是shebang,即:

  1. #!/usr/bin/env java clojure.main

  2. (prn "Hello World")
复制代码
shebang是一种能让文本文件被当做可执行文件执行的方式,shell如果发现一个文件的头两个字符是#!,它会提取后面的所有参数,并带上这个文本文件的文件名来组成一个命令行并执行,比如上面这个程序假设叫test,shell会组装一个命令行“/usr/bin/env java clojure.main ./test”,然后执行这个命令行。最终的结果就是好像这个文本文件能被直接执行一样。这个技术叫做shebang。

但是,bash的shebang有问题,它会将这个程序在shebang中提取的所有参数都当做一个参数来传递给实际的程序,比如说上面这个命令行,env程序实际收到的参数是"java clojure.main"和"./test",而env显然不知道这个带空格的"java clojure.main"是何方神圣,自然就执行失败了。

OwnWaterloo觉得,clojure至少应该提供一个标准的可执行的文件(可能是shell脚本,或者其他的什么的),这个文件可以作为直接执行clojure程序的工具。假设这个文件叫clj,那么shebang可以这么写:

  1. #!/usr/bin/env clj

  2. ....
复制代码
在这种情况下,clj是第一个参数,./test是第二个参数,env会在环境中查找clj的位置并执行,就不会有问题了。OwnWaterloo觉得,即使是不提供这么一个工具,哪怕是给一个标准化的名字,也可以让这个工作变得轻松。clojure这么做很不考虑那些希望让clojure的程序能够当做脚本独立运行的人的感受。

我个人觉得clojure本身是基于java-vm的一种语言。它本身其实并不考虑作为脚本这么一个用途,所以不提供这样的命名约定什么的其实也是合理的。不过OwnWaterloo这个观点似乎有点“王垠”化,用他的原话说:

OwnWaterloo 2:33:24
只有自己遇见的需求才是需求, 其他人的需求就是无理取闹?
其他人不以自己的习惯做法并并且没达到目标, 就一定是其他人的方法不对?
你什么时候变成王垠那种货色了?


必须提到的是,OwnWaterloo自己已经提供了一个方案来做这件事情,其实就是“可以同时被当做shell脚本和clojure程序的脚本”

  1. #!/bin/sh

  2. ":"; /usr/bin/env java clojure.main "$0" $*

  3. (prn "Hello World")
复制代码
我在考虑这么一个问题,就是软件本身的设计目的,和用户的需求不明确的时候,用户到底应该怎么办。我对OwnWaterloo说,你应该去clojure邮件列表发言,说明这个问题,而不是跟我讨论,因为这完全没有用。不过我也不知道OwnWaterloo自己的看法是如何,大概是“我已经想到一种解决方案了,我为什么要等待别人去解决这个问题呢?”

我自己其实也遇到了这种关于“需求”的情况。我用tcsh,tcsh本身的shebang我很少用(其实我是根本就没用过,脚本我都是直接用Vim执行,或者在命令行会写解释器来执行,很少会直接执行脚本),所以在测试的时候,我发现tcsh的windows版本竟然不认shebang,然后经过了Stack Overflow提问、自行编译等等方式最后都没有解决这个问题。这本质上依然是“软件的开发者没有满足使用者的需求”。我认为,我遇到的情况是不合理的,因为作为一个shell,在任何系统上行为一致应该是很有必要的。tcsh不支持shebang的原因是它支持Windows式的“按照后缀名判断文件类型”,可是在这之前,先打开文件并检测一下#!应该是很简单的。而且tcsh的源代码中的确也表示Win32移植版本应该支持HASHBANG特性。

我认为我遇到的现象和OwnWaterloo遇到的现象是不一样的。Clojure的官方主页上完全没有提到过支持在shell中直接执行clojure程序的做法。而tcsh作为一个shell,是必须满足POSIX对shell的要求的——即至少在某种情形下识别shebang。所以这并不是一种情况。对clojure来说,这种用途是作者“完全没有考虑过,或者没有考虑透彻的使用情景”,而对tcsh来说,这应该是“宣称的功能没有达到”。

因为#字符在clojure中并不是注释符。可以发现clojure的确是对clojure程序中包含shebang做出了支持。问题在于这个支持不全面,并不能保证clojure一定能够通过shebang调用到。一方面,shell不支持shebang参数分割是一个缺陷,另一方面,clojure本身没有提供独立的可执行的工具来直接执行clojure程序也是一个问题。两者共同造成了clojure无法通过shebang执行的情况。

这其实是另一个话题了,在两个软件的缺陷同时造成一个困难的时候,谁应该为这个困难负责?OwnWaterloo认为应该是clojure,我不知道这是基于什么情况的考虑,反正我觉得应该负责的是shell。因为归根结底,是shell的shebang不完善造成的,clojure提供独立执行文件的方式只是一个work around而已,而shell的shebang仍然不完善。

这次争吵让我正视了关于软件开发中,需求和设计目标不匹配的一系列问题。包括没有完成设计目标、出现了设计者没有考虑过的情况、数个应该共同协助完成目的的特性之间的不协调等等问题。我想知道大家的看法。


我想知道:
1. 软件的开发者选择软件的应用场景,并决定软件支持的限度(如clojure不提供独立执行文件),究竟是不是开发者自己的自由。
2. 软件没有达到宣称的目标,和软件在自己没考虑过的范畴没有达到设计目的,是不是同样的情况。
3. 对于遇到这个问题的用户的抱怨,向其说明“产品并没有考虑在这种情况使用,这是产品的自由”,是否是正确的行为。
4. 如果你是使用者,你在向人抱怨自己的“正常”使用没有达到预期的目标,反而需要自己去想work around,并埋怨其设计糟糕的时候,如果有人提出相反意见,你是否能保持冷静并考虑。
5. clojure究竟有没有考虑作为shebang程序使用?是设计者考虑不周,还是设计者的shell本身是支持参数分割的,还是设计者自己私人使用了一个独立的可执行驱动呢?
6. 对待这种情况,作为抱怨者,和作为被抱怨者,以及作为聆听抱怨者,应该采取什么样的行为是合适的?

希望能和大家深入讨论这个问题。
作者: Ager    时间: 2012-10-09 05:51
本帖最后由 Ager 于 2012-10-09 06:13 编辑

@starwing83
@OwnWaterloo

用shebang、用java、用clojure,都是可以的,这是在我的机器(zsh)上做的测试:
ager@gnugcc.org:~/cljs
$
cat hello-sw-ow.clj
#^:shebang '[
exec java -cp "/usr/share/java/clojure.jar" clojure.main "$0" -- "$@"
]

;  FILE : hello-sw-ow.clj

(prn "大虾们啊 —— 这样行不行啊?")
(prn (+ 1 2 3 4 5 6 7))

;  END

ager@gnugcc.org:~/cljs
$
chmod +x *.clj
ager@gnugcc.org:~/cljs
$
./hello-sw-ow.clj
"大虾们啊 —— 这样行不行啊?"
28

ager@gnugcc.org:~/cljs
$


以上,仅供参考,呵呵 —— :)




作者: Ager    时间: 2012-10-09 06:20
本帖最后由 Ager 于 2012-10-09 10:58 编辑

@starwing83
@OwnWaterloo



有美女了,还要env干啥?

呵呵……


作者: KanonInD    时间: 2012-10-09 09:19
本帖最后由 KanonInD 于 2012-10-09 09:21 编辑

LZ用的clojure是哪个版本?
  1. k@myhost:/home/k> pacman -Ql clojure                                                                       12-10-09 9:11
  2. clojure /etc/
  3. clojure /etc/profile.d/
  4. clojure /etc/profile.d/clojure.sh
  5. clojure /usr/
  6. clojure /usr/bin/
  7. clojure /usr/bin/clj
  8. clojure /usr/share/
  9. clojure /usr/share/clojure/
  10. clojure /usr/share/clojure/clojure.jar
复制代码

  1. k@myhost:/home/k> pacman -Qi clojure                                                                       12-10-09 9:12
  2. 名称   : clojure
  3. 版本   : 1.4.0-1
  4. URL地址 : http://www.clojure.org/
  5. 软件许可 : CPL
  6. 软件组  : 无
  7. 提供   : 无
  8. 依赖于  : java-environment  sh
  9. 可选依赖 : rlwrap: for a friendlier shell with readline support
  10. 要求被  : 无
  11. 冲突与  : 无
  12. 取代   : 无
  13. 安装后大小:3384.00 KiB
  14. 打包者  : Alexander Rødseth <rodseth\atgmail.com>
  15. 架构   : any
  16. 编译日期 : 2012年04月18日 星期三 23时43分40秒
  17. 安装日期 : 2012年07月21日 星期六 14时27分54秒
  18. 安装原因 : 单独指定安装
  19. 安装脚本 : 是
  20. 描述   : LISP dialect for the JVM
复制代码

作者: huxk_cu    时间: 2012-10-09 09:26

有次在一个系统下遇到一个python脚本 #!/usr/bin/env python 这样不行 改成#!/usr/bin/python倒是可以。因为环境没有配置。

个人觉得这些问题都无解,如果是软件公司的话,领导应该多找几个美女去攻关。哈哈。

用户很多时候也是被惯出来的。开发很多时候也是被逼出来的。
作者: Ager    时间: 2012-10-09 09:27
KanonInD 发表于 2012-10-09 09:19
LZ用的clojure是哪个版本?


大虾你也喜欢用 Arch Linux 呀?



作者: fender0107401    时间: 2012-10-09 09:41
除了用Octave写计算程序以外,对脚本编程基本上没啥兴趣。
作者: mirnshi    时间: 2012-10-09 10:56
除了简单的工作,用shell脚本,复杂都用python或php解决了。python和php都能很好地支持shebang。既然不支持,只能说明用户没这个需求或者开发者没有这个意图,因为支持shebang是非常简单的事情。在很多解释语言里,#是注释,很容易解决,但在不是注释,需要特别处理#!。

对于不能拆解的参数:java clojure.main ./test,应该算是env的缺陷,env的本意是设置环境,然后运行一个程序,给一个空格间隔的字符串,用意很明显,就是这个字符串包含程序及其参数。Linux下的env参数比FreeBSD的少,FreeBSD的支持将传过来的参数分拆后再执行。
作者: __BlueGuy__    时间: 2012-10-09 17:29
笑而不语 ,  
作者: gvim    时间: 2012-10-09 17:38
完了,又干上了。。。应该猩猩相吸啊!
作者: starwing83    时间: 2012-10-09 18:39
本帖最后由 starwing83 于 2012-10-09 18:39 编辑

回复 9# OwnWaterloo


    我想我大概知道矛盾在哪儿了……

除非有十分明显的漏洞,否则假设对方的需求是合理的, 只是自己没遇见过而已; 然后直面问题; 尝试解决或者提供work around; 之后再是点评、吐槽什么的 —— 我记得你之前一直是这样的。


你怎么知道我不是这样的呢?难道我没有找work around吗?

去stack overflow提问如何让clojure支持shebang。

测试tcsh对shebang的支持(因为shebang不分离参数是bash的问题)——最后,大概是昨晚5点的样子吧,得到结论了。shebang是系统的事儿。跟shell没关系。系统自己的exec系列系统调用处理shebang的。还有tcsh的windows版本不支持shebang问题也解决了,是个环境变量:TCSHONLYSTARTEXES,天杀的文档。好,这个“子过程”返回。

我没没有对你的work around有任何恶意的评价吧?相反我觉得这是个解决方案。而且,我对你的说法的评价,都是在你提出这个work around很久以后吧。在这之前,似乎我一直在想办法去找你的问题的解决方案吧?在这之前我一直都没有说你的需求不合理吧??

另外想问一下,既然你也知道,emacs lisp并不是以作scripting language为主要目的,而你也这么用了。而且我也没有评价这个不合理,为什么你觉得我说“开发者并没有考虑到这个情况”就是“这个情况是不合理的”?我从来没有在这两者之间画上等号啊?我仅仅是说,这个情况clojure没有考虑,要你去mailing list去问而已,我根本就没有说过这个想法是很不合理的啊?我说过最接近的一个话是“clojure不是用作脚本设计的,所以不提供启动器也是天经地义的吧”,问题是,“不是作脚本设计”和“作脚本设计就不合理”这个之间是不是没有等价关系?光盘不是做衣服的不是做建筑塑料的可是就是有人用光盘盘片做这些艺术品啊,没有不合理啊。

好,继续说work around。既然你提到了那个解决方案。我的注意力就放到了“如何让shell支持多参数shebang上”。因为添加一个clj是很简单的事情,然而你说clojure没提供,而且连名字都没有标准化——事实上,我觉得有问题的地方是,他没提供这一点是事实,如果你想从这一点出发,要么你自己提供一个,然后等官方提供了以后再改;要么你立刻要求官方提供一个,要么你黑了官方网站自己加一个——不管怎么说,你对我说这个话完全没有意义啊!我不是clojure的维护者啊。你对我抱怨,我也只能有两个态度:1.“啊,clojure好差劲啊,这样的东西都不提供,真是的,完全不考虑使用者的感受和正常需求嘛”——然后又能怎么样?联名上书吗?就是因为考虑到这一点,我才采用了第二个态度2.“你跟我抱怨是没用的,clojure自己本身就没用提供这个东西就已经是事实了。如果clojure真的没提供,那么显然它无法阻止别的用户自己写driver脚本,那么driver脚本的名字不统一估计也是事实了,既然是事实,你对我说又有什么用呢?”

我有说你的需求不合理吗?我在说“这是事实”好吗?

又跑题了……还是说work around,我在找shebang如何支持多个参数上面(前文提到了,从clojure入手是没法解决问题的——至少没法彻底解决OwnWaterloo所有的问题),假设我们可以写特殊的shebang,然后这个shebang能分离参数,那么就很不错了。

不过我查询了POSIX(这时已经早晨7点左右了),才知道shebang不是shell的行为,POSIX规定shell的脚本第一行如果是#!开头是“unspecified”的,然后我查了exec,发现只有很小一段文字提到了。而且是说“直接调用#!后面的代码,然后将程序以stdin的形式喂给解释器”。这样其实就很奇怪了。如果是这样,#!后面就应该是**完整**的命令行,而不应该是我在1L说的待组装的命令行了。而这样的话,操作系统分离参数应该是很正常的事情才对啊!

那么,就只剩下一个可能了:我这里用的是windows,而windows是没有shebang的(甚至连exec系列函数都没有!),所以shebang只有可能是mingw模拟的。那么这应该是minggw的bug。现在应该找一个Linux环境,看看会不会分隔参数,如果会,向MinGW提交Bug,如果不会,向Linux提一下问题。

这才是解决方案吧?——当然,1L已经提到了,你已经通过另外一个方式解决了问题,这些只是为了从根本原因上——shell的shebang和clojure没有driver——上出发去解决。我似乎并没有说过你的使用场景不合理。包括我在1L的帖子都完全没有这个意思。我只是说开发者没考虑这个场景、或者这个场景不是开发者的设计目标、或者开发者对这个使用方式的实现有bug,我自始自终没有说过这不合理吧?而且我的确是一开始就去找work around啊,一开始推荐你自己写一个driver,你说不合理,我就又去鼓捣tcsh到去看一个shell的源代码到底怎么处理的,然后去Stack Overflow注册账户,提问,然后又去看POSIX,难道我不是为了解决问题才这样么?难道是抽风了?

仅仅描述一下事实,怎么就刺痛你了呢?非要别人跟着你一起抱怨让你有共鸣你才开心么?这样能解决问题吗?


作者: OwnWaterloo    时间: 2012-10-09 18:40
回复 1# starwing83

>> 事情最开始是这样的,OW想用clojure写脚本
从你的角度,可能是这样。
从我的角度,这事情从emacs lisp就开始了。

所以我才知道你用的是 #!/usr/bin/perl -w 而不是 #!/usr/bin/env perl -w。
所以在知道shebang的设计有重大缺陷。
所以才知道有些软件为什么要支持 '-Xopt1 arg1 opt2 arg2'
所以才认为语言应该提供一个不需要参数的launcher。

emacs始终没有,它至少得加一个--script参数。
但clojure有,只是官方 —— clojure的repo、clojure.org里的download —— 没有附带而已。
4楼列出的就是一个例子:
clojure /usr/bin/clj
clojure /usr/share/clojure/clojure.jar



>> 我个人觉得clojure本身是基于java-vm的一种语言。它本身其实并不考虑作为脚本这么一个用途,所以不提供这样的命名约定什么的其实也是合理的。不过

clojure基于jvm于是本身不考虑作为脚本用途 —— 你敢不敢承认这话是你自己的臆测?

0. 有些case,尤其是牵涉到网络传输的, 根本不在乎启动速度。
1. 前面一个回复已经说了, 哪怕是emacs lisp这种特殊目的的语言都有当作脚本的需求, 何况是clojure这种通用目的的语言?
2. 各种linux发行版的软件仓库里都有clj, 又该怎么解释? 它们都是傻叉对不对,拿jvm这种启动就要花时间的语言当脚本用?
我批评的是应该将clj更官方化, 最好是拿到clojure的repo里维护。
如果想偷懒, 至少在clojure.org里提一下, 启动方式是clj program.clj, 然后去自己操作系统的软件仓库里找clj。
这要求是不是合理?

是啊,我就是懒,哪怕我没解决这问题也懒得去跟官方说(不擅长英文的理由够充分吗?)。
我就在qq上吐槽了一句"他咪咪的官方居然不带", 在你看来是抱怨了对不对? 是"向你"抱怨了对不对? 就算是我怨妇了一句, 你接下来跟我扯这么多又是怎么回事?
我因为一个合理的需求怨妇了一句, 你给我扯这么多无理取闹的东西, 真tm烦。


>> 我在考虑这么一个问题,就是软件本身的设计目的,和用户的需求不明确的时候,用户到底应该怎么办。我对OwnWaterloo说,你应该去clojure邮件列表发言,说明这个问题,而不是跟我讨论,因为这完全没有用。不过我也不知道OwnWaterloo自己的看法是如何,大概是“我已经想到一种解决方案了,我为什么要等待别人去解决这个问题呢?”

用户需求不明确? 不要自己骗自己了。
我找里讨论? 就像"tm啥啥啥网站又被盾了", 你怎么就不会认为我是在和你讨论? 怎么就不推荐我去给government的邮件列表发言? 我敢去吗?
"他咪咪的官方居然不带", 就是这样个情况。 在给提jark, clj时顺带吐槽了一句, 就是想和你讨论了?

另外: 我还真就是这么想的。 而且这解决方案不是刚想到, 而是在emacs lisp那时就知道了。
所以遇见clojure就有经验了, 赶紧找无参数的启动器, 结果没有, 那只能不用shebang而是混合语言了。
邮件列表有用? 你提了对方就会理你?Roberto 拒绝、无视过多少? 这其中还包括你自己的。
给你看个我在"找"的过程中发现clojure用户是怎么吐槽这语言的:
http://stackoverflow.com/questio ... shebangs-in-clojure

I'm surprised the Clojure authors didn't try harder to make Clojure scripts fit in better. – sarnold Mar 28 '11 at 7:11

The Clojure community is anti-POSIX. How do I shebang? "Don't; Use clj." How do I manually compile? "Don't; use Leiningen." – mcandre Mar 30 '11 at 1:54


是啊,我就是等不及。等不及clojure去支持(哪怕真能说服rich), 等不及他人回答我的"问", 因为通过"找"就能找出他人之前"问过"的。
你问的tcsh的两问题, 到现在有人理你么? "问"比"找"能先进在哪里?
当我"问"了, 要么是这问题我确实不关心,只想找个solution —— 比如被别人问起office什么什么功能 —— 要么就是我最后的手段, 先问着, 然后去找其他方案。 有人回答就赚到了。


>> 我自己其实也遇到了这种关于“需求”的情况。我用tcsh,tcsh本身的shebang我很少用(其实我是根本就没用过,脚本我都是直接用Vim执行,或者在命令行会写解释器来执行,很少会直接执行脚本),所以在测试的时候,我发现tcsh的windows版本竟然不认shebang,然后经过了Stack Overflow提问、自行编译等等方式最后都没有解决这个问题。这本质上依然是“软件的开发者没有满足使用者的需求”。我认为,我遇到的情况是不合理的,因为作为一个shell,在任何系统上行为一致应该是很有必要的。tcsh不支持shebang的原因是它支持Windows式的“按照后缀名判断文件类型”,可是在这之前,先打开文件并检测一下#!应该是很简单的。而且tcsh的源代码中的确也表示Win32移植版本应该支持HASHBANG特性。

"任何系统上行为一致"? 目录树结构都不一样, 一致个毛啊。 人家凭什么要去重复设计一个单根到多驱动器的映射方案?
源代码中的确表示? 就因为一句 #define HASHBANG 1? 不要自己骗自己。
你之前也说过, 以为tcc是stateless的, 最终发现是个骗局。 这有可能又是另一个"想重构、但做到一半(这次是#define HASHBANG 1)没动力或代价太高就摆那不管了"?


>> 我认为我遇到的现象和OwnWaterloo遇到的现象是不一样的。Clojure的官方主页上完全没有提到过支持在shell中直接执行clojure程序的做法。而tcsh作为一个shell,是必须满足POSIX对shell的要求的——即至少在某种情形下识别shebang。所以这并不是一种情况。对clojure来说,这种用途是作者“完全没有考虑过,或者没有考虑透彻的使用情景”,而对tcsh来说,这应该是“宣称的功能没有达到”。

windows关posix什么事? windows的posix子系统记得是因为有段时间吃官司了。 之后风头过了就停止了。 进度都还没达到shell那里去。

我评判的就是clojure.org根本就不提clj。
至于clojure是否可以作为script, 我再给你找个证据 http://clojure.org/repl_and_main
如果你还要继续说此script非彼script, 又或者还是不承认clojure可以当作script用, 我真拿你没办法。
而如果你还敢承认这一点, 那在shell中直接执行也是"暗含的"功能。 同样按你的说法是"宣称的功能没有达到"。

哎。。。 居然最终按你的路线走, 得出个"宣称功能没达到"。。。
从"而tcsh作为一个shell,是必须满足POSIX对shell的要求的" 这句开始就可以不理你的。


>> 因为#字符在clojure中并不是注释符。可以发现clojure的确是对clojure程序中包含shebang做出了支持。问题在于这个支持不全面,并不能保证clojure一定能够通过shebang调用到。一方面,shell不支持shebang参数分割是一个缺陷,另一方面,clojure本身没有提供独立的可执行的工具来直接执行clojure程序也是一个问题。两者共同造成了clojure无法通过shebang执行的情况。

clojure在277a070955e86697c2e0f38883ccab945c47e50a这个commit就增加#!作为至行末注释。
这个commit是1.0之前的200多个commit。  3年前, 1.0之前就支持了。
只是文档一直没提这个事。


>> 这其实是另一个话题了,在两个软件的缺陷同时造成一个困难的时候,谁应该为这个困难负责?OwnWaterloo认为应该是clojure,我不知道这是基于什么情况的考虑,反正我觉得应该负责的是shell。因为归根结底,是shell的shebang不完善造成的,clojure提供独立执行文件的方式只是一个work around而已,而shell的shebang仍然不完善。

我一直都承认责任在shebang。
但问题已经产生了,只追究责任有什么用?因为责任不在自己就事不关己了? 不说别的, 你为Windows的各种缺陷擦过多少次屁股? 因为这是Windows的责任所以自己就什么事都不做? 等着Windows去更新? 它会理你?

shebang这种老古董,你有能力让所有*nix的发行版都更新并让它分离参数?劝说所有的*nix用户都去更新?就为了一个shebang? 这现实么?
哪怕责任不在自己, 但能不能让一步,语言自己提供一个launcher? 而这就很现实。



>> 4. 如果你是使用者,你在向人抱怨自己的“正常”使用没有达到预期的目标,反而需要自己去想work around,并埋怨其设计糟糕的时候,如果有人提出相反意见,你是否能保持冷静并考虑。

你那也叫相反意见? 你完全是更年期综合征好吗?
我坚持和你这种不用unix那一套的人纠缠了这么久,通篇都是你自己的各种臆测,这样讨论真心累啊。你什么时候变成这种人了?
最后实在觉得太浪费时间不想理你了,结果被你反咬一口说我不冷静?

>> 6. 对待这种情况,作为抱怨者,和作为被抱怨者,以及作为聆听抱怨者,应该采取什么样的行为是合适的?

得,以后我再也不"抱怨"了,中?
作者: __BlueGuy__    时间: 2012-10-09 18:41

                             
作者: OwnWaterloo    时间: 2012-10-09 18:42
回复 4# KanonInD

clj在各种软件包管理器管理的软件仓库里(其实我不知道应该怎么说,对*nix那套不熟)。
但不在source repository, 也不在clojure.org的download, 而且clojure.org连提都不提 —— 我批评的就是这点。
作者: starwing83    时间: 2012-10-09 18:44
本帖最后由 starwing83 于 2012-10-09 18:45 编辑

我擦……写了这么多,居然忘了写结论!!!

那么,就只剩下一个可能了:我这里用的是windows,而windows是没有shebang的(甚至连exec系列函数都没有!),所以shebang只有可能是mingw模拟的。那么这应该是minggw的bug。现在应该找一个Linux环境,看看会不会分隔参数,如果会,向MinGW提交Bug,如果不会,向Linux提一下问题。


tcsh在Windows上的shebang是**会**分割参数的!

所以,只有一种可能了:即不分割参数应该是mingw或mingw的后端cygwin的Bug!!

这事儿应该向他们提才对……

下面的代码,在tcsh上面,完美运行:
  1. #!/mingw/git/bin/env java clojure.main

  2. (prn "Hello World\n")
复制代码
root暂时只有bash支持,我将就这么写了。不然找不到env。

但是,这个代码执行了!这证明至少tcsh的shebang模拟支持是可以分离参数的!
作者: starwing83    时间: 2012-10-09 18:55
= =我的想法有问题么……clojure毕竟不是windows嘛……但是如果最终不支持也没办法嘛……我的策略一般是:

1. 搜索看是否有支持的隐藏开关(tcsh里面就有一个……)
2. 邮件列表提问
3. 如果没人回,自己写一个patch,再在邮件列表ANN

Windows完全无力啊,不开源啊……

好吧,就算clojure和Windows一样,rich对于自己不关心的特性完全不理,而且绝对不带入版本库。

——你对我抱怨也没用啊……我最终也只会上面提到的三板斧啊,而且最终你解决了问题也很好啊……

最多赞扬一下混合语言方案比较“巧妙”……

就算是吐槽了,总觉得这种吐槽有点奇怪……
作者: starwing83    时间: 2012-10-09 18:58
回复 13# OwnWaterloo


    其实我对这些都没意见,你说的都对,我只是对一件事情很奇怪——

如果你对一件事情很无力,无力到作者根本不理这个需求,无力到你只能抱怨的时候,我说一句“你抱怨也没用”,有问题么?
作者: starwing83    时间: 2012-10-09 19:00
回复 15# OwnWaterloo


    好吧,我去加clojure的邮件列表,找一下他们的wiki,争取让他们在reference里面提一下……这个可以有——但问题还是一样的——他们如果不加,你依然没有任何办法,网站在人家手上呢,你除了提一下以外,根本做不了别的任何事情——如果是这样,你有啥办法来着……
作者: OwnWaterloo    时间: 2012-10-09 19:04
回复 12# starwing83

>>  你怎么知道我不是这样的呢?难道我没有找work around吗?
>> 去stack overflow提问如何让clojure支持shebang。
>> 测试tcsh对shebang的支持(因为shebang不分离参数是bash的问题)——最后,大概是昨晚5点的样子吧,得到结论了。shebang是系统的事儿。跟shell没关系。系统自己的exec系列系统调用处理shebang的。还有tcsh的windows版本不支持shebang问题也解决了,是个环境变量:TCSHONLYSTARTEXES,天杀的文档。好,这个“子过程”返回。

>> 我没没有对你的work around有任何恶意的评价吧?相反我觉得这是个解决方案。而且,我对你的说法的评价,都是在你提出这个work around很久以后吧。在这之前,似乎我一直在想办法去找你的问题的解决方案吧?在这之前我一直都没有说你的需求不合理吧??

哦,原来你和我聊天的同时一直是为了帮我找work around?
感谢你这份闲心啊。

但如果你仔细看过我在qq回你的话(包括map不应该返回table等等),你就应该知道我已经找到work around了 —— 你确实也知道了。
既然我都屈就work around了,那这问题90%的几率没有正当途径能解决了 —— 只是tcsh支持shebang分离参数根本不现实, 如果你还不理解为什么, 你只能自己体会, 我没法给你说清楚了。


一直没有说我的需求不合理? 说话要凭良心的好吗?
clojure不用做script是不是你说的?
unix哲学不能当教条是不是你说的?
server要daemon是不是你说的?
总之都是我做事的方法有问题。。。

太多了,这才一天不到就不认账了?



>> 另外想问一下,既然你也知道,emacs lisp并不是以作scripting language为主要目的,而你也这么用了。而且我也没有评价这个不合理,为什么你觉得我说“开发者并没有考虑到这个情况”就是“这个情况是不合理的”?我从来没有在这两者之间画上等号啊?我仅仅是说,这个情况clojure没有考虑,要你去mailing list去问而已,我根本就没有说过这个想法是很不合理的啊?我说过最接近的一个话是“clojure不是用作脚本设计的,所以不提供启动器也是天经地义的吧”,问题是,“不是作脚本设计”和“作脚本设计就不合理”这个之间是不是没有等价关系?光盘不是做衣服的不是做建筑塑料的可是就是有人用光盘盘片做这些艺术品啊,没有不合理啊。

终于服软了? 终于承认"用做脚本是合理"的了? 进而开始和我玩文字游戏了?
我就问你, 既然用脚本是合理的, 昨天晚上你和我争这几个小时, 你是不是全在说废话?


>> 好,继续说work around。既然你提到了那个解决方案。我的注意力就放到了“如何让shell支持多参数shebang上”。因为添加一个clj是很简单的事情,然而你说clojure没提供,而且连名字都没有标准化——事实上,我觉得有问题的地方是,他没提供这一点是事实,如果你想从这一点出发,要么你自己提供一个,然后等官方提供了以后再改;要么你立刻要求官方提供一个,要么你黑了官方网站自己加一个——不管怎么说,你对我说这个话完全没有意义啊!我不是clojure的维护者啊。你对我抱怨,我也只能有两个态度:1.“啊,clojure好差劲啊,这样的东西都不提供,真是的,完全不考虑使用者的感受和正常需求嘛”——然后又能怎么样?联名上书吗?就是因为考虑到这一点,我才采用了第二个态度2.“你跟我抱怨是没用的,clojure自己本身就没用提供这个东西就已经是事实了。如果clojure真的没提供,那么显然它无法阻止别的用户自己写driver脚本,那么driver脚本的名字不统一估计也是事实了,既然是事实,你对我说又有什么用呢?”

>> 我有说你的需求不合理吗?我在说“这是事实”好吗?

我就说了一句"他咪咪的居然官方不带", 要你解决这问题了? 我下次说一句"某某网站被墙", 你是不是要去把gfw给黑了?
就因为提到jark了,提到clj了, 就顺带说了这么一句, 你就开始和我争了一晚上, 一会说我不该这样用, 一会说我不该那样用。
现在又反咬我一口, 说"某某不是被设计这样用的", 其实不代表"某某这样用是不合理的", 其实是合理的。 你都是对的, 只是我理解错了你的话中话。
既然是合理的, 你和我争个屁?


>> 又跑题了……还是说work around,我在找shebang如何支持多个参数上面(前文提到了,从clojure入手是没法解决问题的——至少没法彻底解决OwnWaterloo所有的问题),假设我们可以写特殊的shebang,然后这个shebang能分离参数,那么就很不错了。

>> 不过我查询了POSIX(这时已经早晨7点左右了),才知道shebang不是shell的行为,POSIX规定shell的脚本第一行如果是#!开头是“unspecified”的,然后我查了>> exec,发现只有很小一段文字提到了。而且是说“直接调用#!后面的代码,然后将程序以stdin的形式喂给解释器”。这样其实就很奇怪了。如果是这样,#!后面就应>> 该是**完整**的命令行,而不应该是我在1L说的待组装的命令行了。而这样的话,操作系统分离参数应该是很正常的事情才对啊!

>> 那么,就只剩下一个可能了:我这里用的是windows,而windows是没有shebang的(甚至连exec系列函数都没有!),所以shebang只有可能是mingw模拟的。那么这应该是minggw的bug。现在应该找一个Linux环境,看看会不会分隔参数,如果会,向MinGW提交Bug,如果不会,向Linux提一下问题。

>> 这才是解决方案吧?——当然,1L已经提到了,你已经通过另外一个方式解决了问题,这些只是为了从根本原因上——shell的shebang和clojure没有driver——上出发去解决。我似乎并没有说过你的使用场景不合理。包括我在1L的帖子都完全没有这个意思。我只是说开发者没考虑这个场景、或者这个场景不是开发者的设计目标、或者开发者对这个使用方式的实现有bug,我自始自终没有说过这不合理吧?而且我的确是一开始就去找work around啊,一开始推荐你自己写一个driver,你说不合理,我就又去鼓捣tcsh到去看一个shell的源代码到底怎么处理的,然后去Stack Overflow注册账户,提问,然后又去看POSIX,难道我不是为了解决问题才这样么?难道是抽风了?


很不错个毛。 从shell入手一开始就是不现实的。 理前面已经说过了。


>> 仅仅描述一下事实,怎么就刺痛你了呢?非要别人跟着你一起抱怨让你有共鸣你才开心么?这样能解决问题吗?

你要我说几次? 这问题我早解决了。 不需要用户更换、更新自己的shell的情况下解决了。
你又解决了么? 哪怕你自己倒腾出一个shell, 对我来说问题依然没解决。 我要避免的就是过多的依赖, 改shell从一开始就是不符合题意的。
你描述了什么事实? 你自己去翻聊天记录, 把我惹毛的是责任问题?是shebang错了还是clojure错了? 我从一开始就说事是shebang的责任, 但要解决它不现实。
是不是你在一个不用unix那套的机制下一会说我这样做不行, 那样做不行才把我惹毛的。

作者: mirnshi    时间: 2012-10-09 19:11
原来是从QQ打到CU的
作者: OwnWaterloo    时间: 2012-10-09 19:18
starwing83 发表于 2012-10-09 18:58
回复 13# OwnWaterloo

其实我对这些都没意见,你说的都对,我只是对一件事情很奇怪——

如果你对一件事情很无力,无力到作者根本不理这个需求,无力到你只能抱怨的时候,我说一句“你抱怨也没用”,有问题么?


你是真不懂还是装不懂?  你要是直接说"我抱怨也没用", 我半点意见都没有。 我本来就只是随口提一句。

把我惹毛的是你一晚上你不停的给我说:
1. clojure不用作script
2. 用run_clojure运行
3. 不要全信unix那套
4. server应该daemon
。。。

你现在和我玩文字游戏, "clojure不用作script" 不代表clojure用做script是不合理的。 现在你承认这是合理的?
那就从"你一晚上说我这不合理那不合理" 变成了 "你一晚上和我说一些与主题无关的废话" 而已。
我错了, 是我低估你的跑题能力了, 我不应该将这些理解为你在批评这些用法不合理, 我应该从发现你跑题就不理你就行了。


另外, 我对这事很有力, 我已经(早在emacs lisp时就)找到了不用其他人(有可能就是另一台机器前的我)更换、更新shell就可以直接执行的方法。
如果你要去clojure的邮件列表提, 那很好。 如果它要改, 那更好。 改了我就用, 不改我就维持原样。 对我丝毫不影响。
我根本就没兴趣得到一个答案: 作者会不会理会这个需求。 我对clojure又没有归属感, 只要它在大方向上不出错就行了。
作者: OwnWaterloo    时间: 2012-10-09 19:31
starwing83 发表于 2012-10-09 18:44
我擦……写了这么多,居然忘了写结论!!!

tcsh在Windows上的shebang是**会**分割参数的!
所以,只有一种可能了:即不分割参数应该是mingw或mingw的后端cygwin的Bug!!
这事儿应该向他们提才对……


没用, 从shell入手对我来说解决不了任何问题。
我的目的就是要减少用户(哪怕就是另一个机器前的我)的依赖。
相比更换、更新shell,我还不如直接下载一个clj启动器就完了。 这样我还可以继续用bash, 以及git的官方提供的补全脚本。

tcsh支持了, msys支持么? cygwin又支持么? sh/bash? dash? linux? mac os?
你让它们都支持分离参数? 你让用户都去更新shell软件或操作系统? 你做得到?



f() & g(), 如果f与g的副作用的产生顺序是需要留意的, 难道你会因此去给C标准委员会提议,让&产生一个顺序, 然后等各种编译器支持, 然后等用户换编译器?
你也知道:
T x = f();
U y = g();
x & y 不就完了?


虽然不是一个语言, 但shebang是否分离参数是unspecified。
如果能不利用这个unspecified的行为达成自己的目的 —— 无论clojure是否官方提供支持,都已经达成了 —— 何必要去和各种implementations作对?
作者: OwnWaterloo    时间: 2012-10-09 19:53
标题: 达成同一目的的方法有很多,选哪个?
回复 16# starwing83

继续接着回复。

C的例子有点牵强, 但我一时也想不到更好的例子。
C的例子想表达的是"方法的代价", 而不是"正确地做事方法"。
在C的例子里, "正确的做事方法"也恰好是"代价最小"的方法, 所以我说这个例子有点牵强。


而回到shebang这个事。
混合语言是代价最低的 —— 除了难看,没其他代价了。 而且这行真不需要读懂,只需要知道magic happens here就ok了。
无参数启动器会产生一点点代价, 奖励就是依然可以用shebang, 可以被大多数人理解。
而改shell, 虽然它是"最正确地做事方式" —— 我一直,从最最开始就承认这点 —— 但它的代价也是最高的,高得不是一个数量级了。


所以我不会选改shell这种方式。


而你要选改shell的方式,我绝对没意见。
但你怎么就不理解我做出的各种权衡?(不一定是混合语言 vs clj vs shell,我忘记你在这方面有没有说什么了) 而是整晚上说不应该这样用,不应该哪样用。。。
哪怕你真的是在说我不应该怎样用,我又哪次不是在虚心的听? 我能坚持和你扯一晚上,就是因为想着"万一这家伙真有什么地方说中了", 我就赚到了。
可惜一晚上都是一些乱七八糟的理由, 比如让我去找不以.exe发布的软件,比如clojure不作为script是因为有clojurescript。。。
作者: OwnWaterloo    时间: 2012-10-09 20:25
starwing83 发表于 2012-10-09 19:00
回复 15# OwnWaterloo

    好吧,我去加clojure的邮件列表,找一下他们的wiki,争取让他们在reference里面提一下……这个可以有——但问题还是一样的——他们如果不加,你依然没有任何办法,网站在人家手上呢,你除了提一下以外,根本做不了别的任何事情——如果是这样,你有啥办法来着……


这个都随便你。反正我是懒得写英文了。 读、听、写、说一个比一个吃力。


比这个更严重的事我都遇到过,比如有滥用macro的倾向。这事比shebang什么的严重得多。
shebang大不了不写,不会影响代码,影响的只是运行方式。
macro被滥用了会影响代码的。

但最后想想还是算了。。。 懒得去写英文。
总之,clojure又不是我自己的语言,没有归属感。只要大方向不错,能为我所用,投入少见效快就行。小细节上就随便它搞了。
作者: starwing83    时间: 2012-10-09 20:37
回复 24# OwnWaterloo


    好吧好吧,我败了。所有用法,只要你用出来了,就是合理的,好吧………………

不过我还是觉得发布的软件,至少也得装个exe的壳儿,哪怕是脚本写的,这方面的事儿我做过不止一次了,还弄出一个自动装Lua到壳儿的办法……有段时间专门写了一个lunamark-standalone,你知道的…………好吧好吧这不是重点………………

至于一晚上……那的确是我的活跃时间啊……不想写代码找个人扯东扯西的放松一下也不行么……
作者: OwnWaterloo    时间: 2012-10-09 20:45
starwing83 发表于 2012-10-09 18:44

下面的代码,在tcsh上面,完美运行:
#!/mingw/git/bin/env java clojure.main


已经不完美了。 前面就说过,要在Windows上也用shebang,还得弄一个单根到多驱动器的映射。
别人不可能为了Windows而写"/mingw/git/bin/env" 的。 只能去适应现有的 "/usr/bin/env", 然后要将/usr映射到什么地方去。
无论这步的代价如何, 但让其他人用tcsh对我来说就是一个很大的代价了。


另外,说到Windows,我又想起了。昨天你说的"不该不该"什么里,还包括"不该同时用Windows/linux"。不过我不记得原话了。
你要utility.sh, utility.bat是你的事。
但我希望就只有一份 utility.lang 并且希望它在 cmd.exe, msys, cygwin, linux下都能用 —— 这都能有错了?
而且我还达到这个目标了, 我又有反过来说你写两份很搓?  如果我找到一个漂亮干净的做法我真的就会说你写两份很搓了, 只是混合语言本身也很搓。
我就是对 "clojure不将clj作为官方使得我达到只有 utility.clj 的目标更困难, 本来可以以较低代价写得漂亮的"  吐槽了一下, 值得你说我"谁让你同时用windows/linux"么?

当然,你现在估计又会改口说这是合理的了。。。
作者: starwing83    时间: 2012-10-09 20:50
回复 27# OwnWaterloo


    我也没说这个很挫吧?

我自己写两份是因为shell不认bat好不好……

你要是能找出来在cmd/sh下面通用的混合语言我也跟着搞啊……lua邮件列表又一次就是讨论这个话题的说,不过也没什么结果。

所以这样的确是很麻烦啊……混用linux/windows本来就是麻烦事,也不止这个了,你以前吐槽的tty问题,记得么?问题本来就大把的……
作者: OwnWaterloo    时间: 2012-10-09 20:58
starwing83 发表于 2012-10-09 18:55
= =我的想法有问题么……clojure毕竟不是windows嘛……但是如果最终不支持也没办法嘛……我的策略一般是:

1. 搜索看是否有支持的隐藏开关(tcsh里面就有一个……)
2. 邮件列表提问
3. 如果没人回,自己写一个patch,再在邮件列表ANN

Windows完全无力啊,不开源啊……

好吧,就算clojure和Windows一样,rich对于自己不关心的特性完全不理,而且绝对不带入版本库。

——你对我抱怨也没用啊……我最终也只会上面提到的三板斧啊,而且最终你解决了问题也很好啊……

最多赞扬一下混合语言方案比较“巧妙”……

就算是吐槽了,总觉得这种吐槽有点奇怪……



你的想法 —— 这里是指向rich提意见? —— 没问题。
但我也不觉得我的想法 —— 路上有坨便便,懒得理,反正道路宽着,我绕道走 —— 有什么问题。
也不是在抱怨, 就随口提了一下。  对官方而言只是很小一件事, 但它不做, 就会造成很多不方便。

混合语言的方案我本来都不想提的, 所以都是在和你说clj。 我都忘了为什么要给你提了。  反正不是为了炫。

2楼的那个我能读懂, 因为比较复杂的是clojure方面的。 但我不会这么写, 4行代码啊。。。
而我给你说那个one-liner别人不给我解释我真不知道是怎么回事, 因为trick发生在shell那边。
:好像是个空操作,对clojure以及el来说是keyword。 ":"也是空操作我就彻底晕了。  如果有其他更好的方案还坚持用它就是炫耀&耻辱了。
作者: starwing83    时间: 2012-10-09 21:10
回复 29# OwnWaterloo


    这个我倒是看得懂的………………

对clojure而言:


":" -- 字符串
;  -- 注释

对shell而言:

":"就是escape后的:,空操作
;  命令分隔符,表示两个命令顺次执行

利用的就是这个。

如果觉得可能有问题,可以这样:

:shebang; xxxxxx

我记得冒号后面跟着一个identifier也是空操作的,这个比":"稍微verbose一点。
作者: OwnWaterloo    时间: 2012-10-09 21:11
starwing83 发表于 2012-10-09 20:37
所有用法,只要你用出来了,就是合理的,好吧………………

我没这种意思啊。 只是你提的那些理由确实都。。。  给我感觉完全是刁难。


starwing83 发表于 2012-10-09 20:37
不过我还是觉得发布的软件,至少也得装个exe的壳儿,哪怕是脚本写的,这方面的事儿我做过不止一次了,还弄出一个自动装Lua到壳儿的办法……有段时间专门写了一个lunamark-standalone,你知道的…………好吧好吧这不是重点………………

你要加就加啊。 我能理解有个exe让用户直接点是必要的。
但不是所有程序(我都不记得当时是在争那个词了,是程序还是软件,太无聊了)都是面向最终用户的。
而且你自己机器上说不定就有这种程序。改了源代码马上就能看到效果(不需要在加一个exe的壳),少一个环节正是开发效率提升的体现。怎么就非要我去加.exe, 去找不是.exe发布的软件呢?



starwing83 发表于 2012-10-09 20:37
至于一晚上……那的确是我的活跃时间啊……不想写代码找个人扯东扯西的放松一下也不行么……

日, 我原本的打算就只是补充两点:
1. 有个解决clojure启动慢的jark, 只是我平时都用shell-mode,没有重复启动jvm, 所以前几天就没想起这事
2. gfor "把关"(我忘记你原话了), 难道是因为map直接返回整个table? 如果是这样, 这种列表操作的库还是没有实用价值。
然后就闪人去干正事 —— 用一个垃圾语言实现另一个垃圾语言,你懂的 —— 结果你跟我扯一晚上。。。
作者: OwnWaterloo    时间: 2012-10-09 21:20
回复 30# starwing83

我是搜到这个: http://www.emacswiki.org/emacs-es/EmacsScripts  才知道的。

:是空操作。。。 不专门研究shell语言的,只是依葫芦画瓢写写的人。。。 平时哪有机会会用到空操作?
这都算了,我都可以理解。。。
为嘛":"也是啊?
This works, since “:” is the same as : to the shell


哪怕双引号是弱引用(好像是这个名, '单引号内容始终是verbatim', 而"双引号里的内容可能会被替换 $(date)"), 也得有个$才对啊。
嗯,这又是顺带说说而已。 弄不明白就算了。。。  我又懒了, 懒得去shell板块问。。。
作者: starwing83    时间: 2012-10-09 21:27
回复 32# OwnWaterloo


    是这样的,shell命令在实际执行之前,会经过多道处理:

- wildcard替换
- 变量替换
- 脱引号
- 参数分割

等等。

对于:
":"

来说,没有wildcard,没有变量,就走到了脱引号这一步,":"变成了:,而:是builtin-command(内建命令),代表啥也不做。所以最后结果就是啥也不做了~~就是这样~~
作者: OwnWaterloo    时间: 2012-10-09 21:30
starwing83 发表于 2012-10-09 21:10
如果觉得可能有问题,可以这样:
:shebang; xxxxxx
我记得冒号后面跟着一个identifier也是空操作的,这个比":"稍微verbose一点。


el和clojure肯定认的。你的意思是如果shell也认,就可以这么写?

我觉得没必要。
只要不是#! 就免不了要给别人解释 —— 我就是烦这点, 如果用#!导致他人看不懂不是我的错。这都不知道还玩啥?
但不用#! ( 用 ":"; 或 :shebang; )而导致他人看不懂, 这责任划分就不明确, 就不好推卸了。。。
:shebang 并不一定是好主意, 因为这其实不是shebang了, 还是会引起人的疑惑。

反正都得解释 —— 也就是magic happens here, 我只知道这么多, 更多信息请去问懂shell的人 ——  ":"可以少敲几个字。。。
作者: OwnWaterloo    时间: 2012-10-09 21:33
回复 33# starwing83

也就是说,ls也可以写成"ls"?
擦。。。 试了试还真可以。。。
作者: starwing83    时间: 2012-10-09 21:36
回复 35# OwnWaterloo


    对shell来说,命令名和参数没区别,都一样处理的,假设有个目录里面有a.exe, b.exe, c.exe,你写:

$ *.exe

最终的结果就是执行: a.exe b.exe c.exe了。

只有到了最后一步,shell才会把一个string-array的第一项当做命令名,后续的当做命令的参数,到这一步命令名和参数才有区别……
作者: OwnWaterloo    时间: 2012-10-09 21:40
回复 8# mirnshi

clojure有特别处理#!。 从1.0之前就有。 只是文档一直不说这事。。。
但没有一个launcher也是无用功。

我也觉得直接挑战shebang机制代价太高, 重新实现env让它去分离参数至少可以把代价降低到更新一个软件。。。
而且这个软件 —— 反正都要更新,还不如另做一个专用的,比如叫interpreter-launcher啥的 —— 还可以顺带处理其他一些事情, 比如同语言多版本、多安装路径、初始化配置什么的。。。
作者: 346196247    时间: 2012-10-09 21:48
本帖最后由 346196247 于 2012-10-09 21:50 编辑

都出书把,这字够出书了 :wink:书名为,楼住标题,后面加一个疑问
作者: OwnWaterloo    时间: 2012-10-09 22:04
回复 36# starwing83

"$(echo date)" 。。。   我懂了。。。


其实昨天重点都不在jark, 而是map/filter到底返回什么。我很担心它们是直接返回一个table。

  1. for x in map(f2, filter(f1, map(f0, xs) ) ) do print(x) end
复制代码
如果要用列表操作以及它们的组合代替手写循环,需要达到的目标是上面的代码的空间代价是类似:

  1. for x0 in xs do
  2.   local x1 = f0(x0)
  3.   local x2 = f1(x1)
  4.   if not x2 then continue end -- 有 continue 么???
  5.   local x3 = f2(x2)
  6.   print(x3)
  7. end
复制代码
每一个元素的代价与处理的步骤多少(此处是f0,f1,f2)正相关都可以接受。
haskell还可以进一步优化为 local x2 = f1(f0(x)) 以及 print(f2(x2)) ;clojure我怀疑不行。
但整个循环的代价一定不能与元素个数(此处是xs的元素个数)有关。 否则就没意义了。

haskell是通过惰性求值完成的, clojure是通过seq(正在准备转换为recipe)。 而我听你说gfor用来把关什么的, 我就担心map会产生整个table。
准备说完jark后重点说这个的。。。 结果。。。   只听你说道map是产生一个函数。。。 那至少大方向没问题了。。。
作者: starwing83    时间: 2012-10-09 22:12
回复 39# OwnWaterloo


    其实要达到这样的效果,还是会有问题。

主要原因是天杀的所谓“stateless iterator”,即实际上ipairs返回的是iter, state, first_key,这玩意儿不能放到中间:

map(f, ipairs(t1), ipairs(t2)) -- 完蛋了,ipairs(t1)的state和first_key被吞了…

这时**只能**传递table或者closure。

但是closure代价太大,很慢的。

最终只剩下table了。

那啥,小数据量下,map的参数是table似乎没有问题吧?table本身做成惰性的也不难啊……

t = lazy_table(function()...end)

这种……t是标准的table,只是里面的key/value是惰性产生的……
作者: mirnshi    时间: 2012-10-09 22:13
回复 37# OwnWaterloo

修改env,至少可以让linux下的env与bsd下的env看齐。毕竟多数情况下,二者之间的兼容性很高的。不过话说回来,有些工具bsd做得很好,比如tar,不用区分压缩格式,自动识别。
   
作者: OwnWaterloo    时间: 2012-10-09 22:16
回复 41# mirnshi

我的感觉是。。。 修改env比劝说他人更新env难多了。。。
我自己就是个不爱升级软件的人。。。  ubuntu现在还在用8.04。。。  windows还在用xp sp2。。。
作者: mirnshi    时间: 2012-10-09 22:33
回复 42# OwnWaterloo

还停留在08年?

其实用脚本写个支持分拆参数的env,也很简单,可以随你的程序走。

   
作者: OwnWaterloo    时间: 2012-10-09 22:37
回复 40# starwing83

总不能小数据量一种写法,大数据量了再换另一种写法吧。。。
虽然有"先舒服地写,profiling后再挑重点改"的说法,我感觉说的不是同一件事。
现在出现的性能问题基本上都是自己把lazy用错了。。。  但编程的风格依然没变,无论数据量多少都不会改回循环(或loop/recur或do syntax)。


至于lua里怎么完成。。。   事不关己。。。 (主要是明年之前都很忙。。。 除非想通了半途而废)。
lazy table怎么弄? 比如, 如何实现一个range函数:

  1. for _,x in range(12) do print(x) end
复制代码
或者in ipairs(range(12))也行。 总之:
1. range(n)需要的内存与n无关
2. 并且如果它产生的伪table如果只是被顺序取, 并且不保存之前的引用, 那也要求需要的内存是常数。

lua怎么做? table当cons用?
作者: OwnWaterloo    时间: 2012-10-09 22:47
回复 43# mirnshi

问题是怎么说服用户,让他把/usr/bin/env 软连接到随程序附带的那个去?

嗯,这里要区分两类用户来说。。。
大部分Windows用户是第1种,最关心的是双击、下一步、下一步、下一步。。。 然后就能用了, 不关心这过程中对系统产生了什么全局的影响。
这种很好说服。。。

另一种就特别关心安装过程到底发生了什么。。。 所以我就特别喜欢免安装的,放到目录,改改PATH或者链接就行了。
要说服这类用户替换自己的/usr/bin/env就不容易。。。
嗯,写成脚本(文本格式,看得见摸得着)可能会有帮助。。。

作者: OwnWaterloo    时间: 2012-10-09 22:56
回复 44# OwnWaterloo

关于"不会改回循环", 我再声明一下: 没有以循环为耻。

如果能复用列表操作的库当然比一次又一次的用循环重复实现细节更好,至少少犯错。
而对clojure/haskell这种, 其实没有循环这种控制结构; 而且手写loop/recur比其他有循环结构的语言里更繁琐。。。
又容易出错, 而且还难写。。。   只要效率没问题(可能也就是一些inline做不了?), 完全没有用它们的理由。
作者: mirnshi    时间: 2012-10-09 22:57
回复 45# OwnWaterloo


写个myenv:
#!/mypath/bin/myenv interpreter arg1 arg2 ... argn

就ok了,既然是脚本就不用计较速度了,更何况是初始阶段的。   


作者: starwing83    时间: 2012-10-09 23:00
本帖最后由 starwing83 于 2012-10-09 23:04 编辑

回复 44# OwnWaterloo


    range的“stateless iterator”写法(效率最高,应用最狭窄):

  1. local function range_helper(n, i)
  2.    if i <= n then return i + 1 end
  3. end

  4. function range(n)
  5.    return range_helper, n, 0
  6. end
复制代码
注意,这里一个闭包都没有的。

如果数据量大,使用方式可以不变。也就是一个抽象层而已了。而table和closure都是很好的抽象层。

假设我需要这个stateless iterator变成闭包,就需要一个函数:

  1. function iter(f, s, init)
  2.    local t = {init}
  3.    return function()
  4.        t = {f(s, table.unpack(t))}
  5.        return table.unpack(t)
  6.    end
  7. end
复制代码
注意这个写法很浪费,因为每次调用都会产生一个表。更高效的写法是在C API里面写。可以做到每次调用都不产生内存。

有了iter函数,那么就可以这样:

map(f, iter(ipairs(t1)), iter(range(10)))

iter不一定要在这里出现,甚至可以让iter函数是一个处理stateless iterator generator的函数,即抽一个地方:

  1. if data_is_too_big then
  2.     map = iter(map)
  3. end
复制代码
iter负责把表驱动的改为用闭包驱动的。这是很简单的。

好了,这是用闭包/stateless iterator作为接口。如果用表作为接口:

  1. function range(n)
  2.    return setmetatable({}, {__index = function(t, k)
  3.        if k < n then return k end
  4.    end})
  5. end
复制代码
这个写法照样是示例性的,metatable和__index函数都是可以stateless的。这没有问题。

我们可以通过lazy_table函数,做到closure/stateless到table的转换。

  1. if data_is_too_large then
  2.     map = lazy_table(map)
  3. end
复制代码
之前map接受table,返回table之前的map接受闭包,返回闭包,我们可以让现在map接受table(这需要所有的工具都被lazy_table包裹),但是返回的是个lazy_table。即惰性的table。

我们还可以设计接口,让接受表返回表的map变成接受闭包返回闭包的。方案也是上面的lazy_table,它可以让map本身接受的表实际上以前是个闭包,而返回的表实际上依然是个闭包。

这就是Lua中的序列操作和惰性操作的基本方式。有两套接口:函数和表,两套接口都是可以互相转换的,不存在兼容性问题。
      

作者: OwnWaterloo    时间: 2012-10-09 23:02
回复 47# mirnshi

嗯,我想的就是这种。。。 说服其他人替换env不容易。。。  让它另外装一个可能更容易一些。。。
但既然反正都是要装。。。 不如索性做大点。。。 就不做env那种设置环境的事了, 而是专门负责处理各种语言的shebang。。。
作者: OwnWaterloo    时间: 2012-10-09 23:18
回复 48# starwing83

我已经跟不上了。。。
总之如果达不到前面说的对空间的要求。。。 那列表操作库就真的是在做表的转换,而不是在支持另一种编程方式。。。
作者: starwing83    时间: 2012-10-09 23:42
回复 46# OwnWaterloo


    是否存在比丰富表操作更好写的循环方式呢?
作者: tulip0425    时间: 2012-10-11 10:30
很好!很强大!
作者: OwnWaterloo    时间: 2012-10-11 16:37
回复 53# starwing83
回复 52# starwing83
回复 51# starwing83

不知道。。。  哥哥,这些事情我们年后慢慢讨论中不。。。
作者: dyyseo    时间: 2012-10-19 16:57
。。。。。。。。。。。。。。。
作者: epstar    时间: 2012-10-28 20:50
我觉得挺好的,大家的看法呢
作者: OwnWaterloo    时间: 2012-11-10 00:17
留个记录。。。

clojure有留意这件事: http://dev.clojure.org/display/design/CLJ+Launcher
Russ Olsen is leading the charge to create a standard launcher for Clojure, which will be a(n) (r)evolution of his dejour project.

而且是放在: Usability 子目录下。


而且因为JVM启动慢的原因。。。 如果launcher是直接启动一个JVM的话,还会限制scripting的范围。。。
如果像jark那样启动一个JVM当server, 用其他语言 —— 启动快速,依赖小,jark好像只有200k —— 编写client作为launcher。。。
啊,有一堆.py文件可以丢垃圾桶了。。。
dejour这样搞不行的啊。。。





欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2