2006-10-02
有奖竞猜
关键字: quiz
如下代码,第一位正确说出它的功能的我会给4星评价,第一个发现其中有何逻辑bug并适当修改的我会给5星。Good luck~
class Proc
def ^ n
Proc.new do |*args|
(1..n).inject(args){|result, null| result = self.call(*result)}
end
end
end
评论
cookoo
2006-10-02
Suninny 写道
你走了太多的弯路。lambda自带参数校验的。这种场合下inject也不如用n.times直接。
class Proc
def ^ n
raise "Illegal value of power" unless n >= 1 and n.integer?
lambda { |*args| n.times {args = call(*args)}; self}
end
end
n.times用得果然很巧妙啊,看来我得减少喜欢用inject的不良习惯啦。你说的对,Unmatched arguments那个检验是多余的,而且还有副作用。
另外你lambda最后传self这么做有bug:
f = lambda{|x| 2*x}
f.call(f.call(2)) #=> 8
(f^2).call 2 #=> #<Proc: ....>
不符合f^n(x)的数学定义,self改成args就好了
Suninny
2006-10-02
cookoo 写道
Bingo!
既然连f*g(x) = f(g(x))都想到了,应该不会想不到f^n(x) = f(...f(f(x))...)。这个题目好像太数学化了点,罪过。。。主要是我在思考简化一些数组和矩阵运算时的衍生物。
加了点排错的代码:
其实这里面还有个隐蔽的bug嘿嘿。。。
既然连f*g(x) = f(g(x))都想到了,应该不会想不到f^n(x) = f(...f(f(x))...)。这个题目好像太数学化了点,罪过。。。主要是我在思考简化一些数组和矩阵运算时的衍生物。
加了点排错的代码:
class Proc
def ^ n
raise "Illegal value of power" unless n >= 1 and n.integer?
Proc.new do |*args|
raise "Unmatched arguments" unless self.arity == self.call(*args).size
(1..n).inject(args){|result, null| result = self.call(*result)}
end
end
end
其实这里面还有个隐蔽的bug嘿嘿。。。
你走了太多的弯路。lambda自带参数校验的。这种场合下inject也不如用n.times直接。
class Proc
def ^ n
raise "Illegal value of power" unless n >= 1 and n.integer?
lambda { |*args| n.times {args = call(*args)}; self}
end
end
>>>>还能继续赋值:
prime = lambda{|a,*b| print a,' '; b.delete_if{|x|x%a == 0}}
op = prime^10
op.call *(2..100)
cookoo
2006-10-02
qiezi 写道
果然。改成这样就好看了:
真服了你们这些FP的脑袋。。
f = lambda{|a,b| [b,a+b]}
(f^5).call(1,1)
真服了你们这些FP的脑袋。。
其实还有不少例子,比如求质数:
prime = lambda{|a,*b| print a,' '; b.delete_if{|x|x%a == 0}}
(prime^10).call *(2..100) #=> 2 3 5 7 11 13 17 19 23 29
诸如此类在同一数据结构上做重复操作的都可以这么简化
njmzhang
2006-10-02
lambda {|f| lambda {|h| lambda {|x| f[h[h]][x]}}[lambda {|h| lambda {|x| f[h[h]][x]}}]}[lambda {|f| lambda {|x| x<2 ? 1 : f[x-1] + f[x-2]}}][5] # => 8
显示不下了-_-
lambda {|f| lambda {|h| lambda {|x| f[h[h]][x]}}[lambda {|h| lambda {|x| f[h[h]][x]}}]}\
[lambda {|f| lambda {|x| x<2 ? 1 : f[x-1] + f[x-2]}}][5] # => 8
qiezi
2006-10-02
果然。改成这样就好看了:
真服了你们这些FP的脑袋。。
f = lambda{|a,b| [b,a+b]}
(f^5).call(1,1)
真服了你们这些FP的脑袋。。
cookoo
2006-10-02
Bingo!
既然连f*g(x) = f(g(x))都想到了,应该不会想不到f^n(x) = f(...f(f(x))...)。这个题目好像太数学化了点,罪过。。。主要是我在思考简化一些数组和矩阵运算时的衍生物。
加了点排错的代码:
其实这里面还有个隐蔽的bug嘿嘿。。。
既然连f*g(x) = f(g(x))都想到了,应该不会想不到f^n(x) = f(...f(f(x))...)。这个题目好像太数学化了点,罪过。。。主要是我在思考简化一些数组和矩阵运算时的衍生物。
加了点排错的代码:
class Proc
def ^ n
raise "Illegal value of power" unless n >= 1 and n.integer?
Proc.new do |*args|
raise "Unmatched arguments" unless self.arity == self.call(*args).size
(1..n).inject(args){|result, null| result = self.call(*result)}
end
end
end
其实这里面还有个隐蔽的bug嘿嘿。。。
qiezi
2006-10-02
。。这我倒记不太清了。
其实我第一个感觉,这像是一个生成n个用户级线程的东西,但又只能一起call,所以排除。
第二个感觉是一个benchmark工具,不过又不如直接times来得简单。
这个fibonacci是想这家伙的用途的时候想到的,前面已经给出了它的用法,基本上确定它必须:传入n个参数,并且那个proc也要处理n个参数,根据inject用法,这个call也必须返回n个参数,所以fibonacci只是这其中的一个用法。
真要用它来生成fibonacci的话,其实我宁愿写个简单的:
其实我第一个感觉,这像是一个生成n个用户级线程的东西,但又只能一起call,所以排除。
第二个感觉是一个benchmark工具,不过又不如直接times来得简单。
这个fibonacci是想这家伙的用途的时候想到的,前面已经给出了它的用法,基本上确定它必须:传入n个参数,并且那个proc也要处理n个参数,根据inject用法,这个call也必须返回n个参数,所以fibonacci只是这其中的一个用法。
真要用它来生成fibonacci的话,其实我宁愿写个简单的:
irb> (1..5).inject([1,1]){|a,b| a << a[a.length-2] + a.last}
=> [1, 1, 2, 3, 5, 8, 13]
njmzhang
2006-10-02
如果那个Proc接受的参数个数和它返回的个数不一样就失败了。
类似的,还可以定义*,支持像Haskell那种写法f * g
类似的,还可以定义*,支持像Haskell那种写法f * g
class Proc
def * p
Proc.new do |*args|
self[p[*args]]
end
end
end
f = lambda { |a| a * a }
g = lambda { |b| b + b }
h = f * g
h.call(3) # => (3 + 3) * (3 + 3) = 36
cookoo
2006-10-02
qiezi 写道
补充一问:
(1..n).inject(args){|result, null| result = self.call(*result)}
和
(1..n).inject(args){|result, null| self.call(*result)}
是一个意思吧?
嗯,比如
(1..10).inject{|sum,i| sum+=i}
可以写成
(1..10).inject{|sum,i| sum+i}
后一种晦涩一些,一般习惯是前面的写法
基本上那个运算的工作原理不是太难理解,意义可能抽象了点,其实你连fibonacci都搞出来了。。。
厌倦发呆
2006-10-02
大致是这样
((Proc.new{|a,b,c| print a,b,c;puts;[c,b,a]} ^ 6).call 1,2,3,4,5,6,7,8,9)
^这个方法会返回一个Proc(简称p)调用传给他的block共n次
这个p接受一个数组参数,调用block的时候,将这个参数展开传给他,并期望这个block返回一个数组a,作为下一次调用block要展开的参数
((Proc.new{|a,b,c| print a,b,c;puts;[c,b,a]} ^ 6).call 1,2,3,4,5,6,7,8,9)
^这个方法会返回一个Proc(简称p)调用传给他的block共n次
这个p接受一个数组参数,调用block的时候,将这个参数展开传给他,并期望这个block返回一个数组a,作为下一次调用block要展开的参数
qiezi
2006-10-02
我只测试到这个情况:
看这具方法里面new出来的proc的形式,调用应该是这样的:
看起来没有任何意义。。。
不过倒是让我发现它可以干一件无聊的事:
没发现更多的奥秘了,能不能给下官一个小小的提示?
----------------------------------
补充一问:
(1..n).inject(args){|result, null| result = self.call(*result)}
和
(1..n).inject(args){|result, null| self.call(*result)}
是一个意思吧?
(Proc.new{puts 'a'} ^ 3).call
输出:
a
a
a
看这具方法里面new出来的proc的形式,调用应该是这样的:
(Proc.new{ |a| puts a; a } ^ 3).call(1)
(Proc.new{ |a, b| puts a + b; [a, b] } ^ 3).call(1, 2)
(Proc.new{ |a, b, c| puts a + b + c; [a, b, c] } ^ 3).call(1, 2, 3)
看起来没有任何意义。。。
不过倒是让我发现它可以干一件无聊的事:
(Proc.new{ |a, b| puts "#{b}, #{a+b}"; [b, a + b] } ^ 8).call(1, 1)
输出:
1, 2
2, 3
3, 5
5, 8
8, 13
13, 21
21, 34
34, 55
=> [34, 55]
没发现更多的奥秘了,能不能给下官一个小小的提示?
----------------------------------
补充一问:
(1..n).inject(args){|result, null| result = self.call(*result)}
和
(1..n).inject(args){|result, null| self.call(*result)}
是一个意思吧?
- 浏览: 327613 次
- 性别:

- 来自: Montreal

- 详细资料
搜索本博客
我的相册
20059805856241
共 10 张
共 10 张
最新评论
-
Darcs简介
good 3x
-- by 夜鸣猪 -
Pratical Ocaml作者采访
现在主要用F#分析数据,因为比较舒服(人懒啊)。其实也只用到很少的FP特性,Ru ...
-- by cookoo -
Pratical Ocaml作者采访
一年多了,呵呵,cookoo能说说看,学习使用OCaml的进展和体会吗?
-- by billgui -
Memory - 柿岛伸次
还不错啊。
-- by hazzy -
Memory - 柿岛伸次
我很想下这个,可就是不能下。LZ能否提供链接
-- by yeshucheng






评论排行榜