免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: asuka2001
打印 上一主题 下一主题

命名难,难于上青天 [复制链接]

论坛徽章:
0
211 [报告]
发表于 2012-02-17 23:54 |只看该作者
回复 206# 三月廿七


    深有其感。大四现在也在找工作。

论坛徽章:
5
狮子座
日期:2013-08-20 10:12:24午马
日期:2013-11-23 18:04:102015年辞旧岁徽章
日期:2015-03-03 16:54:152015亚冠之德黑兰石油
日期:2015-06-29 18:11:1115-16赛季CBA联赛之新疆
日期:2024-02-21 10:00:53
212 [报告]
发表于 2012-02-18 01:46 |只看该作者
幻の上帝 发表于 2012-02-17 18:31
几个问题。
这里的限制一定和灵活矛盾吗?
只说语言不说实现,能提供检查+不被重写的功能么?一定会导致“注定了决定某些函数到底是机器码还是函数这样的操作被放到了运行时”吗?(“运行时”说白了也不是相对而言的嘛。)这里的责任应该落实到语言还是语言的实现?
“如果当作C语言那样的语言用”——这个应该是语言设计的目的吗?
话说自然语言是怎么摆平这个的……


1. 这里其实主要说的是概念的灵活性会导致实现很尴尬。受lua的影响,我倾向于小语言的实现。
2. 这里绝对是要落实到语言的,因为这实际上是语言的动态类型这个特征决定的。
3. 这个是OW的目标啦,所以我才这么说,否则的话,lisp当脚本也还可以——问题是,lisp根本就没有一个能在轻量和性能上平衡的嵌入式实现。要么就是太重量级——那还不如用Python,要么就是性能不强——那还不如用lua,要么就是API接口有问题——比如tiny-scheme,C层面根本没法控制gc。如果lisp有个能跟lua比肩的实现我就立刻投奔lisp教去了。
4. 自然语言是NP难的 而且自然语言不遵守哥德尔不完全原理

论坛徽章:
5
狮子座
日期:2013-08-20 10:12:24午马
日期:2013-11-23 18:04:102015年辞旧岁徽章
日期:2015-03-03 16:54:152015亚冠之德黑兰石油
日期:2015-06-29 18:11:1115-16赛季CBA联赛之新疆
日期:2024-02-21 10:00:53
213 [报告]
发表于 2012-02-18 01:57 |只看该作者
回复 204# OwnWaterloo


    你也知道一个能打的都没有,你还皈依lisp教?难道是传说中的叶公好龙?

说明一个你没有意识到的问题:+是否映射机器码和是否能改变的确是正交的。YY导致了JIT,YN导致了静态编译,NY导致了动态类型语言,而NN导致了Java这样的残废……问题是你也知道我们的目标是静态编译……所以……(除非你还是准备运行时带gcc?你还是运行时带tcc好了 = =)

我真不是特别明白你的pass-by-value,要不要你重新开个贴详细讲解一下?讲解包括:

1.局部变量及作用域
2.全局变量
3.局部函数及upvalue
4.全局函数及不可改变的命名,还有对其他全局对象(变量+函数)的引用
5.如何实现共享的upvalue语义

你知道的,lua的_ENV方案太优美了,优美到我觉得一个程序,根本就不应该是有所谓“全局变量”一说的,这方面你得说服我。

最后,我想提出一个“导出对象”的概念,即C里面的extern linkage,你看看这个怎么和你的pass-by-value结合起来。这样才能最终编译成C代码。我的问题是,extern linkage可能不得不导致你写在顶层的变量实际上和写在函数里的变量不一样,失去了lua“文件即函数”的优雅。我是希望你设计的K是有这种优雅的。

论坛徽章:
5
狮子座
日期:2013-08-20 10:12:24午马
日期:2013-11-23 18:04:102015年辞旧岁徽章
日期:2015-03-03 16:54:152015亚冠之德黑兰石油
日期:2015-06-29 18:11:1115-16赛季CBA联赛之新疆
日期:2024-02-21 10:00:53
214 [报告]
发表于 2012-02-18 02:00 |只看该作者
还有一点,lisp其实全部都是变的(cons可变,程序即数据可变),而静态编译要求至少有些东西是不可变的。或者某些变化在编译时就能被判定,你不限制住改变,你怎么实现静态编译?

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
215 [报告]
发表于 2012-02-18 02:05 |只看该作者
回复 213# starwing83

写了一堆被我点错叉掉了……

1. 重量级真的是问题么?
haskell platform 800M呢……    但发布时,比如darcs,就只有4M(压缩)14M(解压),和git比比? 虽然功能不如git……
发布时能将不需要的功能strip掉就可以了?

