this.Think();

(Define (Learn-SICP (Begin (Read Book) (Write Scheme) (Thinkabout It))))
随笔 - 13, 评论 - 139, 引用 - 1

导航

关于

关注于.Net, OO Design 和 Scheme

正在阅读:
SICP

Advanced .Net Remoting

已读完:

每月存档

最新留言

广告

2006年11月28日

在上一篇blog: 关于定位 中, 我提到关于我们的定位, 可以从 人->商业人员->IT业职员(软件工程师) 这样的逻辑关系来考虑. 那么今天我们先来看看"人"这一部分.

正如老话说的一样:"做事先做人", 其实无论你从事甚么样的职业(甚至没有工作), 为人正直成熟也是身为文明人最基本的要求. 一名好的IT业职员首先要得是一名好的商业人员, 而一名好的商业人员首先得是一个成熟的自然人, 见图一.


(图一)

纵观全世界各个文化, 虽然它们历史演变的背景都不同, 但倡导的道德都包括: 善良, 正直, 勇气等等这类共通因素. 例如中国传统美德中, 孔子、孟子讲讲忠、孝、仁、义、礼、智等。孟子谈论四端说:“恻隐之心,仁之端也;羞恶之心,义之端也;辞让之心,礼之端也;是非之心,智之端也。”《中庸》所讲的三达德为智、仁、勇。而在西方的Bible中, 《加拉太书》(Galatians) 5:22-23说:“圣灵所结的果子,就是仁爱、喜乐、和平、忍耐、恩慈、良善、信实、温柔、节制。……”

企业文化很多也是以上的社会道德准则演化而来, 越是成熟的企业对其人员道德的重视程度也越高(例如HP的商业执行准则SBC就体现了坚持"絕不妥協的誠信經營企業"的信念. SBC就好像HP的宪章一样, 而违反的下场一般就是be fired). 作为企业的一名雇员, 你的价值观越于企业的文化达成一致, 你得到的提升机会也就越大.


(图二)

如图二所示, "High业绩High企业文化符合度"自然是最佳; "Low业绩Low企业文化符合度"肯定是被淘汰. 那么"High业绩Low企业文化符合度"呢, 从短时间来说还ok, 但是长远下去肯定不行; 至于"Low业绩High企业文化符合度", 则可以成为企业培训的目标.

其实, 关于怎么样做人这个topic实在太大, 完全超过了这里讨论的范畴了, 每个人都有自己的人生观价值观, 我不敢妄自说哪种是对的那种是错的, 这个问题还是交给各位读者自己了. 如何作一个善良,正直勇敢的人, 可以说是一生的课程. :)

不过有一些个人体会linkcd可以share一下给大家: 去制定自己的使命宣言, 也就好像是制定自己的人生宪法一样. 关于如何写, 网上的资料其实很多, 而且每个人的情况不同, 制定好的宣言也是因人而异. 在linkcd的宣言里面包含的有以下几点, 给大家参考吧:
===
(注:有省略)
目标:
更精彩更完整的体验人生

宣言:
作为一个成年人, 我想要成为,并且致力成为具有以下特质的人:
对待生活积极主动, 不无谓浪费时间
第一时间承认错误
勇于承担责任, 而不是逃避
自律, 信守诺言
自信, 并保持谦和
终生学习
财务自由
身体健康

作为一个职业人士, 我想要:
从事自己喜欢的职业, 了解自己的长处,发展自己的才能, 保证自己的核心竞争力
===

下一段胡扯内容的预告: 如何作一个好的商业人员.

后记: 关于系列(一):关于定位那篇blog中, 笔者犯了一个错误: 例子二(Fred和Bob的例子)太过于抽象和主观性了, 导致得到很多批评, 也偏离了笔者的原意.  其实我并不是要将technical skill和profit making对立起来, 但需要注意的是不要把我们的目标 (profit making) 和 实现目标的手段 (technical skill) 完全等同起来. 要实现盈利的目标, 我们还需要思考除了单纯技术以外的东西.

posted on 2006-11-28 14:42:00 by linkcd  评论(24) 阅读(7526)

 
2006年11月24日

前端时间看到Kaneboy的随笔, 提到灵感之源的事, 实在是让人看了心里不好受. 前端时间又刚好看完My job went to India, 也觉得是时候整理一下自己的想法了, 于是大家就听linkcd小小胡扯一下吧


关于定位

首先, 请问自己一个问题:我是谁?相信绝大多数人会回答:我是一名_____工程师.(空白处填上.Net/Java/C++等等). 但是请注意, 除了少数从事计算机教育/科研的人之外, 我们绝大数(无论是普通Employee还是Boss, 但本文只针对Employee而谈)都是在为商业机构工作, 所以我们中大多数其实可以算作是商业人员 (Business people). 简单的逻辑关系就是 人->商业人员->IT业职员(软件工程师).

对于Business People, Wikipedia是这样解释的:A business person is a generic term for someone who is employed at a profit-oriented enterprise.

请注意Profit-Oriented这个词: 商业组织的目的就是创造价值并获得利润, 组织中每一个人所作的工作, 都是为这个目的而服务的.

同意? 很好, 我们继续往下看第二个问题: 我们身上甚么能力是我们的雇主最看重的呢? 或者说,甚么东西是考察一名软件工程师是否称职的重要因素呢?

“自然是技术能力的高低, 水平越高, 雇主自然越愿意聘请你. “ 如果你的回答是这样, 那么请回顾第一个问题的结论: 每一名软件工程师首先是一名商业人员, 而每一名商业人员所效力的组织都有着很明确的Goal: Profit!

因此, 你的老板之所以雇用你, 每个月付你的高额的薪水, 只为了一个目的: 让你为他的组织创造profit.于是我们得到第二个问题的答案: 能否为组织创造profit,能创造多大的profit, 是考察一个employee的重要标准.

哦, 当然, 多数时候, 技术能力和创造profit的能力是一致的:技术能力越高, 为组织获取更多profit的几率也越大, 得到老板赏识和提升的机会也就越多.

但是(天哪,我恨这个但是), 也有可能出现技术能力和profit making相矛盾的情况:

最简单的例子, 某DBA, 技术能力很强, 但是缺乏和客户的合作精神, 导致公司损失客户(也就是损失profit), 他的下场自然可想而知. -- 高technical skill但是低profit making.

再来一个夸张的例子: Sale拿到一个project,价值$30k, 该项目可以用实现完美Object Oriented的J2EE实现, 也可以用”ugly”的asp来完成. 现在有2个PM先后看过了项目需求, PM Fred(技术能力最强的PM)建议把项目交给他, 他准备组建一直全是programming guru的”梦之队”, 用3个月完成一个完美的OO实现的系统, 他为此作出的budget是20k. PM Bob技术没那么好, 也不懂啥叫OO Design, 他准备找几个刚毕业的学生来用ASP做这个项目,当然我们已经可以想象Bob团队做出的东西内部肯定难看的要命了, 但好处在于, Bob的预算只需要10k.

假设Fred和Bob做出的系统都release给用户, 由于Fred梦之队的专家们采用了业内最好的技术, 他们的系统压根没有甚么bug, 遇到需求变更也轻松解决, 于是后期维护的费用几乎是0$. 但是Bob就没那么幸运了, 他的系统后期花在bug fixing和变更上的费用是$3k, 同时因为项目交付延期, 造成用户不满, 造成间接损失(公司信誉)$2k.

你看, Fred完成的任务比Bob漂亮多了, 老板肯定会任用Fred, 不是吗?

但是, 等等, 公司老板不是技术出身, 他可不懂Fred用的OO是多么先进, Bob做出的系统内部是多么的不堪入目, 他只能(也只会)注意这样的公式:

Fred team最后的利润是 收入30k - 开发费用20k – 维护0k = 最终利润10k.
Bob team最后的利润是 收入30k – 开发费用10k – 维护费用3k – 间接损失2k = 最终利润15k.

现在, 再猜猜我们亲爱的老板最终会任用Fred还任用Bob呢?

哦, 我知道你现在想说甚么. 当然, 当然, 我们聪明的Fred当然也可以采用Bob的方法, 他最后也能为公司挣到15k(甚至更多). 但是在这个例子里, 我们可以清楚看到最好的technical skill并不能为公司创造最多的profit. Fred要想成功, 他似乎更需要依赖的是财务预算能力和商业决断能力, 而不是懂得多少个Design Pattern.

因此, Technical skill和profit making之间绝对不是等号关系. 事实上, profit making始终是第一原则, Technical skill可能和profit making一致也可能不一致, 但是它自始自终都要服从profit making.

不扯远了, 回到我们自己身上. 那么, 我们这些软件工程师, 要怎样完善自己, 才能在职业道路上走的更顺利呢? 我想我们可以从前面的逻辑关系: 人->商业人员->IT业职员(软件工程师)一个一个来看.

(To be continuing…)

posted on 2006-11-24 17:31:00 by linkcd  评论(33) 阅读(8357)

 
2006年09月28日
10月16~20号,上海. 这里有来自MS的堂主参加吗? 如果有, 希望可以当面交流一下;)

posted on 2006-09-28 13:14:00 by linkcd  评论(12) 阅读(5846)

 
2006年09月02日
Email的重要性我就懒得废话了, 事实上我们都是靠email过活的, 那么要怎样才能高效的使用它呢?
我先扔几块砖头出来, 大家来补充吧

坏习惯包括:
1. 滥用Reply All功能(又称Reply All综合症) - 相当的人对此比较反感
2. 不压缩庞大的附件 - 想想你收到一个有18MB之巨的Word附件的感觉吧, 特别是你本来邮箱空间就告急的时候
3. 和邮件内容毫无提示作用的Subject - 这样的subject对应以后的邮件查找没有一点帮助
4. 过长的邮件内容, 却在最不起眼的地方提出需要收件人回答的问题 - 收件人很可能错过问题, 或者压根懒得看完
5. 大量的拼写错误 - 写出这样的邮件只能是不专业的表现, 如果是内部邮件还好说, 如果是发给客户的邮件就...
6. 大量的缩写 - 新teammember会模不着头脑

好习惯包括:
1. 刚到新公司的时候, 了解公司对于Email使用的policy
2. 谨慎使用mail list, 不要把你租房信息/farewell mail发给全世界的同事
3. 花心思撰写通俗好懂且简短的mail, 在mail的开头就清楚的提出你的要求或问题
4. 使用Outlook的spell check功能, 或者在sent之前习惯性的按F7
5. 对于作出关键决策的邮件, 保留起来作为以后的证据
6. 在转发很长的邮件的时候, 请对要转发的邮件内容进行概括
7. 如果要发送大容量的附件, 最好把要该附件上传到某个file share, 然后在邮件中给出link
8. 如果告诉别人某个event的时间和地点, 请不要用mail而是使用calendar
9. 尽量不要在邮件中包括花哨的背景图片或者巨大的签名档. 事实上, 使用simple text是最好的选择.
10. 请假之前, 使用"Out of office assistant"
11. 转发Junk邮件时, 把重要性设为Low

个人的邮件管理
1. 时刻注意邮箱的容量, 删除不必要的邮件. 如果把邮件下载到本地:1) 注意备份你的pst文件(否则HD坏了所有邮件丢失,就哭都来不及了) 2)根据MS的建议, 每个pt的大小不要超过1G, 如果接近1G就换个新的pst文件
2. 不要在你的inbox里面堆积上千封没有整理的mail, 简单的按"From"来分组也是不高效的, 应该使用folder+flag来管理
3. 如果使用outlook, 记得使用flag功能, 用不同颜色表示不同意义
4. 学习GTD方法, 找到适合你工作性质的邮件管理方式

杂谈:
1. Email是重要的沟通工具, 但是请注意它不能取代电话沟通或者面对面的交谈
2. Email可以作为官方文档和法律依据

更多的信息:
合理使用Rule来管理邮件
使Gmail做GTD管理
Optimize your life #3 - how to manage e-mail effectively by Richard Kuo

参考:
HP KB0500 Email Etiquette
Air Combat Commanders Guide to Managing Email
http://www.43folders.com/

posted on 2006-09-02 17:10:00 by linkcd  评论(18) 阅读(13756)

 
2006年03月24日

无意中发现的

 http://www.cenqua.com/fisheye/

介绍: Fisheye delivers a unified view of your repository that provides easy navigation, powerful search, historical reporting, configurable file annotation and diff views, changeset analysis, RSS feeds, and integration with your issue tracker. Many more features and enhancements are also under development. FishEye takes the pain out of extracting data from you repository, and puts all that data on your radar.

posted on 2006-03-24 11:43:00 by linkcd  评论(15) 阅读(6467)

 
2006年02月21日

【摘要】:是否厌恶了维护庞大的Switch-Case语句,是否认为可以为这些选择逻辑写出更清晰的代码?
恩,我们至少可以来试试。。。

点这里阅读全文

ps:笔者在手头的项目里,见过存在 分支多达128种的Case语句,遍布于超过2万行的单一class文件,对其原作者佩服不已~~ @_@

posted on 2006-02-21 11:33:00 by linkcd  评论(6) 阅读(8282)

 
2005年11月09日

今天从内部Newsletter上看到PATENT PROFILES的文章。介绍很吸引人:Introduces some of the company's most creative people -- the top inventors, patent holders and engineers -- and finds out what inspires them. (如果您是HP-er的话,直接到这里看全文)里面采访了包括2位华人在内的很多专利发明人。

对于“遇到脑袋短路(mental bloack)时,你一般怎么做?”这个问题,各位发明者的回答大致包括以下3种:
1。去做运动,包括骑车,高尔夫等等,让脑袋完全放松,然后答案会突然出现!
2。向其他人从头开始阐述遇到的问题,往往你解释完一遍,答案自然而然的也就出现了。当然,有人提到“写下来”也是可以帮助整理思路的。
3。和同事讨论,由于大家的工作背景不同,在你看来很困难的问题可能在别人看来就很简单。

如果换成问国内的工程师,估计会有第四种回答:出去抽根烟
(ps:我在那里看到最猛的一位回答:短路的时候去来点French and Spanish wines

然后在回答“是什么影响了你,让你成为一个Inventor或Engineer的?”时,大多回答都是在孩童时代父母的影响很大,让他们从小对创新发明就很感兴趣。反观国内,很多人仅仅是追求所谓高薪而来当Engineer,因为兴趣的确不在这里,当得辛苦不说,成就也不会很高。

所以,如果你想培养自己的孩子成为Inventor的话,马上给他/她准备一份Legos玩具吧!(广告语:因为这是近半数发明者童年的选择

 

posted on 2005-11-09 20:57:00 by linkcd  评论(6) 阅读(6739)

 
2005年10月14日

前几天在HP GDCC办理入职手续,需要填写一大堆表格。每一份表格都有:姓名,性别,籍贯,出生日期,民族,ID No, 家庭住址等等信息需要填写。于是我们不得不把上述相同的信息抄写了一遍又一遍,很费时间。然则回想以前,我们从小到大,入学,重大考试(高考,研究生考试),新公司入职,我们已经填写了无数这样的表格。

很明显,这样的做法已经违反了DRY原则(Don't Repeat Yourself)。事实上,对于绝大多数人来说,如姓名,性别,出生日期这样的信息是终生不变的。这样的信息完全可以与ID No挂钩起来。

不过好消息是第二代身份证据说已经可以做到这点了:其内置内置的IC芯片便可以存储上述信息。这样的做法很类似MS Passport,即在不同系统/场合中通过唯一通用标示,来共享用户信息的机制。而我们的ID No天生就是扮演这种唯一标示符的角色。

在以后类似的场合,我们只需要通过安装在公司HR的ID Card读取设备上刷一下,就可以自动打印出具有完整个人信息的表单。

但是,采用这种方式带来的问题在于:第二代身份证的读取设备是否易于广泛部署呢?如果该设备价格昂贵,或是基于安全性的考虑,只能部署在特定场所(如:公安局),那么必定会限制新身份证发挥其优点。(换句话说,由于公司不能部署该设备,我们还是不得不在入职的时候填那堆表格)

或者换一种方式:由政府部门维护一个面向社会的开放系统,在需要查询个人资料时,通过提交Id No.和查询密码来获得。查询密码由本人提供给公司或学校,即授权公司和学校通过这种方式来获得本人的信息。

posted on 2005-10-14 14:18:00 by linkcd  评论(29) 阅读(8590)

 
2005年09月26日

"这不是bug,这是设计!"

               -- 某软件开发人员对用户说道.

这好像是个很老的笑话, 但我就刚遇到了一次.

原先遇到这个issue, 然后我当作bug报给了MS, 在9月13号ADO.NET的PM  Kawarjit Bedi 回复说这是个design而不是bug, 并给出了理由.

谢谢Kawarjit.

但没想通的是, 我明明注册了这个Issue的MSN Alert的, 但是没有收到任何信息, 于是9月13号的回复我到现在才看到, 真奇怪.

posted on 2005-09-26 12:16:00 by linkcd  评论(3) 阅读(4230)

 
2005年09月01日

我们已经听过太多应该是用 Dataset还是应该使用自定义Class作为container的争论了.

很多Anti-Dataseter 对于.Net 1.1 下面dataset蹩脚的xml序列化方式很是不屑. 不可否认, xml序列化的确是dataset的一大缺陷.  但是Microsoft已经意识到了这个问题, 在即将推出的.Net 2.0中,他们为dataset提供了真正的binary序列化方式.

那么, 改进后的binary dataset性能到底如何呢? 在2.0时代, 什么样的container才是我们正确的选择呢?

本文通过实际的测试结果告诉您 :)
请点击阅读全文.

posted on 2005-09-01 21:13:00 by linkcd  评论(2) 阅读(4322)

 
2005年08月18日

研究Int32&的时候,无意中发现C#里面还有4个Undocument Keyword, 分别是__makeref, __reftype, __refvalue 以及__arglist。 其中前三个keyword可以这样用:

        int i = 1;
        
        TypedReference tr 
= __makeref(i);
        Type t 
= __reftype(tr); //t = System.Int32
        
        
int i1 = __refvalue(tr, int); //i1 = 1
        int i2 = (int)TypedReference.ToObject(tr); //i2 = 1
        
        i
++//i = 2
        
        
int i3 = __refvalue(tr, int); //i3 = 2

(关于TypedReference类型MSDN是这样描述的:Describes objects that contain both a managed pointer to a location and a runtime representation of the type that may be stored at that location. 同时TypedReference有[CLSCompliant(false)]标记)

于是我们可以用下面这种方法来模拟ByRef的参数

public class MyClass
{
    
public static void Main()
    
{
        
int v = 99;
        TypedReference trParameters 
= __makeref(v);
        Foo(trParameters);

        Console.WriteLine(
"v = {0}", v); // v = 100 
    }

    

    
public static void Foo(TypedReference tr)
    
{
        
if(__reftype(tr) == typeof(int))
        
{
            __refvalue(tr, 
int)++;
        }

    }

}

比较不爽的就是我们必须在Foo方法体中判断TypedReference包含的类型。

注意如果把Foo写成public static void Foo(ref TypedReference tr),编译器会抱怨说:Method or delegate parameter cannot be of type 'ref System.TypedReference'。

至于__arglist则可以模拟params关键字,抄个例子:

public void Function(__arglist) 
{
    ArgIterator iterator 
= new ArgIterator(__arglist);
    
for (int count=iterator.GetRemainingCount(); count>0; count--)
    
{
        TypedReference typedRef 
= iterator.GetNextArg();
        Console.WriteLine(__refvalue(typedRef, 
int));
   }

}

调用它:Function(__arglist(2,3,4));  输出2,3,4

后注:这4个keyword毕竟是undocument的,微软也没有提供任何支持,所以不排除以后被delete掉。Mono下面的编译器似乎也不支持,不过我在vs2005 beta里面试验还是有效的。

 Updated: Flier Lu在他的blog对__arglist的使用作了更深入的探讨,推荐阅读。 :)

posted on 2005-08-18 18:49:00 by linkcd  评论(3) 阅读(3828)

 
2005年08月14日
话说有一天你要用反射来对Target类进行操作,调用Foo函数。
public class Target
...{
public void Foo(int x, int y, int z)
...{
}

public void Foo(int x, ref int y, out int z)
...{
}
}
可以看到Foo有2个重载,唯一的区别在于第二个Foo方法签名中有带ref的参数。
如果你直接写:

Target myTarget = new Target();
Type t = myTarget.GetType();
MethodInfo methodInfoWithRefParamters = t.GetMethod("Foo");
那么会在RunTime扔个Exception说: Ambiguous match found.
要想invoke第二个Foo的话,我们必须这样写:
MethodInfo methodInfoWithRefParamters ;
Type[] typeList = new Type[] {typeof(int), Type.GetType("System.Int32&"),Type.GetType("System.Int32&") };
methodInfoWithRefParamters = t.GetMethod("Foo", typeList );
好吧,现在运行是正常运行了,可是新的问题又来了:这个System.Int32&是个啥东东呢?
 
先在MSDN/.Net Reflector找找Int32&,没有。Google和查看微软放出的Framework Source Code,同样无果。
 
得,现成的资料找不到,那只有让我们自己通过做试验来玩玩了。
 
1。 先试试能不能搞一个Int32&的实例出来:

当然,就不用指望直接能在C#里面new一个Int32&了。(如果是unsafe的话,Int32*到还可以)
来试试亲爱的Activator吧:
Type refInt32Type = Type.GetType("System.Int32&");
object myRefInt = System.Activator.CreateInstance(refInt32Type, true);
哎呀,扔了一个“No parameterless constructor defined for this object.”异常出来。
 
2。好吧,那让我们来看看Int32&有啥样的constructor:
BindingFlags bf = BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance
                              | BindingFlags.GetField | BindingFlags.GetProperty | BindingFlags.NonPublic ;

Console.WriteLine(refInt32Type.GetConstructors(bf).Length);
结果却返回了0。

狠一点,把全部BindingFlags Enum放到bf上去呢,用GetMembers试试呢?

BindingFlags bf = // all values of BindingFlags
Console.WriteLine("count of member in type Int32&: {0}", Type.GetType("System.Int32&").GetMembers(bf).Length);
oops,输出长度还是0!
 3。Ok,Ok,不能创建实例就暂时不管它,那让我们用QuickWatch来看看这个Int32&类型有啥属性:

下面是我把Int32,Int32&, Int32*,外加Boolean&类型做对比的结果。(属性值相同的已经略过)
 
 
通过这张表我们可以观察到很有意思的结果:
Int32& 是ByRef的(最明显,呵呵),不是ValueType, 不可以序列化,没有Sealed,GUID都是0,BaseType 显示为《undefined value》
 
请特别注意的是Int32&, Int32*它们IsClass属性为True,说明是个Class,先记下来,在后面我会给大家看一个更有趣的结果。
 
既然,Int32&和Int32*都说自己有ElementType,那就来看看是什么Type吧:
Type.GetType("System.Int32&").GetElementType(); // Print “System.Int32”
Type.GetType("System.Int32*").GetElementType(); // Print “System.Int32” too.
4.回过头来看看生成的IL代码呢?
 

如图,只能看到对于ref/out 的参数,使用的是ldloca.s 指令,还是没看到我们的Int32&类型,
 
5.最后来看看最有趣的发现:
先试试在你的机器上run这3句代码:
Console.WriteLine(Type.GetType("System.Int32&").IsSubclassOf(typeof(object)));
Console.WriteLine(Type.GetType("System.Int32*").IsSubclassOf(typeof(object)));
Console.WriteLine(Type.GetType("System.Boolean*").IsSubclassOf(typeof(object)));
再看结果,呵呵,吃惊吧。以上3句都是输出False。难道说.Net里存在着不是从Object继承的Type吗?可它的IsClass属性是为True的哦~

会不会Int32&不是属于.Net框架的呢?可看看它的AssemblyQualifiedName是“System.Int32&, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089”,也没看出什么问题啊?(汗)
 
个人初步猜测:
 
Int32&类型并不是一个真实存在的类型(原因是通过Reflector没能发现它的踪影),而是在CLR中动态构造的一个类型。MS使用它来“表示/标志”某个ValueType的地址。

2005/08/16 Update: 
思归的帖子,以及Joel Pobar的blog对这个问题作出了比较好的解释,有兴趣的读者可以看原文,偷懒的话就听我说一下吧
 
ByRef types 是受控指针,在CLR里面也是真实存在的类型。不过因为只有很少的IL指令能够作用与它,所以我们不能创建它的实例。同时,系统也限制我们只能在parameter的位置使用ByRef的类型。值得注意的是Int32&和Int32之间不存在什么关系哦...
 
 

posted on 2005-08-14 20:17:00 by linkcd  评论(12) 阅读(5561)

 
2005年07月21日

《4个程序员的一天》一文中,idior问道:

不知道类似foo(+,-,+,*,/, a) //a is a array
实现a[0]+a[1]+a[2]*a[3]/a[4]这种功能能实现吗?(用FP)

昨晚去看了看scheme的数据结构操作,得出以下解法:(;号后面是注释)
(define (inner-runner 1st-number operators numbers)
  (if (= 0 (length operators))
    1st-number
    (inner-runner ((car operators) 1st-number (car numbers))   ; calculate new 1st-number
                          (cdr operators)                                            ; get new operators list
                          (cdr numbers))))                                          ; get new numbers list

(define (Foo operators numbers)
  (inner-runner (car opes) ops (cdr opes)))

然后我们来run run试试:3 * 5 - 2 + 4  = 17
> (Foo (list * - + ) (list 3 5 2 4))
等于17 ,得解 ;)

好了,现在来说下解题的思路:
Setp1:从Numbers中“POP”出第一个数作为初始化操作数,叫做1st-number,。Numbers现在剩下n个数字,我们称这个新的list为Numbers*.

Setp2:然后递归的分别从Operators和Numbers*里“POP”出运算符和第二个运算数,拿来和前面我们拿到的1st-number做运算,把得到的结果当作新的1st-number,连同新的Operators和新的Numbers*,重复step2,直到Operators变为空。

这时候再回过头来看上面的scheme代码:

先简单说明下scheme的语法:
(list * - + ) :构造一个list,包含3个元素:*,-, +
(length operators):得到operators这个list的长度

(car operators):得到operators这个list的第一个元素。
例:(car (list 1 2 3)) = 1,注意它返回的是一个元素,不是list

(cdr operators):得到operators这个list从第二个元素开始的子list
例:(cdr (list 1 2 3)) = (list 2 3),注意它返回的是个子list而不是元素

来看看inner-runner函数,它完成的是step2的工作:
它先看看operators是否为空,如果为空就直接返回1st-number;如果不是,那么分别取得一个operator和一个number,进行(operator 1st-number number)运算,把得到的结果又当作1st-number,连同剩下的operators和numbers进行下一轮的递归。

至于主函数foo就比较简单了。它接受2个list类型的参数:Operators,包含n个运算符,Numbers,包含n+1个数字(当然你也可以放多于n+1的数字,不过多的数不会参与运算),Foo做的工作只是取出最初的1st-number,剩下的就交给inner-runner搞定了。


