Author: 杨 贵福
lambda过程作为返回值的例子-分析,及一个作用域的例子
lambda过程作为返回值的例子-分析,及一个作用域的例子1. 昨天的例子的分析昨天整完lambda过程作为返回值的例子就被二猫叫走了,没来得及分析.以下是分析及另一个的例子(似乎出自SICP,记不大清了).以下混用过程和函数.: guile> (define (foo x)
: (cond ((= x 1) (lambda (y) (+ y 10)))
: ((= x 2) (lambda (y) (+ y 20)))
: (else (lambda (y) (+ y 0)))))这段代码可以理解为(define (foo x) (啥啥东西))这意味着,定义了一个过程名为foo,有一个参数.我们再看 (啥啥东西) 的里面: (cond ((= x 1) (lambda (y) (+ y 10)))
: ((= x 2) (lambda (y) (+ y 20)))
: (else (lambda (y) (+ y 0))))一个条件判断,有三种可能,每种可能都形如: ((= x 1) (lambda (y) (+ y 10)))其中 (= x 1) 是 判断条件部分,后面的 (lambda (y) (+ y 10)) 是整个表达式
的值,即foo这个过程的返回值.这个返回值是什么呢?: (lambda (y) (+ y 10))这个返回值是一个函数,匿名,有一个参数,函数体是 (+ y 10),即把这个参数
加10以后返回.整理一下.
1.foo这个函数返回值是一个函数;
2.这个作为返回值的函数,函数体是 (+ y 10).我们再测试一下.: guile> (foo 1)
: #<procedure #f (y)>意思是:foo这个函数传参数值为1,返回值是个函数,有一个参数.: guile> ((foo 1) 23)
: 33当foo的参数为1的时候,cond求值为
: ((= x 1) (lambda (y) (+ y 10)))(lambda (y) (+ y 10)) 的参数是
: guile> ((foo 1) 23)
中的23.即,把(foo 1)代换为(lambda (y) (+ y 10)),这正是对(foo 1)求值的结果.那么 ((foo 1) 23) 就成了 ((lambda (y) (+ y 10)) 23).在一个参数的函数上,传参(apply)值为23,所以值为(+ 23 10),即33.以下例子请作为练习分析.: guile> ((foo 2) 23)
: 43
: guile> ((foo 3) 23)
: 23
: guile> ((foo 2) 33)
: 532. 新的例子.2.1: guile>(define (f x y)
: ((lambda (a b)
: (+ (* x (* a a)) (* y b) (* a b)))
: (+ 1 (* x y))
: (- 1 y)))即 (define (f x y) (啥啥东西) )定义函数f,有两个参数.啥啥东西是:: ((lambda (a b)
: (+ (* x (* a a)) (* y b) (* a b)))
: (+ 1 (* x y))
: (- 1 y))这是什么呢?这是 ((lambda (a b) (又一个啥啥东西))
(东西1)
(东西2))这是什么意思呢?这是 (一个匿名函数 (参数1) (参数2)).其中 参数1 = 东西1; 参数2 = 东西2.请先回顾一下,然后我们继续.所以这是什么呢?这是给有两个参数的一个匿名函数传参,求值.这个匿名函数是什么呢?(lambda (a b) (又一个啥啥东西)原文是 (+ (* x (* a a)) (* y b) (* a b)).2.2所以,我们退回去一些,下式得到了解释.: ((lambda (a b)
: (+ (* x (* a a)) (* y b) (* a b)))
: (+ 1 (* x y))
: (- 1 y))它的意思是"这是给有两个参数的一个匿名函数传参,求值."再往回退一点,第2节提到的式子,如下,得到了解释.: (define (f x y)
: ((lambda (a b)
: (+ (* x (* a a)) (* y b) (* a b)))
: (+ 1 (* x y))
: (- 1 y)))我们定义了一个函数名为f,两个参数,这个函数f的作用是 给两个参数的一个匿
名函数传参求值.我们测试一下.: guile>(f 1 2)
: 42.3这个例子的求值,一个关键因素是那些 x、y、a、b 的值,或者说,它们的作用域。在没有被覆盖的情况下,lambda里面的x、y就是f里面的x、y。请看下面的等价测
试。: guile> (define x 1) (define y 2) (define a 3) (define b -1)
:
: guile> (+ (* x (* a a)) (* y b) (* a b))
: 4
lambda过程作为返回值的例子
pics
当你说不行时,你应该说些什么:以Android播放midi为例
中国好几年前都对能对美国说"不",软件工程师也经常要对用户和同事说"不"。但是别人经常还要在你说不以后继续喋喋不休,为什么呢?
据说男生说不的时候,就是不的意思;据说女生说不的时候,是请再继续表现的意思。这坑害了很多猥琐男。因为,只有她希望你继续表现的时候,那时"不"的意思才是请继续表现,否则,"不"的意思就是"不"。一些女生假设对方能够理解这一显然的事实:即,你是否是被欢迎继续表现的。
而这个世界上没有显然的事情。继续表现的,多是猥琐男,被希望继续表现的,通常很快就引退了。
关于如何说是,咱们今天不讨论;今天单讨论一下如何明确地说不。
会发生上述误会,盖因东方民族隐晦含蓄的表达方式传统。看过一个日本片子。某个提了个什么主意,女主角坐在那里,低头着头,很坚毅地说:"虽说很好。"
你不要以为还有下文,她说到这里就戛然而止了。日本人就是这样说话的。她发出的声音是"虽说很好",但实际想传达的是后面所有没说的内容。
在工程中,用户和同事也经常会误解。那么如何准确地传达"不"的信息呢?
1. 对用户
这个简单。
除了告诉他不以外,还要告诉他 技术上完全可以,但是...然后开始罗列代价:时间(工期)、经费等等。
然后他就自动引退了。这在女生说不的场景中,类似于,女生说完不以后,再补充,"其实呢,也不是不行,但是需要加些条件。我想要的很简单:一座大大的露台,上面有个秋千……"
明确的回绝,就是 不行 + 你不具备"行"的理由。
2. 对同事
明确告诉同事,尤其是分配给你任务的那个人,"你的想法很猪头" 的方法是,告诉他,他的想法不可行的原因。
并且,为了交流简洁起见,把他所有可能的提问,所有可能修正的主意都罗列出来,然后一一否定。写文档或报告的时候,不要期待交互,不要期待他问你答,用答案堵住他所有可能下嘴的地方。
不恃敌所不攻也,恃吾有以待也。
以下是一个实例故事。这也我们为什么要训练写实验报告的原因,它记录了过程和数据,以此支持你的看法。没有人会像科幻电影里的总统啥的那样,因为你琼瑶般喊"你们相信我吧,地球真的要毁灭啦"就相信你。
我们应该做的是:告诉小伙不行,然后对他淡定地笑笑,然后准确清晰完整地说出他不行的原因。
背景:
我请牛同学做Android下的一个程序原理,播放音乐合弦,比如大三度。意思是,同时把do,re,mi的声音发出来。
技术方案之一是用PCM混音,之二是在MIDI中同时播放这几个音。牛同学分别试了。
牛同学试了一段时间以后,说终于找到一个生成midi文件的方法。
我提出新的要求,不要把midi文件写到文件系统(internal
storage)中,而是用java的stream,在内存(RAM)中直接发给MediaPlayer播放。
牛同学说:不行。
故事开始了。
你说不行,我当然不能因为是你说的,然后就信了。要有事实。
所以牛同学发来他的代码,我学习了一段,发现真的不行。然后写了下面这封信。略有修改。
----信的正文由此开始----
下面提到的"应该"是指 建议给你的
报告的写法.有了这些你"应该"提供的资料,我才能了解你研究了哪些必要的方法.这是用以证明你研究的路线是正确的方法.或者换种说法,如果以下报告中的"应该"部分你已经告诉我,我就不必看你的代码了.
1. 你应该提供我MidiFile的出处,以便我参考,因为MidiFile不是你写的,且不是java/android的一部分;
2. 你是否参考了此邮件后面网址的实现?[http://kevinboone.net/javamidi.html]
3. 我提到的不必向文件系统中写出midi文件,原计划的路线是这样的:通过重写 writeToFile
实现,把这个方法中的写到文件系统中转为对Stream赋值,也可以把midi的内容放在 vector<byte>中;
4. 然后设置MediaPlayer.SetDataSource()的参数为这个vector或者Stream.
下面是我寻找解决方案的路线。
4.1 MediaPlayer需要FileDescriptor
[http://developer.android.com/reference/android/media/MediaPlayer.html#pubmethods]MediaPlayer.setDataSource(FileDescriptor
fd)Sets the data source (FileDescriptor) to use.
4.2 FileDescriptor可以由FileInputStream/FileOutputStream建立
[http://developer.android.com/reference/java/io/FileDescriptor.html]It's
possible to get the file descriptor used by some classes (such
asFileInputStream, FileOutputStream, and RandomAccessFile), and
thencreate new streams that point to the same file descriptor.
[http://developer.android.com/reference/java/io/FileOutputStream.html]FileInputStream.getFD()public
final FileDescriptor getFD ()Returns the underlying file descriptor.
4.4 到这里,我的思路走不下去了。因为FileInputStream的构造函数要求存储在FLASH中的文件。
你应该列出以下方法,并说明MediaPlayer没有其他的方法 setDataSource.
void setDataSource(String path)Sets the data source (file-path or
http/rtsp URL) to use.void setDataSource(FileDescriptor fd, long
offset, long length)Sets the data source (FileDescriptor) to use.void
setDataSource(FileDescriptor fd)Sets the data source (FileDescriptor)
to use.void setDataSource(Context context, Uri uri, Map<String,
String> headers)Sets the data source as a content Uri.void
setDataSource(Context context, Uri uri)Sets the data source as a
content Uri.4.5 然后我开始查是否有其他的办法。因为利用stream而不通过文件系统,这实在应该是个非常通用的方案,android sdk没有理由不支持啊。
[http://developer.android.com/reference/android/content/Context.html#getCacheDir()]讨论了这一问题,播放内存中,而不是flash(internal
storage)中的midi文件。
4.6 下面这个方法我同意[http://code.google.com/p/android/issues/detail?id=739]
: Comment 7 by [email protected], Aug 19, 2008: From the ReadMe
included with 0.9 SDK.: : Unfortunately, the ability to play audio
streams from memory (such as via an : InputStream or Reader) will not
be possible in Android 1.0. As a workaround, we : recommend that
developers save media content to SD card and use MediaPlayer to play :
from a file URI, or embed a small HTTP server and play from a URI on
localhost (such : as http://127.0.0.1:4242/something
杨注:但是第二天一早,我又意识到这是不行的。因为读http必然要求那个midi文件已经存在了。这与我原计划不希望写入文件系统相违背。
同一贴子有人提到
: Comment 12 by [email protected], May 19, 2009: Issue now
resolved with AudioTrack in Android 1.5 (Cupcake)
这是我们以前提到过的方法,在[http://developer.android.com/reference/android/media/AudioTrack.html]
里提到,不过需要PCM作为buffer而不能用midi作为buffer.
正如同一贴子的人回答道:
: Comment 22 by sam.clegg, Sep 13, 2011: Is there really still no
streaming audio support in android?: : AudioTrack doesn't help as it
only works for PCM samples, not encoded files.
4.7 至此,我提出的从stream中写入midi,然后从stream中构造MediaPlayer,这一方案可以得出结论 不行.
我们不能因为谁说不行就认定不行,而只能根据以上的分析.
4.8 我们仍然可以用PCM的方法合成和弦.我建议还是试回这个方法.
杨注:然后第二天一早,我又反悔了,因为PCM的尺寸会比MIDI大很多,这不是我们希望的。
请用MATLAB做这样的试验:
杨注:所以下面的实验我就在此省略了。