2. api接口: 这也许真不容易……

3. 性能: 这个比lua强的应该不少。

http://ecls.sourceforge.net/  求点评啊……
这只是common lisp->C的,其实乱七八糟lisp->C的还有一些……

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
216 [报告]
发表于 2012-02-18 02:49 |只看该作者
回复 214# starwing83

>>  你也知道一个能打的都没有,你还皈依lisp教?难道是传说中的叶公好龙?

所以一直在说语言本身优美,但实现没找到好的。
或者是否不可能有好的实现?不就是在争论这个嘛……

>> 说明一个你没有意识到的问题:+是否映射机器码和是否能改变的确是正交的。

显然意识到了,那天qq难道白说了嘛…… 以后果然还是要gtalk…… 聊天记录方便……
所以才会说capture by value,以及cl那段不包含call的反汇编也许是因为safety的原因所以编译器才敢替换了也不管的优化。


>> 我真不是特别明白你的pass-by-value,要不要你重新开个贴详细讲解一下?讲解包括:

  1. (let ((x 12))
  2.   (print x) )
复制代码
(print x)有自由变量x,但这个表没有机会在(let 之外被求值,所以根本看不出它到底是dynamic还是lexical。

必须要让包含自由变量的表达式(或者函数什么的)在bound form之外求值才能看出来。

按注释前的序号阅读:

  1. (let ((x "dynamic: emacs lisp"))
  2.   ( (let ((x "capture by value: C++")) 1. 如果是非dynmaic,0处包含的自由变量就是这个。如果是capture by value,它的"值"会被复制到f中。
  3.       (let ((f (lambda () x)))  ;  0. 该表达式有自由变量x,并且它的求值会超出 1 处建立的bound,因此能观察到到底是什么作用域。
  4.         (set! x "lexical: C(top level),CL,scheme,lua...")) 2. 如果是词法,f中的x与这里被set!的x是同一个"变量",会影响到f。
  5.       f ) 3. 返回f, 使它超出1处的bound。
  6.   ) ) 4. 调用f。如果是dynamic,1处的bound根本就不会影响到f,只有最外层的let才会影响到
复制代码
输出是什么就是什么作用域。代码是按scheme写的,是lexical。

>> 1.局部变量及作用域
这是上面所的,包含自由变量但不会超出bound form被求值的情况吧?

>> 3.局部函数及upvalue
说了嘛,就类似C++的lambda。
或者理解为C里面的callback+context,context被整体复制,不需要显示处理。

>> 5.如何实现共享的upvalue语义
指针……  然后手工管理内存,或者gc……

>> 4.全局函数及不可改变的命名,还有对其他全局对象(变量+函数)的引用
依然是可改的,只是改了对已经产生的闭包不可见。

  1. (let ((+ __builtin_add__))
  2.   (let ((f (lambda () (+ 1 2)))) ; 此处的+始终是 __builtin_add__
  3.     (set! + *)                   ; 此处被改了
  4.     (list (f)                    ; 不会影响到f
  5.           (+ 1 2) )))            ; 但会影响到这里
  6. ; => (3 2)
  7. ; => (2 2) 如果是词法就应该输出这个
复制代码
>> 2.全局变量
>> 你知道的,lua的_ENV方案太优美了,优美到我觉得一个程序,根本就不应该是有所谓“全局变量”一说的,这方面你得说服我。

对,很多语言在顶层的东西与函数内的东西有区别。差不多就是与lua相同的想法。
不过那个全局表要在不需要的时候干掉,映射到data section。
同时也想干掉声明什么的……  还要是静态类型什么的……
嗯,还没想好……


这里并不是lisp独有的问题。
如果像lua那样带个全局表,而且是动态类型检测,就没难度了。
或者说lua想要将这些映射到data section也需要添加其他什么东西才能描述?

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
217 [报告]
发表于 2012-02-18 02:58 |只看该作者
回复 214# starwing83

上面那个例子重新写吧,全局就全局吧……

  1. (define x "capture by value: C++")
  2. (define f (lambda () x))
  3. (set! x "lexical: scheme")
  4. (let ((x "dynamic: emacs lisp"))
  5.   (f) )
复制代码
BTW:关于文件即函数。
lua如果想要将全局的变量映射到data section,有办法么?如果没有,是不是也像你说的,虚假的一致性?

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
218 [报告]
发表于 2012-02-18 03:11 |只看该作者
回复 215# starwing83

不会像你想象的那么多东西都是可变的。
即使"+"可变,cl不是有safety声明么(假设是它引起的)。

(car (lambda () 12))
各种lisp,以及编译或解释都会产生区别。 code要作为data,必须显示说明:
(car '(lambda () 12)) ; => lambda

(apply '(lambda () 12) '())
同样不同lisp,编译or解释都会产生区别。 data作为code也必须显示说明:
1. eval,你最不想看到的……
(apply (eval '(lambda () 12)) '())

2. macro,且输入输出都是编译时已知,这才是最通常的用法
(defmacro ID(x) (id x))
(apply (ID (lambda () 12)) '())
对ID来说,它处理的是(编译时已知)数据 '(lambda () 12)。

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
219 [报告]
发表于 2012-02-18 03:21 |只看该作者
回复 218# OwnWaterloo

我傻了,data的export/global与函数是一样的,问题依然只是静态类型lisp的语法问题……
假设依然是dynamic tpying:

  1. ; (lambda ()                            function()
  2.     (let ((x 12))                         local x = 12
  3.       (set! X x)                          X = x
  4.       (set! F (lambda (y) (+ x y))) )     F = function(y) return x + y end
  5. ; )                                     end

复制代码
如果将整个文件想象成匿名函数,那么只有X与F是它的自由变量,是其他module可见的,分别映射到data/code section。

论坛徽章:
5
狮子座
日期:2013-08-20 10:12:24午马
日期:2013-11-23 18:04:102015年辞旧岁徽章
日期:2015-03-03 16:54:152015亚冠之德黑兰石油
日期:2015-06-29 18:11:1115-16赛季CBA联赛之新疆
日期:2024-02-21 10:00:53
220 [报告]
发表于 2012-02-18 08:52 |只看该作者
本帖最后由 starwing83 于 2012-02-18 08:56 编辑

回复 217# OwnWaterloo


    我又数了半天的括号………………

看来你的静态作用域实际上是没办法解决函数名的问题的………………

我举个例子:

(let ((g (lambda () 1)))
  (if (= (rand) 0) (set! g (lambda () 2)))
  (let ((f (lambda () (g)))))
  (display (f)))


请问这里,到底是输出2还是输出1呢??只要允许函数被改变,即使是你的冻结作用域,最终的结果(f里面到底是哪个g)仍然不可预料,因为你的冻结是取决于“如果赋值,则产生新的名字”,问题是,如果连赋值与否都是运行时决定的呢?你如何决定是否产生新的名字???

顺便吐个槽,也许是我用lisp太少了,在浏览器里面修改lisp几乎是不可能的事情,特别是互换行,你换完了得花一分钟数一遍括号嵌套得对不对……

最后再提一个更严重的问题:假设你的程序支持goto,然后你goto到了赋值之前,这时你会发现你之后赋的值“突然”回来了!甚至不需要goto都可以:

(let ((i 1))
  (while (< i 10)
      (set! i (+1 i))
  )
)

这个程序将是一个死循环!因为即使是set! i了,但是因为while的循环条件在set之前,set永远会产生i的新拷贝,而while循环条件中的那个i一定是等于1的,永远小于10,于是就是个死循环。

即使你的意思是只有在定义函数的时候才去拷贝变量的值也还是会有第一个问题。而且在这种情况下,作用域还是词法作用域,满足词法作用域的任何特征。区别只是没有upvalue,所谓upvalue实际上是值拷贝罢了。换句话说,你的函数实际上是Python2式的嵌套函数(Python2根本就没有upvalue一说,你引用同样的名字会拷贝那个名字当前的值,然而你没法对那个名字赋值——任何赋值都会导致Python2认为那是个局部变量,所以Python3加了nonlocal关键字说明那是个upvalue——多么糟糕的设计啊,说不定是作者水平有限根本就实现不出来真正的upvalue所以最开始才那么实现的……由此也可以看出来local-default的失策了)

最后说一下我的测试:按照你的写法,Python2的确是词法作用域的:它没有拷贝变量,而C++的确是拷贝了变量的值,但是告诉你一个很不幸的结果:C++是如何避免我一开始就提到的问题呢?它禁止重新对lambda赋值………………

所以嘛…………

如果是这样,即使有了冻结作用域,你仍然不允许对+重新赋值的……


UPDATE:重新试验了一下,如果写auto foo = [] {....}的确是没法再重新赋值的,而且这时foo的类型被显示为lambda(),而如果写:std::function<void()> foo = []{...}的话居然可以重新赋值了,原因估计是,std::function里实际上是保存了lambda的一个指针,因此,其实C++的函数仍然是不允许重新赋值的,要重新赋值只能指针……
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP