“一个人(可以假设是你自己)被邪恶科学家施行了手术,他的脑被从身体上切了下来,放进一个盛有维持脑存活营养液的缸中。脑的神经末梢连接在计算机上,这台计算机按照程序向脑传送信息,以使他保持一切完全正常的幻觉。对于他来说,似乎人、物体、天空还都存在,自身的运动、身体感觉都可以输入。这个脑还可以被输入或截取记忆(截取掉大脑手术的记忆,然后输入他可能经历的各种环境、日常生活)。他甚至可以被输入代码,‘感觉’到他自己正在这里阅读一段有趣而荒唐的文字。那么问题来了——

“你如何担保你自己不是在这种困境之中?”

上边这个问题被称为 “缸中之脑”,是希拉里·普特南(Hilary Putnam)1981年在他的《理性,真理和历史》(Reason, Truth, and History)一书中阐述的假想。随着脑电波芯片、收集生物能发电等技术逐渐从科幻作品变成了现实,很难说有一天是否真的会出现,也许我们现在就像黑客帝国里的场景一样,泡在营养液里呢?

据说有一种对 “缸中之脑”的讨论方法是对能否形成 “缸中之脑”的条件进行分类,得出一个可信性概率。思路很有意思,但是没有看到论文原文,我也不知是否正确,不过这种跳出原问题的窠臼,站在另一个角度或更高的高度去解决解决的方法经常是有效的。

说到从无限循环里“跳出去”在python里还真是有点棘手,我们知道用“[x for x in range(1,10)]”形式可以获得[1, 2, 3, 4, 5, 6, 7, 8, 9],换句话说第一个x被运行了9次。这是一个可以确定循环次数的例子,但是如果循环次数不那么好确定,就费劲了。比如前面《map、reduce、lambda能做神马?》“将一个正整数转换成二进制数的字符串”的一种解法:reduce(lambda x,y:(str(x[1]%2)+x[0],x[1]>>1) if x[1]>0 else x, xrange(len(str(N))*3.321928095+2), ('',N))[0]

可以看到,为了估计出一个大概齐能用的次数是多么麻烦,而且还要忍受哪怕待处理的数是1也要浪费时间把整数每一位都运行一遍的麻烦。所以想到了这个:

>>> help(iter)
Help on built-in function iter in module __builtin__:

iter(...)
    iter(collection) -> iterator
    iter(callable, sentinel) -> iterator

    Get an iterator from an object.  In the first form, the argument must
    supply its own iterator, or be a sequence.
    In the second form, the callable is called until it returns the sentinel.
 

注意上边的第二种形式生成的迭代器,当callable的返回值等于sentinel的时候会终止迭代。于是用这种方式可以作出用参数控制循环次数的解法:

>>> f=lambda n:[x for x in iter(lambda:([lambda:n[0],lambda:'y'][(n.insert(0,(n.pop(0)+1)),n)[1][0]>n[1]]()),'y')]
>>> f([1,10])
[2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> f([1,5])
[2, 3, 4, 5]
>>>

通过调整iter的判断条件,很容易将循环改成while、until型循环,另外如果担心callable的返回值可能因为转义或其他原因“碰巧”与sentinel相同导致逻辑错误,可以用id函数获取某一对象的地址作为判断条件。