至于预算步骤,让我们来看看(先减少些运算符以缩小运算过程):
(Foo (list * - ) (list 3 5 2))  =>

(inner-runner
  (car (list 3 5 2))
  (list * -)
  (cdr (list 3 5 2))) =>

(inner-runner
  ((car (list * -))
   3
   (car (list 5 2)))
  (cdr (list * -))
  (cdr (list 5 2))) =>

(if (=
     0
     (length (list -)))
  15
  (inner-runner
    ((car (list -))
     15
     (car (list 2)))
    (cdr (list -))
    (cdr (list 2)))) => 等于13

怎么样,明白了吧? 事实上,scheme很多运算都是靠这种简单的递归来完成的。

如idior所说,这个问题可以在".net下利用delegate的多播可以方便实现, java利用compostion模式也能完成"。(如果idior你有时间的话,能否说明一下compostion的解法呢? 毕竟Design Pattern方面你比较熟,呵呵)

而且就表现方面来说,虽然scheme代码看上去比较少,不过对于大多数programmer来说,代码的可读性也是非常重要的。FP的代码咋看上去,的确很让人头晕...@_@

写到这里,我们的Semon同志过来看了看我这post的草稿,对我上面最后一句话很是不屑,然后提了一个问题:

既然已知3 * 5 - 2 + 4  = 17,那么用scheme这样写:(Foo (list * - + =) (list 3 5 2 4 17)),即在operators最后加入一个=号,在numbers最后加入结果17,该语句返回true。(Foo (list * - + =) (list 3 5 2 4 18)) 返回false。

你能用java或C#实现这个最后判等的功能么?

哇呀,这可把我难倒了...

各位看官,您有啥好建议么?

PS:很高兴来到博客堂大家庭,请大家多多指教 :P

 

posted on 2005-07-21 19:49:00 by linkcd  评论(1) 阅读(3601)

 

Powered by: Joycode.MVC引擎 0.5.2.0