免费注册 查看新帖 |

Chinaunix

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

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

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

我发现问题了,这不睡梦中爬起来回帖了么…… 结果没赶上,你已经醒了……

先说数括号的问题……
前面217楼那个,没有影响全局的代码,我是在编辑器里面敲的,没觉得有什么不妥。发上来后脱离编译器看了看就发现不妥了。
所以218楼就不管全局影响什么了……
如果愿意,总是可以像html那样自己加 begn-tag, end-tag,只是lisp不强迫,编辑器里也很容易匹配就给忘了plain text是啥效果……

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

先说让我爬起来回帖的原因……
问题出在:

  1. (let ((x 12))
  2.   ( (lambda () (set! x 26)) ) ; 匿名函数调用
  3.   x )
复制代码
如果是词法作用域,3个x是同一个,最终结果是26。
如果像C++那样,其实是lambda内复制了一份,然后改变这份copy,不能影响外层的值。最终结果是12。

尤其是当外层没有绑定时……

  1. ( (lambda () (set! x 26) )
复制代码
会怎样?


回到你前面那个:如何共享的问题。
C++,capture by value,无法共享:

  1. int i = 12;
  2. for_each(beg, end, [](int x)->void { cout<<x+i; } );
复制代码
但可以通过指针:

  1. int sum = 0;
  2. reference_wrapper<int> sum_ = sum;
  3. for_each(beg, end, [](int x)->void { sum_+=x } );
复制代码
或者是gc,这就与lua里的行为很像了:

  1. int sum = 0;
  2. gc<int> sum_ = sum; // boxing
  3. for_each(beg, end, [](int)->void { sum_+=x; } );
  4. // sum = sum_;
复制代码
但应用于全局的问题就是,得先有一个东西才能reference_wrapper……
217楼提到的想干掉的声明就是指这个。



C++的lambda除了capture by val还可以capture by ref。
就与上面的reference_wrapper一样了,显式地创建一个,但要自己保证生命期不会超出。

  1. int sum = 0;
  2. for_each(beg, end, [&](int x)->void { sum+=x } );
复制代码
by ref可以通过by val表达,但对顶层就行不通……


是仅对顶层开漏洞,不需要显式地使用reference_wrapper:

  1. ; (lambda ()
  2.     (let ((x 12))
  3.       (define X x)
  4.       (define F (lambda (y) (+ x y))))
  5. ; )
复制代码
还是(这其实就不止一种作用域了):

  1. ; (lambda ()
  2.     (capture-by-ref (F X)
  3.       (let ((x 12))
  4.         (set! X x)
  5.         (set! F (lambda (y) (+ x y)))))
  6. ; )
复制代码
还是其他方案?



而且我一直都在被你提到的那个lua代码困扰:
local x,y,z = ... --> 写arg应该也可以吧?
要怎样才能让代码描述出模块入口点是个3元函数呢……
又要声明吗?

论坛徽章:
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
223 [报告]
发表于 2012-02-18 10:25 |只看该作者
回复 218# OwnWaterloo


    没有办法。不过lua的目标根本跟生成C代码一点关系都没有。所以不是虚假的一致性。我一直在强调,lisp和C本质的不同,翻译成C会导致很多问题。看到了吧……safety……以后还会有更多这种东西么……那还不如用C呢

论坛徽章:
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
224 [报告]
发表于 2012-02-18 10:35 |只看该作者
OwnWaterloo 发表于 2012-02-18 10:13
回复 221# starwing83

而且我一直都在被你提到的那个lua代码困扰:
local x,y,z = ... --> 写arg应该也可以吧?
要怎样才能让代码描述出模块入口点是个3元函数呢……
又要声明吗?


我不明白你的意思,如果你说的是lua,lua没声明。另外这里不能写arg,arg映射的是argc和argv,...映射的是实际传给文件的参数,这两者在某些情况(比如require、dofile等等)下是不一样的:

file.lua
print(select('#', ...), ...)
local function parse(...)
   printf("arg: ", select('#', ...), ...)
end
parse(unpack(arg))


$ lua file.lua 1 2 3
3 1 2 3
arg: 3 1 2 3

main.lua:
local f = loadfile "file.lua"
f('a', 'b', 'c')

$ lua main.lua 1 2 3
3 a b c
arg: 3 1 2 3


如果你说的是import/export问题。首先你知道新语言肯定是必须支持vararg函数的,而显然文件函数(指文件本身这个函数)肯定是个vararg函数。这种函数显然不需要声明……还有啥?

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

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

你那个例子来说,如果(rand)产生的是0,输出就是2,否则输出就是1。
(lambda () 1) 与 (lambda () 2) 是两个被编译好的函数。
g首先指向1,如果(rand)产生0, g指向2。
然后f将g的值复制,可能指向1,也可能指向2。

如果换成顶层也是一样。
(define g (lambda () 1)) ; g指向一个始终返回1的函数
(define f1 (lambda () (g))) ; f1指向另一个始终返回1的函数

(set! g (lambda () 2)) ; g指向一个始终返回2的函数
(define f2 (lambda () (g))) ; f2指向另一个始终返回2的函数

(set! f1 (lambda () (g))) ; 如果调用,返回2

(if (= (rand) 0) (set! g (lambda () 3))) ;
(set! f3 (lambda () (g))) ; 始终返回2或者3,视(rand)而定


>> 请问这里,到底是输出2还是输出1呢??只要允许函数被改变,即使是你的冻结作用域,最终的结果(f里面到底是哪个g)仍然不可预料

结果不能预料是因为(rand),但可以预料的是:
1. 要么被复制进的是(lambda () 1),要么是(lambda () 2)
2. 不妨设是(lambda () 1),那之后f的结果就始终是1,不会受到g的变化而变化

  1. (let ((g (lambda () 1)))
  2.   (if (= (rand) 0) (set! g (lambda () 2)))
  3.   (let ((f (lambda () (g)))))
  4.     (set! g (lambda () 3)) ; 我增加了一行,但输出要么是1,要么是2,不会是3
  5.     (display (f)))
复制代码
>> 因为你的冻结是取决于“如果赋值,则产生新的名字”,问题是,如果连赋值与否都是运行时决定的呢?你如何决定是否产生新的名字???

不是赋值就产生新的名字,那是218楼我自己搞错了。
没法解决顶层函数名的问题,除非声明/增加词法作用域……


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

敢复制到编辑器里吗……
或者,你下面的代码不就很聪明吗……  使用与lua相同的行数与缩进,不就清晰了


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

  1. (let ((i 1))
  2.   (while (< i 10)
  3.       (set! i (+1 i))
  4.   )
  5. )
复制代码
可以说(set! i (+ 1 i))有自由变量,但只要往上能找到一个binding form,此处是let;而且该表达式不会超出其binding form求值,根本就不存在capture, closure什么的东西……
此处几个i都是同一个i,无论是dynamic/lexical还是capture by value,根本就么有被capture嘛……


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

python可以
reference_wrapper = [x] # 或者更好的名字是container什么的,这里只是为了对应上面的C++代码
reference_wrapper[0] = reference_wrapper[0] + 1

local-default不是失策,是local implicit,nonlocal explicit与local explicit,nonlocal implicit的区别。
只是python里nonlocal加晚了或者说作者太笨去加了个什么global……
这已经说过很多次了…… 你个lua厨可以不要每次都忘了好吗……


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

嗯,python是词法作用域的,是因为语法限制所以没法共享……


>> 如果是这样,即使有了冻结作用域,你仍然不允许对+重新赋值的……
>> UPDATE:重新试验了一下,如果写auto foo = [] {....}的确是没法再重新赋值的,而且这时foo的类型被显示为lambda(),而如果写:std::function<void()> foo = []{...}的话居然可以重新赋值了,原因估计是,std::function里实际上是保存了lambda的一个指针,因此,其实C++的函数仍然是不允许重新赋值的,要重新赋值只能指针……

在C/C++里几时用"函数类型"进行调用过……
你再考虑下,我困死了,睡一会……

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

>>     没有办法。不过lua的目标根本跟生成C代码一点关系都没有。所以不是虚假的一致性。我一直在强调,lisp和C本质的不同,翻译成C会导致很多问题。看到了吧……safety……以后还会有更多这种东西么……那还不如用C呢

这个我们也说过至少两次了好吗?

lua对一般的函数调用同样存在间接性。f里对g的调用会被后续g的改变所影响。
如果要消除这种间接性,lua同样要想其他办法。

lisp在此处的问题仅仅是它连加法都是普通函数。
这是一致性之一,但不如像处理数据那样(在编译时)处理程序的一致性重要。
如果你觉得这里不放心,将加法弄成内建的operator可以么? 至少此处在一致性上降低到了与lua同一水平。

另外,lua里面想要消除间接性又该怎么办呢?就只满足于能将 1 + 2 优化么?
一致性就是说,只要能想出办法解决间接性,就可以解决+,也可以解决函数,而不需要引入更多的内建operator。

论坛徽章:
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
227 [报告]
发表于 2012-02-18 11:12 |只看该作者
回复 226# OwnWaterloo


    你看看你的说法:指向……

难不成你需要**所有**的函数名其实都是函数指针?难道每次你都得弄个额外的指针才行?

int (*g)();
int real_g() {...}

这样?

我的重点就是你所谓的函数重命名好吗?对于静态语言,有多少个变量是编译时必须决定的,函数类型就是函数类型,是没法去赋值的,那是动态语言语义好吗?

PS:那些我没忘啊,你难道没看出来重点么?重点是share啊!!!python需要boxing不就是意味着没有share啊,没有share还能叫upvalue么????

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

>> 另外这里不能写arg,arg映射的是argc和argv,...映射的是实际传给文件的参数,这两者在某些情况(比如require、dofile等等)下是不一样的:
那lua51怎么办? 这只能在lua52里用么难道?
是哪个版本加入的...来着?

>> 如果你说的是import/export问题。首先你知道新语言肯定是必须支持vararg函数的,而显然文件函数(指文件本身这个函数)肯定是个vararg函数。这种函数显然不需要声明……还有啥?

lua不需要考虑它的类型啊……
也有完善的运行时类型检测与错误检测(假设参数传少了算是错误的话)……

vararg类型信息,参数个数神马都没有……
如果是format那样什么的,还不如附带一个any以及相关的runtime……

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

>> PS:那些我没忘啊,你难道没看出来重点么?重点是share啊!!!python需要boxing不就是意味着没有share啊,没有share还能叫upvalue么????

python一直都是shared:
f = lambda: x
f() # error
x = 12
f() # 12

只是语法限制使得内层不能用=来改,因为这是let/set一体。 但它有nonlocal好吗?

只是let是否需要写local(lua)还是什么都不写(python),free variable是否需要写nonlocal(python)还是什么都不写(lua)的问题。
并不是一种优于另一种,所以local-default并不是失策。
失策的只是python。

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

>> 你看看你的说法:指向……

你真以为在C/C++里用过函数调用么……  你只用过函数指针调用好吗……

>> 难不成你需要**所有**的函数名其实都是函数指针?难道每次你都得弄个额外的指针才行?

先无论加法是否可以改,普通一点的函数能改否?

local log = function(...) ... end
local f = function(...) ... log("f\n") end

log = function(...) --empty
end

或者像你说的,替换标准库里的error函数。


如果想要替换,每一个调用点,或者被调用者的入口处,就需要有一层间接性。这有办法消除?
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP