Emacs开发VC程序 zz

[http://emacser.com/dev-vc.htm]Emacs开发VC程序
背景
前些日子,微软宣布Visual studio 2010的EMACS扩展。此前,Visual studio 2005
6.01已然引入了Emacs的键盘模拟,这次又将Visual studio
的Emacs化更进一步,这种事发生在Microsoft这样无利不起早的企业,原因呢,你懂得。
话说,武功再高,也怕菜刀。Emacs玩的再溜,也保不齐哪天你要去开发Visual studio
程序。习惯了Emacs的高效,使用Visual studio
就是一个杯具1。这种情况,一般一颗红心,两手准备。一颗红心:cosplay,两手准备:1.Visual studio 扮Emacs
2Emacs扮Visual studio 。VC扮EMACS非官方扩展式visEMACS
官方的Emacs扩展2
不过,我对这种方式的经验总结:享受不到Emacs的周到体贴,却净受VS的大小姐脾气了。不给力啊,不给力。不过,作为出差旅行,远程登陆,客户服务时,没有Emacs可用时,让Visual
studio 模拟一把Emacs,也不失为一种没有办法的好办法了。这个方法不是本文的重点,所以不深入。EMACS扮VC配置EMACS为IDE
一个基本的IDE,必备功能:编辑,编译,调试。编辑应该很多人都很眼红Visual studio的销魂的插件visual assist
x吧。实时语法检查,快速打开文件,h,cpp文件,回到刚才编辑的地方,函数跳转,自动补全,插入模板。可以号称操作系统的Emacs怎么可能没有这些功能呢?尽管这些不在本文范围,但是稍稍提及功能在Emacs中的对应,有兴趣想深入的请Google,
Duckduckgo, Wikipedia.VXA功能 EMACS对应功能
实时语法检查 Flymake 3
快速打开文件 ECB, 快速打开文件
h,cpp跳转 CEDET 4
回到刚才编辑的地方 Recent-jump5
函数跳转 CEDET 4
自动补全 Auto-complete 6
插入模板 Yasnippet 7
快速打开文件
至于快速打开文件一项,我感觉ECB做的并不是特别好,如果C++程序的头文件和实现文件没有在一个文件夹,很难找到。所以我用了一个比较笨的方法,生成文件的列表到一个文件,使用Emacs的查找功能和打开当前光标下文件的功能
find-file-at-point,我把它编定到了C-c
C-f。这个过程还有两个副产物供cscope和etags用。确认你的机器上有cscope, find,
etags8,将以下代码成为uptags.bat,放到系统的pathz中的某个文件夹下。
%1
cd %2
rm TAGS
rm cscope.files
rm filelist.txt
rm cscope.in.out
rm cscope.out
rm cscope.po.out
if "%3" EQU "java" set PARAM=-name "*.java" -print
if "%3" EQU "c++" set PARAM=-name "*.cpp" -print -o -name "*.r" -print
-o -name "*.[hcrHs]" -print -o -name "*.hpp" -print -o -name "*.lua"
-print
echo %PARAM%
find . %PARAM% > cscope.files
less cscope.files | xargs etags -aR
cscope -bkq -i cscope.files
cp cscope.files filelist.txt
find . -name "*.txt" -print >> filelist.txt
假设我们的C++工程在d:mydocumentsworkspacecpp,那么调用方法9为:uptags d: d:mydocumentsworkspacecpp c++
java工程在d:mydocumentsworkspacejava, 那么调用方法为:uptags d: d:mydocumentsworkspacejava java
那么打开文件helloworld.cpp的操作就是:C-x b filelist.txt , C-s helloworld.cpp, C-c
C-f, RET。确实,稍显复杂,期待有更好的方法。编译编译的话基本上还是要靠Visual studio 自带的工具:nmake10,msdev。本文主要介绍msdev。使用msdev.exe
msdev.exe位于安装路径下的bin目录,如我本机使用Visual studio 6.0,目录为"C:Program
FilesMicrosoft Visual StudioVC98bin"。 直接调用msdev.exe,即启动Visual
studio的UI界面,同时msdev.exe也接受命令行调用。我们看其帮助。
msdev /?
Usage:
MSDEV [myprj.dsp|mywksp.dsw] - load project/workspace
[<filename>] - load source file
/? - display usage information
/EX <macroname> - execute a VBScript macro
/OUT <filename> - redirect command line output to a file
/USEENV - ignore tools.options.directories settings
/MAKE [<target>] [...] - build specified target(s)
[<project> - <platform> <configname>]
[[<project>|ALL] - [DEBUG|RELEASE|ALL]]
/CLEAN - delete intermediate files but don't build
/REBUILD - clean and build
/NORECURSE - don't build dependent projects
假设我们有这么一个工程,路径为d:Mydocumentsworkbench,工程目录结构,Configuration如下图
可以通过命令msdev.exe来编译工程test211。
C:Program FilesMicrosoft Visual StudioVC98binmsdev.exe test2.dsw
/Make "test2 - Win32 Debug" /NORECURSE
同样,使用clean,rebuild可以清除、重编译该工程。将test2 改为test21,test23,即改变编译对象。
总这样写也很麻烦,而且为了在Emacs中调用 ,我们将其写成一个批处理。d:
cd d:Mydocumentsworkbench
set project=%1
set target=%2
if "%1" == "" set project=test2
if "%2" == "no" set target=/NORECURSE
msdev test2.dsw /Make "%project% - Win32 Debug" %target%
保存为makTest2.bat。调用方式为:makeTest2 [工程 [目标]]
默认为编译test2 的 /NORECURSE。如果要编译test23的rebuild,调用方式为:makeTest2 test23 /REBUILD
调试实际上,如果有了编辑,编译,那么调试就不需要了。因为调试器是一切罪恶他妈12。哈哈,当然是开玩笑的了。作为一个有思想的程序员,要认清楚,编译器,调试器都只是恶魔,程序员本身,也就是我们,才是恶魔他妈(当然大部分是他爹^_^ )。哈哈,那么作为恶魔的产生者,我们当然要丰富自己的技能,而调试就是一个必杀技。我杀,bug闪……..cdb-gud
要用Emacs调试Visual studio 的程序,首先需要一个el – cdb-gud.el
。cdb-gud使用Microsoft的命令行调试器cdb来调试程序。
cdb-gud.el只需下载,然后在.emacs中使用下面语句,cdb-gud就随时待命了。
;;+cdb [[http://msdn.microsoft.com/en-us/vstudio/default.aspx][Visual studio ]]
(when (eq system-type 'windows-nt)
(load-file "~/.emacs.d/lisp/cdb-gud.el")
)
调用cdb-gud: M-x cdb RET。Microsoft命令行调试器cdb.exe
如果你是一个Windows程序员,Windbg听说过吗?如果没有听说过,我建议你去看看《软件调试》,这本书讲的非常的透彻。
注意,这是一本厚度为1000页的砖头书。如果你没有耐心去读这么厚的书,那么还有一个选择,《Windows用户态程序高效排错》,
内容236页,内容写的不多,但是书内提供的资源。
两本书排名不分先后。那么cdb就在Windbg的安装目录下。Windbg是Windows下的能用户态调试核心态调试的强大的图形界面的调试器。那么,简而言之,尽管不太准确13,cdb就是非图形界面的调试用户态程序的windbg。
简要介绍一下cdb:cdb就是一个命令行的调试器,over。深入探讨一学cdb: 我想很深入的探讨一下cdb,但是实在是没有如此深厚的内功,但是我可以推荐一些内容供有兴趣的去深入。WINDBG安装目录内的debugger.chm
windbg info
MSDN的帮助
强烈推荐将windbg info 打印出来在手边供不时查阅之需。现在,来启动cdb-gud吧:M-x cdb RETShowtime14!例子
建立一个Visual studio 的console典型的Hello world工程(比如刚才的test2),源代码如下15:
#include "stdafx.h"
#include <string.h>
void assign (int a[], int n)
{
for (int i = 0; i < n; ++i)
{
if (a[i] == 0)
{
a[i] = i;
}
}
}int main(int argc, char* argv[])
{ int a[100];
assign(a, 100);
for (int i = 0; i < 100; ++i)
{
printf("%dt", a[i]);
} return 0;
}
通过上边程序,我们期待打出所有0-99的数,每个数是间隔一个制表符,每十个数打出一个换行。我们编译运行代码,得到结果:-858993460 -858993460 -858993460 -858993460 -858993460 -858993460
-858993460 -858993460 -858993460 -858993460
-858993460 -858993460 -858993460 -858993460 -858993460 -858993460
-858993460 -858993460 -858993460 -858993460
-858993460 -858993460 -858993460 -858993460 -858993460 -858993460
-858993460 -858993460 -858993460 -858993460
-858993460 -858993460 -858993460 -858993460 -858993460 -858993460
-858993460 -858993460 -858993460 -858993460
-858993460 -858993460 -858993460 -858993460 -858993460 -858993460
-858993460 -858993460 -858993460 -858993460
-858993460 -858993460 -858993460 -858993460 -858993460 -858993460
-858993460 -858993460 -858993460 -858993460
-858993460 -858993460 -858993460 -858993460 -858993460 -858993460
-858993460 -858993460 -858993460 -858993460
-858993460 -858993460 -858993460 -858993460 -858993460 -858993460
-858993460 -858993460 -858993460 -858993460
-858993460 -858993460 -858993460 -858993460 -858993460 -858993460
-858993460 -858993460 -858993460 -858993460
-858993460 -858993460 -858993460 -858993460 -858993460 -858993460
-858993460 -858993460 -858993460 -858993460
有点奇怪,为什么没有得到我们需要的东西呢??从代码中貌似看不到直接的证据证明我们的代码逻辑的错误。我们就祭出cdb。M-x cdb RETminibuffer: cdb d:Mydocumentsworkbenchtest2debugtest2.exe 会有以下界面提示。Microsoft (R) Windows Debugger Version 6.11.0001.404 X86
Copyright (c) Microsoft Corporation. All rights reserved.CommandLine: d:/Mydocuments/workbench/tmp/VCTest/test2/test/Debug/test.exe
Symbol search path is:
C:symbolsXpSp3;d:/Mydocuments/workbench/via/helios/coyote/Bin/MULTIMEDIA_PRO_240x320_Debug
Executable search path is:
*** WARNING: Unable to verify checksum for test.exe
ModLoad: 00400000 0042c000 test.exe
ModLoad: 7c900000 7c9b2000 ntdll.dll
ModLoad: 7c800000 7c8f6000 C:WINDOWSsystem32kernel32.dll
(a90.1eb8): Break instruction exception - code 80000003 (first chance)
eax=00241eb4 ebx=7ffd9000 ecx=00000000 edx=00000001 esi=00241f48 edi=00241eb4
eip=7c90120e esp=0012fb20 ebp=0012fc94 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
ntdll!DbgBreakPoint:
7c90120e cc int 3
0:000> cdb: Reading initial command 'l+*;l-s'
Source options are ffffffff:
1/t - Step/trace by source line
2/l - List source line at prompt
4/s - List source code at prompt
8/o - Only show source code at prompt
Source options are fffffffb:
1/t - Step/trace by source line
2/l - List source line at prompt
8/o - Only show source code at prompt
0:000>
0:000> bp main
bp 表示打断点,断点的方式有几种:函数名,文件行数,内存地址。但是我最喜欢的还是:当调试过程已经在运行,*在Emacs中打开文件,走到需要打断点的行,C-x space*,断点就打到该行,很给力啊。0:000> g
Breakpoint 0 hit
test!main:
0040d880 55 push ebp
0:000> p
test!main+0x1e:
0040d89e 6a64 push 64h
0:000> t
test!ILT+15(?assignYAXQAHHZ):
00401014 e907c80000 jmp test!assign (0040d820)
0:000> p
test!assign:
0040d820 55 push ebp
0:000> p
test!assign+0x18:
0040d838 c745fc00000000 mov dword ptr [ebp-4],0 ss:0023:0012fd8c=cccccccc
g==go,所以表示开始运行程序。p 单步跟踪,不进入子函数。t 单步跟踪,但是进入子函数。不出意外,当你使用p或者t跟踪程序的时候,源代码窗口已经打开,同时随着跟踪,相应的代码行也会高亮。0:000> dv
a = 0x0012fdf0
n = 100
i = -858993460
0:000> p
test!assign+0x32:
0040d852 8b55fc mov edx,dword ptr [ebp-4] ss:0023:0012fd8c=00000000
0:000> dv
a = 0x0012fdf0
n = 100
i = 0
0:000> dt a[0]
Local var @ 0x12fd98 Type a[ 100]
[0] 0x0012fdf0
-> -858993460
0:000> dt a[1]
Local var @ 0x12fd98 Type a[0]
[1] 0x0012fdf0
-> -858993460
0:000> dt a[i]
Local var @ 0x12fd98 Type a[1]
[0] 0x0012fdf0
-> -858993460
dv:显示当前的局部变量。dt: 显示指定的变量。当前发现为什么a数组的值怎么是负数,不是期待的0呢?0:000> k
ChildEBP RetAddr
0012fd90 0040d8ac test!assign+0x32
[D:MydocumentsworkbenchtmpVCTesttest2testtest.cpp @ 10]
0012ff80 00401209 test!main+0x2c
[D:MydocumentsworkbenchtmpVCTesttest2testtest.cpp @ 21]
0012ffc0 7c817077 test!mainCRTStartup+0xe9 [crt0.c @ 206]
WARNING: Stack unwind information not available. Following frames may be wrong.
0012fff0 00000000 kernel32!RegisterWaitForInputIdle+0x49
0:000> .frame 1
01 0012ff80 00401209 test!main+0x2c
[D:MydocumentsworkbenchtmpVCTesttest2testtest.cpp @ 21]
0:000> dv
argc = 1
i = -858993460
Type information missing error for a
0:000>
k:打印出当前的栈内容.frame:跳转到栈中的第几帧,当前为第0帧。在.frame 1后,我们注意到以下代码:int a[100];
assign(a, 100);
貌似a[ 100]没有初始化吧。0:000> q
然后修改代码后#include "stdafx.h"
#include <string.h>
void assign (int a[], int n)
{
for (int i = 0; i < n; ++i)
{
if (a[i] == 0)
{
a[i] = i;
}
}
}int main(int argc, char* argv[])
{ int a[100]={0};
assign(a, 100);
for (int i = 0; i < 100; ++i)
{
if (0 == (i % 10))
{
printf("n");
}
printf("%dt", a[i]);
} return 0;
}
编译运行,结果:testdebugtest.exe0 1 2 3 4 5 6 7 8 9
10 11 12 13 14 15 16 17 18 19
20 21 22 23 24 25 26 27 28 29
30 31 32 33 34 35 36 37 38 39
40 41 42 43 44 45 46 47 48 49
50 51 52 53 54 55 56 57 58 59
60 61 62 63 64 65 66 67 68 69
70 71 72 73 74 75 76 77 78 79
80 81 82 83 84 85 86 87 88 89
90 91 92 93 94 95 96 97 98 99
那么cdb简单使用就介绍完了。然而,其实很多cdb的强大功能都没有介绍到:可以调试程序崩溃时留下的内存转储文件dump,调出其堆栈休息。
可以附挂到一个正在运行的程序。
远程调试
显示,执行代码
处理断点(支持复杂的条件断点)
读写内存地址
反汇编
多线程调试
Windows符号文件
对于一般的console程序,可能这样就够了。但是在调试广大的Windows程序时,哪能不接触Windows的API啊,调试这些个玩意儿,才是让人头痛的东西呢,没有源代码!!cdb的一个机制可以让你没有源代码的情况下看到很多Windows的公开数据结构。
首先,先查看自己的系统的版本,在我的电脑->右键->属性,我可以看到我的系统是Microsoft Windos XP
Professional Service Pace 3, 那么我就来这里下载Windows的相应的符号文件。将其安装到本机,比如:C:symbolsXpSp3。添加环境变量:_NT_ALT_SYMBOL_PATH,设其值为安装目录。经此设置,cdb在调试时就可以看到Windows API的符号文件。更多内容,还请参考帮助文档或者我推荐的两本书。Footnotes:
1 @木鱼指出 6.0中的Epsilon即为emacs模式。 可查到资料中最早的是2005, 来源猛击我。 但是有可能更早,如果有资料,麻烦请留言告之.2 此处没有贬低Visual studio 的意思,只是我中Emacs的毒已太深,用其它什么都不爽:)3 下载链接Visual studio Emacs emulation addon4 flymake配置见http://marcelotoledo.com/2007/07/11/emacs-flymake/5 CEDET配置见http://emacser.com/c-cedet.htm6 recent-jump 配置见http://liuminzhao.com/emacs/recent-jump-el-for-emacs/7 auto-complete 配置见http://emacser.com/auto-complete.htm8 yasnippet主页http://code.google.com/p/yasnippet/9 cygwin, mingw, msys, unixutils10 好吧,我承认这个调用方法很蛋疼,如果你的工程比较少的话,其实可以将路径,程序类型什么的写到文件里,多整几个文件即可。upCppProject1Tags.bat,
upCppProject2Tags.bat,upJavaPro1Tags.bat,upJavaPro2Tags.bat。11 此文 介绍了如何使用nmake,但是恕我直言,我在Visual studio 的安装目录里没有找到nmake。12 如果不成功,请注意检查大小写和空格。13 调试器,恶魔之母 http://stackoverflow.com/questions/602138/is-a-debugger-the-mother-of-all-evil14 其实,用户态的windbg是图形界面的cdb。15 谨以此名纪念我经历的一个软件项目:Showtime 0.7。16 请注意,这是实验代码,所以请忽略魔幻数,程序是否有意义等话题。15 请注意,这是实验代码,所以请忽略魔幻数,程序是否有意义等话题。

方舟子继续遭受网络暴民袭击 zz

方舟子继续遭受网络暴民袭击 zz http://www.tianya.cn/publicforum/content/no01/1/422937.shtml
方舟子先生躲过锤击之后,近日继续遭受网络暴民的围剿。谁是暴民呢?我在这里不是指某个"坏人",最坏的人可能也有偶尔和善的时候。我是说,你的某种情绪可能促使你在某个时候做出了一件非常错误的事。我下面要把暴民分成几种,我相信是他们内心的某种倾向性使他们失去了公正,我要对他们内心的倾向性予以猜测,并做适当的分类。符合这些猜测的网友,请您反思一下,你是否不自觉地受到了这些倾向性的影响,而在最近对方舟子先生做出了一些不那么理性也并非基于事实的指责。思想在某些方面具有某种倾向性,这不是过错,相反,那很可能是自然的。但批评性言论本身有个公正性的问题。如果你批评某个人,这个人在某些方面具有与你不同的倾向性,你可以通过事先表明自己的这种倾向性来显得文质彬彬,这可能有助于你避免做出不公正的判断。我们中国人有句话,叫做"攻其恶,无攻人之恶",意思是说:因为这样做是错的,所以我才反对,而不是因为这是我所不喜欢的某个人做的,所以我才反对。这是我们的祖先为我们指出的君子之道。当然,无论你的内心有何种倾向,言论就是言论,只要你的指责基于事实,你的推理可以被接受,你的评判准则被大家所认可,那么,你的批评性意见肯定会被很多人尊重。相反,如果您对于什么是事实并不是很清楚,您对此也并不感兴趣,但您仍然要出言诋毁方舟子这个人,我认为,您需要看一看自己是否受到了内心如下一些倾向性的影响。我认为,无须承担责任的、受到群体行为暗示的、情绪化的、缺乏事实依据的、不公正的指责,是一种错误的行为,这些行为看起来像一群暴民所为。本文所针对的读者,完全排除那些为了经济利益而愿意发表任何言论的人,当然也不包括任何通过造假谋取利益的人。适合与他们谈论是非善恶的,应该是他们的妈妈,而不是其他人。以下是我归纳的思想倾向:倾向一:神创论者、设计论者,他们反对人类自己创造新的生命形式。这些人以前的说法是,世界是在七天之内被一个人格神所创造的,信这个神,可以得到拯救,不信这个神的异教徒,都会在末日审判中被区别对待。现在,这些人显得比较科学,毕竟科学太强大,他们现在只说这个世界是被创造或者被设计的,而做这件事的主体则被省略。最有趣的,他们说他们的理论应该与进化论一样,在(公立)学校中教授。虽然他们已经不怎么公开谈论创世的主体,但是,他们仍然认为,只有这个主体,才有创造生命的资格,任何改变基因、控制胚胎发育的行为,都是人类对这个创世主体的权力的僭越,这是由人类自己在创造新的生命形式,因此是不可接受的。他们显然是对未知的世界比较悲观、比较恐惧的一部分人。因为方舟子先生被某些人塑造成了转基因食品的著名支持者,因此,这些神创论者或者设计论者,或者秉承某种原教旨主义的教徒,也就把他当成了著名的敌人。当然,方舟子先生可能确实也不喜欢某种西方的一神教。对于有此种思想倾向的网友,我认为您先亮出自己的宗教信仰,然后再参与讨论,更容易避免不公。至于说对于转基因食品的立法,这是一个政治问题,我希望大家能够和平地予以讨论。我个人认为,按照是否支持对转基因食品施加某种法律限制,包括必须在包装上予以标注,这并不足于区分好人和坏人,大家不必因此而敌对。我们完全可以心平气和地讨论转基因食品的意义及其风险。即使你认为这挑战了你的教义,你可能仍然需要尊重他人的观点。我个人还没有看到转基因食品可能对人类构成伤害的证据,这可能需要长期的实验。因此,我认为,在是否立法对转基因食品予以必要限制这个议题上,只能反映大家对未来的感受,这不大可能是一种理性的选择,这只能反应一个人更悲观或者更乐观的性格特点,这种观点上的差别不是一个严重的问题。至于有人说方舟子先生是转基因食品生产商的顾问,因此,他的结论可能是带有倾向性的,说这种话的人,您需要给出证据。
倾向二:相信某种超自然力量或者玄秘理论,但无法容忍别人说这"不科学"或"不够科学"的人。汉语经常对"科学"一词有些古怪的用法,这些古怪用法的一个严重结果是,"科学"一词经常让人联想到"正确",而"不科学"则意味着"错误"、"落后",甚至"迷信"。某些愿意相信某种超自然力量或者玄秘理论的人,他们当然不愿意被人说成是"错误"、"落后"或者"迷信"的。因此,如果他们觉得方舟子先生是保卫"科学"、声讨"不科学"的一位"斗士",那么,方舟子先生也就成了他们的一个重要敌人。其实,从较为狭义的角度说,科学只是一些得到知识、组织知识的系统性方法,这种方法最显著的特点是基于数学推理或者可控制、可重复的实验。一种理论被称为科学的,通常是这种理论的陈述符合科学家共同体对于什么是"科学方法"的认识,而一种理论被认为不那么"科学",这通常意味着这种理论的陈述很难满足科学家共同体对于"科学方法"的认识。举个例子,你可能觉得,"某人一发功,就治好了眼前这个人的病",这是很科学的。但科学家可能并不这么认为,他们需要知道,经过怎样一个可操作的、可重复的程序,就能以一定的概率治好某个病人,如果他们没法从"一发功"这个特殊现象研究出某种可操作、可重复、可检验的程序,他们就会认为自己一无所获,他们就没法承认"一发功就能治病"是个"科学"的理论。当然,这并不意味着他们打算否定什么,科学家们不知道的事情,肯定比他们知道的事情来得多。我相信,无论您相信什么样的超自然力量或者玄秘理论,只要您不坚持要科学家共同体承认您的理论是"科学"的,您就不大可能与他们发生冲突。当然,据说也有人用魔术冒充"神功",这是另一回事,这可能涉及到法律问题,比如诈骗。如果这并不是魔术表演,而是一种牟利行为,甚至可能伤害他人的健康,这种行为值得戳穿。
倾向三:民科,但不希望别人指出这一点。其实我也是民科。很多民科不知道的是,"教科书"与"学术界"是两码事,如果你念过大学本科,你肯定对教科书里的内容不陌生,但那通常不是"研究",而只是"结论"。打个比方,你可能读到过一本叫做《历史》的书,但《历史》不是"历史学",一个"历史学"的学者,他要发表"学术"著作,不能只写下几条结论、给出几个故事,他必须而且主要需要阐明的,是他所得到的结论的意义,以及得到这些结论的过程是否"科学"。因此,如果你只读过一本叫做《历史》的书,你很可能不知道什么是"历史学",你仿照这本书写下的东西,是不大可能被历史学家们所接受的。类似地,你读过几本叫做《数学》的书,也不意味着你了解什么是数学研究,因此,你对于哥德巴赫猜想的见解,数学家们可能只想把它扔进垃圾篓。事实上,学者们确实生活于一个似乎隐秘的世界里,没有一本教科书能真正让你了解什么是"研究",你只能在很多年的时间里,通过阅读其他研究者的论文来逐渐"摸索"什么是"研究的方法",更重要的,尝试找到合适的研究问题,普通大众并不知道这个世界到底是什么样子,就如同很多人没有去过饭店的厨房,他们能看到的,只是厨师做好的菜。我本人并不觉得方舟子先生以取笑民科为乐,虽然这样的人可能很多,当然,也许有些人不这样认为,他们觉得自己的自尊心受到了伤害。我觉得,民科们完全可以自得其乐,没必要去烦扰学术界。一个更自由、更有责任感的学术界,也应该关注与其他社会成员的交流,让他们尽可能多地了解学者们正在做什么。他们正在做什么?:-)
倾向四:自惭形秽的文科生,他们内心里认为"人文"并不是如同自然科学一样的"科学",没有那样显赫的地位,因此,谁在那大声谈论"科学",谁就是伤害了他们的感情。可能普通大众不知道,写小说,不是"科学","研究"别人写的小说,才是"科学"。莎士比亚和曹雪芹都不是科学家,"研究"莎士比亚和曹雪芹的人才是各大学文学系的"科学家",而他们得到研究成果的过程,必须是满足科学家共同体对于"科学方法"的认识。因此,一个人成为某个大学文学系的教授,领到一份工资,这是因为他在"研究"和教学,至于他自己写小说,那完全是他的私人生活,与这份工资无关。类似地,哲学系的教授不是发明哲学的,而是研究别人发明的哲学的,历史系的教授不是记录今天历史的,而是研究他人在历史上留下的蛛丝马迹的。因此,"人文"确实不是科学,"研究人文"才是科学。创造"人文"是不可能在大学里领到工资的,研究并教授"人文"才能在大学里领到工资。文科生们应该再反思一下科学的概念。
倾向四:宣扬伪科学的科学共同体成员,他们曾经与方舟子一边的科学共同体成员直接论战。有一些人,已经是科学共同体的成员,但可能有一些特殊的经历,比如曾经被训练来教授某种十九世纪的哲学,但他们必须得把这种哲学说成是科学之母。现在他们只能是哲学系的教师,但是,在习惯上,他们并不研究"别人"发明的哲学,而是向他人灌输某种哲学,这就是当初训练他们的人所要达到的目的。现在,他们当中的某些人,很想把"科学"里塞进一些他们自己喜欢的东西。他们相当有文化,因此,可以写出一些似是而非的东西,试图动摇传统上"科学"的概念。他们是文化人,可能还自诩为哲学家,因此,我想,他们大概既不会参与铁锤事件,也不会为此叫好。但他们可能有一定的影响力。比如,他们给方舟子这边的人按上了一个"科学主义"的帽子,据说持有这种观点的人认为科学能够解释一切以及解决一切,而且只能由科学来解释和解决。但是,就像人们所嘲笑的,除了他们自己(他们当中的某些人说自己曾经是"科学主义"者),尚未在世界上发现持有如此愚蠢观点的人。
倾向五:认为方舟子打假不够专业的专业人士。对于这些人,我不想多说,谁说方舟子不够专业,你专业?你专业你来打!总不至于说学术界没有假可打吧?其实,方舟子在学术界能打的假,都是一些最不入流的,比如,明显抄袭论文的,招摇撞骗过分生猛的,等等。这根本不是今天学术界的主要问题,这是一台机器都能判断的不端行为。至于那些需要高度专业知识和崇高职业道德才能做出的判断,你根本听不到,没本事的都在琢磨着怎么应付论文数量的要求,有本事的都在琢磨着怎么申请经费、花掉经费,最有本事的自己立项、自己拿。而在这些人背后,是一些终于认识到提高知识分子待遇的好处的人,利出于一孔之后,上下同钱同德:-)
倾向六:认为方舟子代表了要消灭中医的力量。我不知道方舟子先生是否真的这样认为。但是,"中医"与"西医"这种并列方式,肯定遮蔽了问题的实质。问题是,什么是"现代"的、可以接受的医学?我们是否需要立法规定任何人要取得行医执照,都必须满足同样的、"现代"的训练标准?而诊断和治疗的过程,是否也要满足某种必需的标准?无论你怎样看待中医,你不可能禁止别人提出这样的问题,哪怕你觉得他们仅仅是出于一种文化上的自卑感,因此要竭力消灭"祖国的传统文化"。理论上说,医学是实践性很强的学科,西医并不足以否定中医,但是,如果要所有学生接受相同强度的西医训练,而学习中医的学生还要额外接受中医训练,这可能在事实上导致没有人去学中医了。当然这只是猜测。没准事实相反,中西医两个学位会让你更受欢迎,既接受过相同强度的现代西医训练,又懂得"祖国传统文化",你可能看起病来更有"文化底蕴"?:-)
没准中医院因此很火?:-) 结果,"祖国的传统文化"被你更好地发扬光大了。
倾向七:其他认为科学或者严谨的理性是他的绊脚石的人。
至此,以上七种倾向分析完毕。我认为,每一种倾向都不应该导致铁锤或者为铁锤叫好,指责他人应该基于事实,而且保持公正。现在我们讨论一下什么是一个好的社会?首先,我相信,你会承认,普遍的诚实对于我们这个社会的意义。一个互相撒谎的社会不可能是一个好的社会,在这样的社会里,好人没有机会,只有那些最寡廉鲜耻的人才能如鱼得水。你不可能认为,普遍的欺诈能导致一个好的社会。因此,你肯定会认为,保卫诚实、反对欺诈对于我们的社会意义重大。其次,科学是人类有史以来最伟大的发明之一,它在今天直接给我们带来利益。科学的存在和发展依赖于科学家,而自由和诚实是科学家之所以能够成为科学家的前提。一群被包养的不诚实的精英对于科学的发展是零价值的,他们创造不了任何东西,他们甚至学不会别人的东西。如果一个国家的科学界已经堕落到只会点数经费,那么,哪怕是一点批评性的意见,即使这种意见只能针对那些最不入流的造假者,这也是非常珍贵的。这是为在这个国家中保卫人类最有价值的精神财产而战。有些不了解科学界的人士可能觉得自己也被归为造假者的行列,我认为,如果你没有伤害任何人,你不必感到可耻,当然,如果你指望"科学"这个概念能够变得像你希望的那样,你也可能会遭到批评。最后,法律对于我们来说很重要,如果没有法律,你可能一天也活不过去。我们必须明白,雇凶杀人或者伤人,这是一个非常严重的法律问题。这种行为,不会仅仅伤害一个你所不喜欢的人,也会伤害你赖以生存的法律,就如同伤害你周围的空气。如果抽走我们身边的空气,不是只有方舟子会窒息而死,我们也无法生存。你作为这个社会的一员,你有义务在必要的时候重申法律对于我们的意义,而不是相反,对于极其恶劣的谋杀行为幸灾乐祸,如果你这样做了,你只是在伤害你自己,那不是任何其他人的耻辱,那只是你自己的耻辱。你内心怎样看待方舟子,这不重要。我也很多年没有去过方舟子的网站了,我的浏览器总是告诉我他的网站无法连接,可能受到防火墙的阻挡,要我与网络管理员联系。我一般没有与网络管理员联系的勇气。更重要的问题是,你怎样看待上面的几个问题?我们需要保卫诚实吗?我们需要爱护和保卫科学吗?我们需要保卫法律吗?如果你的回答是:是!那很好,我相信,你与你观点不同的人会因此达成很多共识。因此,我建议,在最近一段时间,讨论与方舟子有关的问题时,大家都来表明自己的观点,告诉大家,你知道诚实很珍贵,你认为科学应该被爱护、被保卫,你认为法律必须得到尊重。我相信,有了这些表达,很多分歧容易解决。方舟子没有做到的,你可以去做到,他没有做好的,你可以做得更好。你也可以做一名"打假斗士":-)
而且更货真价实。但你肯定不是希望这个世界一片黑暗,方舟子作为一个"打假斗士"的符号,很可能是这个黑暗世界上的最后一盏灯,或许你不这样认为,或许你认为你不需要光明,但是,如果你想熄灭他,我还是希望你能慎重考虑,你真的能把你的理由在下面写清楚吗?实际上,你可以选择,你可以说:"这个世界是我们的"。你也可以觉得自己就是一个过客,一个每天被人操纵的人,因此你愤世嫉俗,有一种要做暴民的冲动,拿出你指尖的小铁锤,用言词砸烂任何听起来比你更勇敢的故事,好让自己相信,你自己平凡而怯懦的人生,已经是这个黑暗世界里最光荣、最勇敢的人生了。但你其实什么也没有改变!写给我的暴民同胞们:-)2010-09-27

谜语答案

谜语答案1. Invoking heap(20) in heap(int *a,int size), at line 2,
an instance of heap is created
(which can be a local variant to be referenced) without being named as
an variant.
Let's call it heap_drop.2. root[i] in heap(int *a,int size), at line 5, is a member of the instance that
will be created by heap(int *a,int size), just this constructor
itself.
root[i] in heap(int *a,int size) is NOT a member of heap_drop mentioned above,
therefore it has not been allocated memory yet.
1 heap(int *a,int size){
2 heap(20);
3 cout<<"hhh";
4 for(int i = 0;i<size;i++){
5 root[i] = a[i];
6 }
7 heapSize = size;
8 build_Heap();
9 }
10 heap(int maxSize){
11 root = new int [maxSize];
12 }典典一句话评论:
heap(20) 不是调用构造函数初始化当前对象,而是分配了一个临时对象然后立刻销毁。感谢某用功同学提供代码示例。

猜谜活动

猜谜活动。人生艰难,听来个谜语给大家讲讲,娱乐一下。话说某同学整了以下C++代码,运行就崩溃。问:为啥?等级考试以后公布答案。#include<iostream>using namespace std;struct heap{ private: int *root; int heapSize; int maxSize; void build_Heap(){ int n = (heapSize+1)/2 -1; for(int i = n;i>=0;i--){ max_Heapify(i); } } public: heap(int *a,int size){ heap(20); cout<<"hhh"; for(int i = 0;i<size;i++){ root[i] = a[i]; } heapSize = size; build_Heap(); } heap(int maxSize){ root = new int [maxSize]; } heap(){ root = new int [20]; } void copyBuild(int *a,int size){ cout<<"hhh"; for(int i = 0;i<size;i++){ root[i] = a[i]; } heapSize = size; build_Heap(); } void max_Heapify(int i){ int leftChild = i*2+1; int rightChild = i*2+2; int max = root[i]; int maxLoc = i; if(leftChild<heapSize&&root[leftChild]>max){ max = root[leftChild]; maxLoc = leftChild; } if(rightChild<heapSize&&root[rightChild]>max){ max = root[rightChild]; maxLoc = rightChild; } if(maxLoc!=i){ root[maxLoc] = root[i]; root[i] = max; max_Heapify(maxLoc); } } int pop_top(){ if(0==heapSize){ cout<<"error!!! this is an empty heapn"; return -9999999; } if(1==heapSize){ heapSize = heapSize-1; return root[0]; } else { int max = root[0]; root[0] = root[--heapSize]; max_Heapify(0); return max; } } void output(){ for(int i = 0;i<heapSize;i++){ cout<<root[i]<<" "; if((i+1)%10==0) cout<<endl; } cout<<endl; }};int main(){ int *a = new int [20]; for(int i = 0;i<9;i++){ a[i] = i; cout<<a[i]<<" "; } int ss = 9; heap *p = new heap(a,9); cout<<"build heapn"; p->output(); cout<<"pop_top "<<p->pop_top()<<endl;}

通往奴役之路 笔记

通往奴役之路 笔记2010-09-15 21:53:26补录以前的,估计是2年前的pp.73 法治最能清楚地将一个自由国家的状态和一个在专制政府统治下的国家的状况区分开的,莫过于前者遵循着被称为法治的这一伟大原则。撇开所有技术细节不论,法治的意思就是指政府在一切行动中都受到事前规定并宣布的规则的约束--这种规则使得一个人有可能十分肯定地预见到当局在某一情况中会怎样使用它的强制权力,和根据对此的了解计划它自己的个人事务。虽然因为文法者以及那些受委托执行法律的人都是不可能不犯错误的凡人,从而这个理想也永远不可能达到尽美善尽美的地步,但是法治的基本点是清楚的:即留给执掌强制权力的执行机构的行动自由,应当减少到最低限度。虽则每一条法律,通过变动人们可能用以追求其目的的手段而在一定程度上限制了个人自由,但是在法治之下,却防止了政府采取特别的行动来破坏个人的努力。在已知的竞赛规则之内,个人可以自由地追求他人私人的目的和愿望,肯定不会有人有意识地利用政府权力来阻挠他的行动。pp.77 道德第二个方面,即道行的或政治方面的论证,与我们现在所要讨论的问题有更直接的关系。如果政府要精确地预见到其行动的影响,那就意味着它可以不让受影响的人有任何选择的任地。凡是当政府能够精确地预见其各种可能的行动对某种人的影响时,也恰恰是政府能够对各种目标进行选择。如果我们要创造新的对一切人都开放的机会,要给人们提供他们能随意加以利用的机会牟话,那么其精确的结果就是难以预见的。因此,普遍性的规则,有别于具体命令的真正法律,必须意在适用于不能预见其详情的情况,因而它对某一特定目标,某一特定个人的影响事前是无法知道的。只是在这种意义上,立法者才可能说得上是不偏不倚的。所谓不偏不倚的意思,就是指对一定的问题没有答案--如果我们一定要解决这类问题的话,就只能靠抛掷硬硬币来决定。在一个每一件事都能精确预见到的社会中,政府很难做一件事而仍然保持不偏不倚。只要政府政策对某种人的精确的影响是已知的,只要政府的直接目的是要达到那些特定影响,它就不能不了解这些影响,因而也就不能做到不偏不倚。它必定有所偏袒,把它的评价强加于人民,并且,不是帮助他们实现自己的目标,而是为他们选择目标。只要当制定法律的时候就已预见到这些特定影响,那提出,法律就不再仅仅是一个供人民使用的工具,反而成为立法者为了他的目的而影响人民的工具。政府不再是一个旨在帮助个人充分发展其个性的实用的机构,而成为一个"道德的"机构--这里的"道德的"一词不是作为"不道德的"反义词来使用的,而是指这样一种机构,它把它对一切道德问题的观点都强加于其成员,而不管这种观点是道德的或非常不道德的。在这种意义上,纳粹或其它任何集体主义的国家都是"道德的",而自由主义国家则不是。pp.85 法治限制政府行为

沉默容易 不说谎很不容易 zz

◇◇新语丝(www.xys.org)(xys4.dxiong.com)(www.xinyusi.info)(xys2.dropin.org)◇◇  沉默容易 不说谎很不容易  作者:高新  方舟子悬赏二十万找目击者,让我不知何感?这个政府不仅无脸还无能。二
十万可能可以找到50个杀手,却不一定能找到一个知情者。哪个的代价大谁都很
清楚,我甚至想:如果是悬赏杀手,会不会更容易找到答案?虽然抱着一丝希望
这案能破,但又对这丝希望隐隐不安,幕后黑手一旦大白天下,政府会怎么处理?
因为要拿到他的这种罪证基本不可能,更何况,这些疑似幕后黑手的人何其多也,
曝光了一个又会怎么样?所以这二十万只是政府脸面的一道口,不知道胡温一直
都要沉默下去吗?  和一佛家居士好友长聊,她也承认佛家的戒条中,最不易的就是不说谎。我
们对"打酱油、做俯卧撑"一族很同情,是因为他们没有选择沉默的机会,更不
能说真话,只能说谎了。佛家思想教人修身养性,独善其身,对周围一切都抱着
宽容之心,包容一切恶的、丑的、贪婪的、无耻的,献完了左脸又献出右脸。诵
着佛经等着因果的轮回。我和朋友说起新加坡,这个岛国无文化底蕴、无地大物
博,何以现在有如此高的素质和文明?佛家的宽容是不是导致大陆现状的幕后推
手?居士好友彻夜解读,也没能让我参透一二,我甚至问:佛门弟子会做官吗?
能搞管理吗?  居士好友仍会坚定地耕耘着,以其善去感动着身边非佛的众生们,而我却为
有那么多佛性同胞而感到难过。7月底,我和一个朋友带着孩子一行四人路途遥
遥地奔赴上海,在我的强权下,两个孩子坚持进了三次园。做为我这等草根,如
果不是为了让孩子见识一下国际大都市、世界博览会,有可能数十年也不会那么
长途一次的。虽然事前己打过预防针:要排很长时间的队进一场馆,但真轮着一
次次的三、四个小时换来一片片人海时,这已经不是热情,而是挑战流进密集人
堆的勇气了,如"世"子般的队伍不知道何处是头何处是尾,大家很快接受了来
世博园是练习排队,而我也只剩下了:每天进园四十多万人,那么多排队的都是
傻子,就你俩个聪明?!排吧,否则我们来这干吗来了?我不是佛家弟子,我却
教育着孩子们逆来顺受。是呀,我惊叹我们的同胞有这么多!更惊叹我们有如此
多良民!看了杨恒均先生的文章"世博亲历记:中国人的低素质让世博蒙羞?"
后,我更后怕这沉默的大多数,素质何其高、数量何其大!  多么难能可贵的太平盛世,多么难能可贵的和谐安康呀!这么大的草根良民
群体,轮回后又会成为什么?  昨天一个朋友在火车站发短信告诉我,她着急赶往车站,检票时才发现车票
没了,要求补票上车,结果检票员既不让补票更不让上车,她一急一气之下,伸
出了一拳,结果被一群工作人员围上。若不是一个当地的友人赶来解围,她就被
扣留在火车站了。我这朋友从我们读大学时就是一个吃苦耐劳、忍辱负重的典范,
曾在九十年代初期就获得过北京市劳模的称号,绝对是属于不会呐喊的沉默中的
良民。发生这样雷倒我的事,我竟然很开心,称赞她:总算有人味了!  我身边的佛实在太多,他们作为个体真完美得无可挑剔,善良、勤奋、坚韧、
智慧、淡泊名利,他们为了善常常会撒点善意的小谎,或帮别人圆圆骗局,也经
常做点舍己利人的事,甚至牺牲生命也再所不惜,他们是道德的楷模!但他们基
本不除恶扬善,也不会拉起手来共同向恶呐喊一声,指望他们象领袖一样建立如
新加坡式惩罚分明、严明的法制更是没门!  这是不是我们草根良民的佛性?(XYS20100913)◇◇新语丝(www.xys.org)(xys4.dxiong.com)(www.xinyusi.info)(xys2.dropin.org)◇◇

笔记 The Little Schemer

笔记 The Little Schemer
MIT Press - The Little Schemer - Daniel P. Friedman.pdf
The Little Schemer - 4th Edition.pdf[2010-08-17 周二 00:40]-
[2010-09-05 周日 20:06]* define atom?pp.5 [2010-08-17 周二]
> (define atom?
(lambda (x)
(and (not (pair? x))(not (null? x)))))
> (atom? (quote ()))
#f* cdrpp.13 [2010-08-17 周二]cdr is a list.What is (cdr (cdr l))
where
l is ((b) (x y) ((c)))(((c)))类似的What is the cdr of l
where
l is ( a b c)(b c)* consWhat is the cons of s and l
where s is (banana and)
and
l is (peanut butter and jelly)((banana and ) peanut butter and jelly)* consWhat is (cons s l)
where a is ((a b c))
and
l is bNo answer,
since the second argument l must be a list.* null listWhat is (null? (quote ()))* eqIs (eq? l1 l2) true or false
where l1 is ()
and
l2 is (strawberry)No answer, () and (strawberry) are lists.* eqIs (eq? n1 n2) true or false
where n1 is 6
and
n2 is 7No answer,
6 and 7 are numbers.* eqIs (eq? (cdr l) a) true or false
where
l is (soured milk)
and
a is milkNo answer,
See The laws of Eq? and Cdr.
Young says, (cdr l) is (milk), which is not an atom.* latTrue or false: (lat? l)
where l is ()True,
because it does not contain a list.* recursionInsertR(cons old (cons new (cdr lat)))* recursionpp. 62
在定义multinnsertL中,
需要在递归中改变条件。* recursionpp.81
We recur with a first argument from which we subtract the second
argument. When the function returns, we add 1 to the result.
=> division.* recur with carpp. 89
How are insertR* and rember* similar?They both recur with the car, whenever the car is a list, as well as
with the cdr.* 递归代替迭代pp.94 leftmose的递归调用方法,是用函数的递归调用代替了迭代。
* S-expressionWhat is an S-expression?An S-expression is either an atom or a (possibly empty) list of S-expressions.* lamda
pp.129Now what is
(lambda (a)
(lambda (x)
(eq? x a)))It is a function that, when passed an argument a, returns the function
(lambda (x)
(eq? x a))
where a is just that argument.* lambda applypp.135如何应用函数
(define multirember-f
(lambda (test?)
(lambda (a lat)
.....
)))(multirember-f test?) a lat)multirember-f是这样的函数,以test?作为参数,返回值是一个函数,
返回的函数以 a 和 lat 作为参数。(multirember-f test?) a lat)
相当于
(foo a lat)* lambda应用一个过程
Applying a procedure of lamda返回函数的函数 的应用语法pp.130
Do we need to give a name to eq?-saladNo, we may just as well ask
((eq?-c x) y)
where
x is salad
and
y is tuna.pp. 129
Now what is
(lamda (a)
(lamda (x)
(eq? x a)))It is a function that, when passed an argument a, returns the function
(lambda (x)
(eq? x a))
where a is jsut that argument.* closurespp. 137开始。递归太复杂。** [http://www.michaelharrison.ws/weblog/?p=34]
:
: (define multirember&co
: (lambda (a lat col)
: (cond
: ((null? lat)
: (col '() '()))
: ((eq? (car lat) a)
: (multirember&co a
: (cdr lat)
: (lambda (newlat seen)
: (col newlat
: (cons (car lat) seen)))))
: (else
: (multirember&co a
: (cdr lat)
: (lambda (newlat seen)
: (col (cons (car lat) newlat)
: seen)))))))
基于closures的解释,参见文献[1]。** 文献[2]提到,可以用Dr.Scheme 语言Pretty Big的debug观察。实验。定义multirember&co以后。Dr.Scheme, Pretty Big.
: >(define foo
: (lambda (x y)
: (length x)))
:
: > (multirember&co 'tuna '(tuna aa bb cc) foo)
: 3** 尝试用drscheme"展开"闭包,不支持;求助刘典,用display显示变量,不够直观,只能显示应用求值,不能显示代换的过程。** 手动: (define multirember&co
: (lambda (a lat col)
: (cond
: ((null? lat)
: (col '() '()))
: ((eq? (car lat) a)
: (multirember&co a
: (cdr lat)
: (lambda (newlat seen)
: (col newlat
: (cons (car lat) seen)))))
: (else
: (multirember&co a
: (cdr lat)
: (lambda (newlat seen)
: (col (cons (car lat) newlat)
: seen)))))))
: (define foo
: (lambda (x y)
: (length x)))
:
: ultirember&co 'tuna '(tuna aa bb cc) foo)substitute:The arguments of calling multirember&co:
: | calling | current lat | col | col, substituted a and
lat | col, substituted lambda |
: | multirember&co | | |
| |
: |----------------+-----------------+-----+----------------------------+-------------------------|
: | 1st round | (tuna aa bb cc) | col | /
| lambda (x y)(length x) |
The arguments of calling multirember&co:
: | calling | current lat | col, before substitution
| col, substituted a and lat
| col, substituted lambda
|
: | multirember&co | |
|
|
|
: |----------------+-----------------+---------------------------------------------------------+----------------------------------------------------------------------+-------------------------------------------------------------------------------------------|
: | 2nd round | (tuna aa bb cc) | lambda (newlat seen) (col
newlat (cons (car lat) seen)) | lambda (newlat seen) (col newlat (cons
(car '(tuna aa bb cc)) seen)) | lambda (newlat seen) ((lambda (x
y)(length x)) newlat (cons (car '(tuna aa bb cc)) seen)) |Note:In the expression
: lambda (newlat seen) (col newlat (cons (car lat) seen))
lat is (tuna aa bb cc), insetead of (aa bb cc).
The substitution happens before multirember&co is called,
so the lat is the original one without cdr applying.
Sic passim.End of the note.The col
lambda (newlat seen) ((lambda (x y)(length x)) newlat (cons (car
'(tuna aa bb cc)) seen))
is from:
lambda (newlat seen)
((lambda (x y)(length x))
newlat
(cons (car '(tuna aa bb cc)) seen))The arguments of calling multirember&co:
: | calling | current lat | col, before substitution
| col, substituted a and lat
| col, substituted lambda |
: | multirember&co | |
|
| |
: |----------------+-------------+---------------------------------------------------------+-----------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------|
: | 3rd round | (aa bb cc) | lambda (newlat seen) (col (cons
(car lat) newlat) seen) | lambda (newlat seen) (col (cons (car '(aa bb
cc)) newlat) seen) | lambda (newlat seen) ((lambda (newlat seen)
((lambda (x y)(length x)) newlat (cons (car '(tuna aa bb cc)) seen)))
(cons (car '(aa bb cc)) newlat) seen) |The col
lambda (newlat seen) ((lambda (newlat seen) ((lambda (x y)(length x))
newlat (cons (car '(aa bb cc)) seen))) (cons (car '(bb cc)) newlat)
seen)
is from:
lambda (newlat seen)
((lambda (newlat seen) ((lambda (x y)(length x)) newlat (cons (car
'(aa bb cc)) seen)))
(cons (car '(aa bb cc)) newlat)
seen)The arguments of calling multirember&co:
: | calling | current lat | col, before substitution
| col, substituted a and lat
| col, substituted lambda
|
: | multirember&co | |
|
|
|
: |----------------+-------------+---------------------------------------------------------+--------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
: | 4th round | (bb cc) | lambda (newlat seen) (col (cons
(car lat) newlat) seen) | lambda (newlat seen) (col (cons (car '(bb
cc)) newlat) seen) | lambda (newlat seen) ((lambda (newlat seen)
((lambda (newlat seen) ((lambda (x y)(length x)) newlat (cons (car
'(tuna aa bb cc)) seen))) (cons (car '(aa bb cc)) newlat) seen)) (cons
(car '(bb cc)) newlat) seen) |The col
lambda (newlat seen) ((lambda (newlat seen) ((lambda (newlat seen)
((lambda (x y)(length x)) newlat (cons (car '(tuna aa bb cc)) seen)))
(cons (car '(aa bb cc)) newlat) seen)) (cons (car '(bb cc)) newlat)
seen)
is from:
lambda (newlat seen)
((lambda (newlat seen) ((lambda (newlat seen) ((lambda (x y)(length
x)) newlat (cons (car '(tuna aa bb cc)) seen))) (cons (car '(aa bb
cc)) newlat) seen))
(cons (car '(bb cc)) newlat)
seen)The arguments of calling multirember&co:
: | calling | lat | col, before substitution
| col, substituted a and lat
| col, substituted lambda |
: | multirember&co | for multirember&co |
|
| |
: |----------------+---------------------+---------------------------------------------------------+-----------------------------------------------------------+-------------------------|
: | 5th round | (cc) | lambda (newlat seen) (col
(cons (car lat) newlat) seen) | lambda (newlat seen) (col (cons (car
'(cc)) newlat) seen) | |
The col
lambda (newlat seen) ((lambda (newlat seen) ((lambda (newlat seen)
((lambda (newlat seen) ((lambda (x y)(length x)) newlat (cons (car
'(tuna aa bb cc)) seen))) (cons (car '(aa bb cc)) newlat) seen)) (cons
(car '(bb cc)) newlat) seen)) (cons (car '(cc)) newlat) seen)
is from:
lambda (newlat seen)
((lambda (newlat seen) ((lambda (newlat seen) ((lambda (newlat seen)
((lambda (x y)(length x)) newlat (cons (car '(tuna aa bb cc)) seen)))
(cons (car '(aa bb cc)) newlat) seen)) (cons (car '(bb cc)) newlat)
seen))
(cons (car '(cc)) newlat)
seen)There is no 6th round of calling multirember&co, because of cond fullfilled.: ((null? lat)
: (col '() '()))Current lat is (cdr '(cc)), as '().The procedure col has been subsitituted in the previous steps to be
: lambda (newlat seen) ((lambda (newlat seen) ((lambda (newlat seen)
((lambda (newlat seen) ((lambda (x y)(length x)) newlat (cons (car
'(tuna aa bb cc)) seen))) (cons (car '(aa bb cc)) newlat) seen)) (cons
(car '(bb cc)) newlat) seen)) (cons (car '(cc)) newlat) seen)Eval (applying '() '() as arguements on col);(col '() '())
=>
((lambda (newlat seen) ((lambda (newlat seen) ((lambda (newlat seen)
((lambda (newlat seen) ((lambda (x y)(length x)) newlat (cons (car
'(tuna aa bb cc)) seen))) (cons (car '(aa bb cc)) newlat) seen)) (cons
(car '(bb cc)) newlat) seen)) (cons (car '(cc)) newlat) seen))
'()
'()
)* 图灵机停机pp. 153
will-stop? 无法定义,因为有的函数不会停止。* Y-combinator[http://www.catonmat.net/blog/derivation-of-ycombinator]
解决在函数中应用匿名函数的问题。1. 使用???替换函名函数,如果执行不到,这代码是可以执行的。: (lambda (list)
: (cond
: ((null? list) 0)
: (else
: (add1 (
:
: (lambda (list) ; the
: (cond ;
: ((null? list) 0) ; function
: (else ;
: (add1 (??? (cdr list)))))) ; itself
:
: (cdr list))))))2. 以length为参数以后,下面这段代码需要修正后执行,否则报错 "reference to undefined identifier: ???": ((lambda (length)
: (lambda (list)
: (cond
: ((null? list) 0)
: (else
: (add1 (length (cdr list)))))))
: ???)??? 被改为 length 后可执行。
??? 被改为 '(???) 也可以被执行。
??? 被改为 '() 也可以被执行。
看起来,只要???是个可以被引用的东西就行,但是不能是未定义的。
事实上,lambda (length)的参数不管是什么,都会返回 (lambda (list) 这个函数。如下实验:: (((lambda (length)
: (lambda (list)
: (cond
: ((null? list) 0)
: (else
: (add1 (willnot_run_here (cdr list)))))))
: 'place_holer) '() )下面的代码: ((lambda (f)
: (lambda (list)
: (cond
: ((null? list) 0)
: (else
: (add1 (f (cdr list)))))))
: ((lambda (g)
: (lambda (list)
: (cond
: ((null? list) 0)
: (else
: (add1 (g (cdr list)))))))
: ((lambda (h)
: (lambda (list)
: (cond
: ((null? list) 0)
: (else
: (add1 (h (cdr list)))))))
: ???)))"ince the argument names f, g,h in (lambda (f) ...), (lambda (g) ...),
(lambda (h) ...) are independent, we can rename all of them to length,
to make it look more similar to the length function:"以上并非可以替换名字的原因。
真正的原因是,lamda(f)中的参数f,是lamda(g);
lamda(g)中的参数g,是lambda(h);
而h只是占位符,对程序的求值没有任何作用。
以下代码是上面代码的变形,帮助理解。: (((lambda (lambda_lambda_place_holder)
: (lambda (list)
: (cond
: ((null? list) 0)
: (else
: (add1 (lambda_lambda_place_holder (cdr list)))))))
: ((lambda (lambda_place_holder)
: (lambda (list)
: (cond
: ((null? list) 0)
: (else
: (add1 (lambda_place_holder (cdr list)))))))
: ((lambda (place_holder)
: (lambda (list)
: (cond
: ((null? list) 0)
: (else
: (add1 (willnot_run_here (cdr list)))))))
: 'place_holder))) '(a b))下面的代码中,
把lambda(length)作为参数传给lambda (mk-length)
lambda (mk-length) 的执行是以参数作为函数,给这个函数的参数是占位符???;
这个参数此时是 lambda (length)。
lambda (length)的占位符参数没有被求值,函数就结束了。
所以,以下代码能求 '(): ((lambda (mk-length)
: (mk-length ???))
: (lambda (length)
: (lambda (list)
: (cond
: ((null? list) 0)
: (else
: (add1 (length (cdr list))))))))下面的代码中
lambda (mk-length)的执行是,
向mk-length传递参数 (mk-length ???)。
这一参数的解释上面已经提到,执行一次lambda (length)。
执行lambda (length),最后返回的是 length (cdr list)。
即,以lambda (length)作为lambda (length)的参数。
一共执行两次。: ((lambda (mk-length)
: (mk-length
: (mk-length ???)))
: (lambda (length)
: (lambda (list)
: (cond
: ((null? list) 0)
: (else
: (add1 (length (cdr list))))))))既然???是占位符,不会被求值,所以可以: ((lambda (mk-length)
: (mk-length mk-length))
: (lambda (length)
: (lambda (list)
: (cond
: ((null? list) 0)
: (else
: (add1 (length (cdr list))))))))所有的length改在mk-length。
传进来的参数确实是它。
代码略去。然后,length (cdr list) 换成 (mk-length mk-length) (cdr list)。
这样,(mk-length mk-length) 递归地返回 原来的lambda (length) 应用在 (cdr list) 上: ((lambda (mk-length)
: (mk-length mk-length))
: (lambda (mk-length)
: (lambda (list)
: (cond
: ((null? list) 0)
: (else
: (add1 ((mk-length mk-length) (cdr list))))))))其实mk-lenth只执行了一次,然后mk-length参数就是占位符了。
但是,"The function works because it keeps adding recursive uses by passing
mk-length to itself, just as it is about to expire."递归的跳出条件是(null? list)。把(lambda (length)移出作为lambda (le)的参数,
(lambda (x)作为le的参数。
代码如下。: ((lambda (le)
: ((lambda (mk-length)
: (mk-length mk-length))
: (lambda (mk-length)
: (le (lambda (x)
: ((mk-length mk-length) x))))))
: (lambda (length)
: (lambda (list)
: (cond
: ((null? list) 0)
: (else
: (add1 (length (cdr list))))))))Y-combinator如下。: (define Y
: (lambda (le)
: ((lambda (f) (f f))
: (lambda (f)
: (le (lambda (x) ((f f) x)))))))匿名函数的应用如下。: ((Y (lambda (length)
: (lambda (list)
: (cond
: ((null? list) 0)
: (else
: (add1 (length (cdr list))))))))
: '(a b c d e f g h i j))另一种Y-combinator的写法,
[http://www.mactech.com/articles/mactech/Vol.07/07.05/LambdaCalculus/]
and [http://www.stanford.edu/class/cs242/readings/vocabulary.html]
"When applied to a function, returns its fixed point."
: (define y
: (lambda (f)
: ((lambda (x) (f (x x)))
: (lambda (x) (f (x x))))))参见TLS书(非pdf页码)pp.171,
如何把lambda (length)移出,从而形成了Y-combinatior的框架。*关键:applying arguemnt lambda on precedure lambda, and eval the
augument lambda in precedure lambda.*另,参考[http://blog.vazexqi.com/2006/07/13/y-combinator]原来看不懂的一个原因是,这本电子书有缺页。
[The Little Schemer - 4th Edition.pdf]是个更完整的版本。* valuepp.185
What is (value e)
where
e is (quote nothing)nothing.What is (value e)
where
e is nothing.nothing has no value.* value
Where is (value e)
where
e is ((lambda (nothing)
(cons nothing (quote ())))
(quote
(from nothing comes something)))((from nothing comes something))以 '(from nothing comes something) 作为 lambda(nothing)的参数实验,Pretty Big
>'(nothing)
(nothing)
> (cons '(nothing) '())
((nothing))* interpreterpp. 189
Have we used the table yet?
No, but we will in a moment.Why do we need the table?
To remember the values of identifiers.pp. 188
(define value
(lambda (e)
(meaning e (quote ()))))
(define meaning
(lambda (e table)
((expression-to-action e) e table)))
* What is the Value of All of This?第10章,略读了。
这一部分应该是用 apply & eval 构造解释器。
准备细读《计算机程序的构造和解释》的相应部分。* laws** carThe primitive car is defined only for non-empty lists.
Young says: the result is a atom.** cdrThe primitive cdr is defined only for non-empty lists.
The cdr of any non-empty list is always another list.** consThe primitive cons takes two arguments.
The second argument to cons must be a list. The result is a list.** null?The primitive null? is defined only for lists.** eq?The primitive eq? takes two arguments.
Each must be a non-numeric atom.** lat[http://objectmix.com/scheme/186190-newbie-problem-understanding-lat-atom-little-schemer.html]
I bet, they use lat as short for "List of-AToms".** S-expression[http://objectmix.com/scheme/186190-newbie-problem-understanding-lat-atom-little-schemer.html]
The S in S-expression stands for symbolic. The word S-expression is
older than Scheme.** The First CommandmentWhen recurring on a list of atoms, lat, ask two questions about it:
(null? lat) and else.
When recurring on a number, n, ask two questions about it: (zero? n) and else.
When recurring on a list of S-expressions, l, ask thress question
about it: (null? l), (atom? (car l)), and else.
[以下前面的版本]
Always ask null? as the first question in expression any function.When recurring on a list of atoms, lat, ask two questions about it:
(null? lat) and else.
When recurring on a number, n, ask two questions about it: (zero? n) and else.
** The Second CommandmentUse cons to build lists.** The Third CommandmentWhen building a list, describe the first typical element,
and then cons it cons onto the natural recursion.
** The Fourthe CommandmentAlways change at least one argument while recurring.
When recurring on a list of atoms, lat, use (cdr lat).
When recurring on a number, n, use (sub1 n).
And when recurring on a list of S-expressions, l, use (car l) and (cdr l)
if neither (null? l) nor (atom? (car l)) are true.If must be changed to be closer to termination. The changing argument
must be tested in the termination condition:when useing cdr, test termination with null? and
when using sub1, test termination with zero?.[以下前面的版本]
Always change at least one argument while recurring. It must be
changed to be closer to termination. The changing argument must be
tested in the termination condition:
when using cdr, test termination with null? and
when using sub1, test termination with zero?.** The Fifth CommandmentWhen building a value with +, always use 0 for the value of the
terminating line, for adding 0 does not change the value of an
addition.When building a vluae with X, alwyas use 1 for the value of the
termination line, for multiplying by 1 does not change the value of a
multiplication.When building a vluae with cons, always consider () for the value of
the terminating line.
** The Sixth CommandmentSimplify only after the function is correct.** The Seventh CommandmentRecur on the subparts that are of the same nature:
- On the sublists of a list.
- On the subexpressions of an arithmetic expression.** The Eight CommandmentUse help functions to abstract from representations.** The Ninth CommandmentAbstract common patterns with a new function.** The Tenth CommandmentBuild functions to collect more than one value at a time.* 参考文献[1] [http://www.michaelharrison.ws/weblog/?p=34]Unpacking multirember&co from TLS The purpose of The Little Schemer,
its authors profess, is to teach you to think recursively, and to do
so without presenting too much math or too many computer science
concepts. The book is a ball to read. However, from the perspective of
this reader, who is fairly new to functional programming and totally
new to Scheme, the book gets almost asymptotically more difficult and
complicated towards the end of chapter 8, when we hit the function
multirember&co. Looking around on the web, I noticed quite a few
people had also hit this speed bump and were scratching their heads
about how to go on. I think I can offer some assistance. So, as
threatened yesterday, I now unveil my initial contribution to the wild
world of Lisp, my explication of multirember&co and the concept of
currying. Here's hoping I don't embarrass myself too much.
The Little Schemer, (hereafter "TLS") is the latest iteration of The
Little LISPer, and is presented as a dialogue between teacher and
student. If you take the roll of the student, and try to answer the
teacher's questions, especially those of the form "define this
function whose behavior we've been describing," you can really flex
your neurons. Each chapter is a little more complicated than the
previous, and within each chapter the questions get slightly harder as
you go. It's like walking up a steadily graded hill. Until you get to
page 137 and they hit you with a long function definition, for a
function you've never seen before, and they ask, "What does this do?"Yikes!Here is the code for the function. (Thank you, Geoffrey King, for
transcribing it in your post.)(define multirember&co
(lambda (a lat col)
(cond
((null? lat)
(col '() '()))
((eq? (car lat) a)
(multirember&co a
(cdr lat)
(lambda (newlat seen)
(col newlat
(cons (car lat) seen)))))
(else
(multirember&co a
(cdr lat)
(lambda (newlat seen)
(col (cons (car lat) newlat)
seen)))))))The first clue to dealing with this function is its context. The
previous pages of TLS deal with currying, in which you define a
function like (lambda (x) (lambda(y) (eq? x y) )) — it takes one
argument, parameter x, and then returns the inner function, which also
takes one argument, parameter y. The value you pass as x acts to
customize the inner function by binding the occurance of variable x in
the inner function to the value you passed in. So chapter 8 is about
the practice of wrapping functions in this way.The chapter is also about passing functions as arguments. The first
line of multirember&co, (lambda (a lat col) defines three
parameters. The variables 'a' and 'lat' are by convention used for an
atom and a list of atoms. But 'col' is a function–you have to pass
multirember&co a function that it uses inside its own definition.TLS admits that multirember&co is complicated. "That looks really
complicated!" says the student. But it seeks to simplify the function
by defining functions to stand in for a) the function that will be
passed as 'col'; b) the first inner function defined in the cond
branch (eq? (car lat) a); and c) the inner function defined in the
cond else branch. To try to make you feel better about being up to
your eyelids in deep water, the TLS authors give their functions
friendly names, like "a-friend" and "next-friend." But I prefer names
that tell me what roll the functions play, so here are my renamed
functions:a) the function that will be passed initially as 'col' (and will be
executed last):(define last-function
(lambda(x y) (length x)))b) the function called when a matches (car lat):(define when-match
(lambda (newlat seen) (col newlat (cons (car lat) seen)))c) the function called when the cond else branch executes:(define when-differ
(lambda (newlat seen) (col (cons (car lat) newlat) seen))TLS walks you through an execution of multirember&co, and so will
I. To further simplify things, and reduce the amount of typing I have
to do, I'll change the example in the book. Instead of a four-word lat
with some longer words, let's use (berries tuna fish) for our list,
and we'll keep tuna as our atom argument.Here's multirember&co, with the two inner functions replaced by the
pre-defined helper functions:(define multirember&co
(lambda (a lat col)
(cond
((null? lat)
(col '() '()))
((eq? (car lat) a)
(multirember&co a
(cdr lat)
(when-match)))
(else
(multirember&co a
(cdr lat)
(when-differ))))))When the function is called the first time, a is tuna, lat is (berries
tuna fish), and col is last-function. (car lat) is berries, which does
NOT eq tuna, so the else branch executes: multirember&co is called
with tuna as a, (tuna fish) as lat because we pass (cdr lat) and so we
lose the berries atom at the front of the list, and when-differ as
col.But wait. Actually, we're not just passing the when-differ function we
defined above. Here is that definition:(lambda (newlat seen) (col (cons (car lat) newlat) seen))This definition contains a variable, lat, that has a value at the time
multirember&co is called recursively: (berries tuna fish). So (car
lat) is (quote berries). What we've got here is a version, or an
instance, of when-differ that has a value bound to one of its
variables.This is like currying, this binding of values to the variable of a
function and then using this altered function to do something. I think
that currying, however, refers to wrapping functions so that only one
variable at a time is given a value. What this apparent creation of a
specific instance of the function when-differ DOES have in common with
currying is this: both use closures to encapsulate the instance of the
function with bound variables, or, to be precise, to make a copy of
the function with its own scope that will persist so long as there are
references to the closure. I didn't realize this on my own, of
course. I owe this insight to Richard P. Gabriel's essay The Why of Y,
which you can read in this Dr. Dobb's article or download as a PDF.There's something else in when-differ that will bind to a value:
col. The function passed, remember, is last-function. So we can (and
should) substitute that in for col.Let's give a unique name to the instance (technically the closure) of
the function when-differ that has these two values bound to it:
when-differ-1. Let's write it out, and set it aside for later use:(define when-differ-1
(lambda (newlat seen) (last-function (cons (quote berries) newlat) seen))
)Now, on to iteration two, which we can summarize like this:(multirember&co (quote tuna) (tuna fish) when-differ-1)OK, so this time, (eq? (car lat) a) yields true, and the other branch
of the condexecutes: multirember&co is called with tuna as a, (fish)
as lat, and when-match as col. Once again, thanks to currying, the
definition of when-match contains expressions to which values are
bound:(car lat), which becomes (quote tuna) , and col, which becomes
when-differ-1. Remember, we just recurred by calling multirember&co
with when-differ-1 as the function argument for the parameter col. So
now let's define the resulting instance of when-match as when-match-1:(define when-match-1
(lambda (newlat seen) (when-differ-1 newlat (cons (quote tuna) seen)))
)On on to iteration three–we're nearly there–which we can summarize
like this:(multirember&co (quote tuna) (fish) when-match-1)This time, tuna and fish don't match, which means we're going to recur
with another version of when-differ, when-differ-2:(define when-differ-2
(lambda (newlat seen) (when-match-1 (cons (quote fish) newlat) seen))
)Finally, iteration four:
(multirember&co (quote tuna) () when-differ-2)This time lat is an empty list, which means (null? lat) is true, and
the terminating line (col (quote()) (quote())) is executed. Yay! We're
done!Except…The result of the completed execution (col (quote()) (quote())) has to
be evaluated. Here's where everything turns inside out, or rightside
out if you like.First of all, the value of col in the final iteration was
when-differ-2. So we'll start there.(when-differ-2 (quote()) (quote()))Now, look back up and get the definition of when-differ-2 and
substitute it.((lambda (newlat seen) (when-match-1 (cons (quote
fish) newlat) seen)) (quote()) (quote()))OK, so the parameters newlat and seen both get assigned the value of
an empty list:(when-match-1 (cons (quote fish) (quote())) (quote()))We can simplify this by consing fish onto the empty list:(when-match-1 (fish) (quote()))We have a definition for when-match-1 too. Let's substitute that in now.((lambda (newlat seen) (when-differ-1 newlat (cons (quote tuna)
seen))) (fish) (quote())) )And again assign values, this time (fish) and () to newlat and seen:
(when-differ-1 (fish) (tuna))We're getting somewhere now. Do you see how at each step we're consing
a value onto either seen or newlat? seen has gotten the instance of
tuna, which was the atom we passed to multirember&co at the start,
whereas newlat has gotten the other atom, fish. Guess where berries is
going to go when we get to it.Now, let's substitute our definition of when-differ-1:((lambda (newlat seen) (last-function (cons (quote berries) newlat)
seen)) (fish) (tuna))Which becomes….
(last-function (berries fish) (tuna) )And now we're back where we started, with last-function.( (lambda(x y) (length x)) (berries fish) (tuna) )(length (berries fish) )2So that's how multirember&co works. What does it accomplish? It seems
to separate occurrences of the atom a in the list of atoms lat from
the other atoms in lat, and then it executes last-function using the
list of occurrences and the list of other atoms.In an imperative language like C or Java, you would probably define
two variables, one for each list, and then loop through the list of
atoms, testing each element in the list for equality with a, and then
pushing the element onto either of the two lists. Finally, you would
call the final function with the two lists you built.Consider the differences in this approach. Throughout the loop, you
have several variables remaining in scope, which means you have an
opportunity to munge one of them accidentally. Also, how modular is
this hypothetical code? In C, you could pass the last-function
function as an argument to a procedure that encapsulates the loop, but
try it in Java. No sir, in Java you'd have to call a method to get the
two lists (which would have to come back wrapped into one object,
probably a String[] array) and then call last-function with returnval[
0 ] and returnval[ 1 ]. Not terrible, but not elegant either.That's just scratching the surface, I'm sure. If the example were more
complicated, other implications of the recursive approach might become
clear, at least to smarter people than me. But there is one other
thing to point out.As TLS points out, the function you supply for use with the two lists
is assigned to a parameter names col because "col" stands for
"collector" by convention. What is this function collecting? The two
lists, of course. But more than that each use of col, as it changes
from when-differ to when-match, is persisting the values of the lists
from one step to the next. And that's important because as of page
136, there has been no mention in TLS of an assignment operator. So
even if we wanted to define variables to reference while looping
through the list, we could not. Not yet. After all, such code would
produce what functional programmers refer to, with a sniff, as side
effects.[2] [http://www.rhinocerus.net/forum/lang-scheme/100568-how-why-did-they-do.html]

中国城市化进程考验城市管理 人治模式亟待转变 zz

中国城市化进程考验城市管理 人治模式亟待转变
来源:瞭望新闻周刊2010年09月04日18:56
我来说两句(716)复制链接打印大中小
  《瞭望》文章:不断突破城市管理瓶颈
  进入城市大国的新时代,我们再一次面临"赶考"的挑战:如何在快速推进的城市化过程中管理好城市?
  文/韩保江
  随着城市化进程的快速推进和越来越多的人口向城市聚集,中国正在从农村人口占大多数的国家向城市居民占大多数的国家转变。这是一个巨变,它宣告传统以控制乡村、限制农民流动为特征的"城乡分治"模式将退出历史舞台,昭示以鼓励农村人口流动、放开城市限制为特征的"城乡一体化"治理模式将隆重登场。这个巨变,既会给城市带来新的发展机遇、发展动力和经济繁荣,也会给城市稳定和社会秩序带来巨大压力。因此,如何适应这一巨变,如何在城乡一体化加速推进的过程中管理好城市,如何突破制约城乡一体化发展的各种管理瓶颈等问题,亟待回答。
  早在1949年新中国成立前夕,毛泽东是用进京"赶考"来形容我们党从领导农村革命和夺取政权到执掌政权与开展城市建设这一时代转换的。如今,进入新的城市大国的时代,我们将再一次面临"赶考"的挑战。这次"赶考"的主要题目就是如何在快速推进的城市化过程中管理好城市。这需要认真研究现代城市发展规律,虚心借鉴发达国家管理城市的经验,深入检讨我国城市管理中的不足甚至缺陷。
  客观地讲,我国在过去几十年的城市管理中积累了不少经验。正因如此,城市化进程不仅快速推进,而且城市内部的经济和社会实现了发展和稳定。但也必须看到,我国的城市管理尚有诸多不足。具体表现在:一是刚性有余,柔性不足。现有城市管理方式多是沿袭计划经济体制和战争年代的管理观念,过于强调整齐划一。然而,城市应是丰富多彩的,城市人的生活应是更有个性的,特别是"市民社会"追求"自由和自治",由此要求城市管理要更富有柔性,要更有人情味,而绝非简单的"命令与服从"、"违规与惩罚",甚至"围追堵截"。
  二是重人治,轻法治。当前我国的城市管理过程中仍偏重领导重视和领导批示,以会议落实会议的现象普遍存在,重部署,轻落实,进而使许多法律法规流于形式。甚至由于长官意志而更改法律的现象也仍然存在。由于忽视法律法规严肃性及其在城市管理中的作用,城市中的许多违规主体或是采取"上有政策,下有对策"的办法来应付管理,或采取贿赂手段来逃避法律制裁。
  三是重政府,轻中介。城市管理主体是政府,但面对纷繁复杂的城市经济和社会生活,什么都要政府事必躬亲,是不可能的。许多发达国家都非常重视发挥"非政府组织"在城市管理中的作用。由于非政府组织的"民间性"、"中立性",可帮助政府解决民间政府不能解决的许多矛盾和问题。而这一点在我国城市管理过程中常常被忽视。
  四是重运动,轻制度。在我国城市管理过程中,无论是针对城市卫生、食品安全、假冒伪劣、黄赌毒、还是社会治安,都喜欢搞"战役式"的运动。不仅有五花八门的"大检查"、"严打月(年)",而且有形形色色的专项治理"领导小组"。这种治理城市的方式不仅容易劳民伤财,引起民怨,而且其效果也不甚理想。许多丑恶现象经常在轰轰烈烈的"战役"之后"死灰复燃"。
  五是政出多门,缺乏协调。在我国,专司城市管理的部门可谓不少,不仅有城管部门,而且有工商、卫生防疫、质量监督、食品安全、安全生产、公共安全等众多部门。城市管理水平不高,主要是因为部门之间职能交叉、缺乏协调。每个部门都容易从自身利益出发来制定政策,实施管理。有利的事大家争着管,无利的事易相互推诿,逃脱责任。由于这种"群龙治水"的管理方式效率很低,有的甚至越管问题越多,加上执法和管理过程中还存在着某些腐败或执法不公的现象,久而久之,管理部门的公信力每况愈下。
  针对不足和问题,我们应在研究中国城市发展规律的基础上,尝试用"法治"来管理和治理城市。为此,首先要深化城市管理体制改革,精简和整合城市管理机构,加快建立公共服务型政府。全新的城市管理应是刚柔并济、管理与服务并重、把管理寓于服务之中,并以此来缓解管理者与被管理者的"对立情绪"。有效的管理是政令统一的管理,为此需要整合诸多的城市管理部门职能,合理分工,努力形成城市管理合力,提高城市管理效率。
  其次,要加快完善我国城市管理的制度和法规,提高管理执法水平,最大限度减少管理执法过程的随意性。"公生明,廉生威",城市管理只有有法可依、执法必严,才能有利于城市居民形成"遵纪守法"的良好预期,进而提高政府执法部门的公信力。
  再有,要充分发展和利用中介组织,学会用社会力量管理社会。在城市管理过程中既要不遗余力地打击非法或黑社会组织,也要重视发展合法的非政府中介组织,充分发挥非政府中介组织在城市管理中的积极作用。
  同时,要大力提高城市管理人员的素质和能力,克服城市管理人员的"本领恐慌"。正所谓"事在人为",再好的制度、法规和政策都得通过城市管理人员来落实。因此,加强城市管理人员的培训,增强城市管理人员的素质,是落实好各项制度、法规、政策的根本保障。□
(责任编辑:曾安能)