- 浏览: 221331 次
文章分类
- 全部博客 (155)
- activerdf (1)
- html (0)
- depoly (1)
- src_present (1)
- ria (1)
- beast (2)
- cache (1)
- acts_as_atggable (1)
- http (1)
- talk (1)
- rest (1)
- rake (1)
- vim (2)
- active_resource (1)
- jruby activerecord_jdbc (1)
- nginx (1)
- plugin (1)
- gui (1)
- push (1)
- 介紹 (1)
- rails (19)
- regex (1)
- svn (1)
- 說明 (13)
- gem (4)
- ruby (16)
- rails12 (2)
- fastcgi (1)
- os (1)
- mongrel (5)
- scale (4)
- quickref (1)
- 安裝 (5)
- tiobe_index (2)
- planet (1)
- lighttpd (4)
- Capistrano (1)
- 嘴砲 (2)
- performance (4)
- ide (6)
- jruby (12)
- railsconf (1)
- activerecord (2)
- ajax (3)
- ruby.net (1)
- 程式 (1)
- actionmailer (1)
- company (2)
- security (1)
- redmine (1)
- book (2)
- news (2)
- 廣告 (1)
最新评论
-
bluerose:
你好,我下载了文件是Textile格式的。应该怎么阅读呢?我想 ...
Textile,RedCloth,Vim -
whg333:
谢谢,LZ是香港或台湾人士?怎么都是繁体?
學習 Ruby on Rails 要看的書 -
jerry:
https可以作吗?
Net::HTTP 使用方式 -
thinhair:
能不能具体点? 这个Config文件在那啊?
用 JRuby 來連接 Oracle -
dearsuper:
就是希望少占资源。
Another Ruby IDE:InterlliJ Idea for Ruby Plugin launch
[Ruby] recursive lambda
==本文連同引文同步載於 ptt Ruby 板、LightyRoR、飽和脂肪星(星之一角備份區)==
很抱歉最近狀況真的是相當糟糕,導致很多事情都沒做或是沒做好。雖然以後大概也不會比較好。這樣講講就沒關係嗎?當然不是,只是替自己找一點比較能安心的藉口吧。另外本文有任何錯誤歡迎指出。
==本文開始==
我一直覺得 Ruby 缺少一個類似 self 的東西,用來表達現在這個 function/method. 這個東西有什麼用呢?其實我也不知道有什麼用,就只是單純覺得好像少了這種東西。最直覺的例子,恐怕就是具有遞迴能力的 lambda function. 我曾在 ptt Ruby 板發過一篇文,講 quine(self-reproducing programs),後來我用了 Ruby2Ruby, 寫了像這樣的結果:(飽和脂肪星有該文的備份(通常連不上))
最蠢的地方是明明都用 lambda(proc) 了,我卻還得把 lambda 的結果記起來留待以後使用。這樣實在是有點無趣。我希望我可以寫:
lambda{ print(this.to_ruby); print(".call") }.call
這樣不是帥氣多了嗎?於是我開始試著思索實作這東西的可能。接著我忽然想到,所謂 this 不正是指在 call stack 最上端的 function/method 嗎?因為當我們執行到這個 function/method 時,this 一定是指同一 function, 不可能忽然去指涉其他 function, 而另外一個 function 進 call stack 時,不把他解掉也不可能會執行到 this. 於是可以把 this 寫成一個 function, 不吃任何引數,回傳一個 Proc/Method 代表正在 call stack 頂端的那個 function.
而我記得 Ruby 是有方法可以去存取 call stack... 雖然好像是用很蠢的方法,也確實是有點蠢,但總之可以用模擬的。隨意 google 了一下,找到一個很簡單的方式,就是用 set_trace_func, 丟一個 callback 進去,於是 Ruby 在各個 function 間做動作的時候,都會呼叫這個 callback. 感覺就是效率會變狂差,不過呢,至少暫時是可以用的。
接著可以利用 Thread.current[:symbol] 來儲存 current thread call stack info, 任何 function call 時,push 資料進這個假的 call stack, function return 時,pop 資料出來。這樣就有一個很簡單的 call stack info 可以用了。
以下程式歡迎任意使用,licensed under Apache License 2.0, 複製到檔案用的話希望可以把以下這段 copy 到檔案最前面… XD
以上不管有沒有問題,都可以來看一下我額外寫的幾個 unit test, 參考一下幾個我目前想到的用法。
為什麼要用 def f; end 呢??這樣不就失去 this 的意義了??因為不曉得為什麼,Ruby2Ruby 跑 lambda + this 都會有奇怪的 runtime error, 而這個錯誤是來自 class RubyToRuby 的 rewrite_defn(exp), 最後的:「raise "Unknown :defn format: #{name.inspect} #{args.inspect} #{body.inspect}"」這我一時不知道要怎麼解決,不知道會是誰的錯,所以只好暫時用 def f; end 這種蠢方式了。
另外,還有一些無聊的花枝可以玩:
類推,我也不知道有什麼用,搞不好有什麼 cleanup 是要等所有的事都做完才能做?總而言之,就是這樣啦,沒什麼營養,但我卻覺得很重要的功能。在很多時候可以少打很多字。搞不好哪一天也會想到什麼真的很有價值的應用也說不定。總覺得真的有太多事是無心插柳柳橙汁。雖然大部份都來不及喝就乾掉了。
2007.04.16 godfat 真常
==本文連同引文同步載於 ptt Ruby 板、LightyRoR、飽和脂肪星(星之一角備份區)==
很抱歉最近狀況真的是相當糟糕,導致很多事情都沒做或是沒做好。雖然以後大概也不會比較好。這樣講講就沒關係嗎?當然不是,只是替自己找一點比較能安心的藉口吧。另外本文有任何錯誤歡迎指出。
==本文開始==
我一直覺得 Ruby 缺少一個類似 self 的東西,用來表達現在這個 function/method. 這個東西有什麼用呢?其實我也不知道有什麼用,就只是單純覺得好像少了這種東西。最直覺的例子,恐怕就是具有遞迴能力的 lambda function. 我曾在 ptt Ruby 板發過一篇文,講 quine(self-reproducing programs),後來我用了 Ruby2Ruby, 寫了像這樣的結果:(飽和脂肪星有該文的備份(通常連不上))
#!/usr/bin/ruby
require 'rubygems'
require 'ruby2ruby'
(a = proc {
puts("#!/usr/bin/ruby")
puts
puts("require 'rubygems'")
puts("require 'ruby2ruby'")
puts
print("(a = ")
print(a.to_ruby)
print(").call")
}).call
最蠢的地方是明明都用 lambda(proc) 了,我卻還得把 lambda 的結果記起來留待以後使用。這樣實在是有點無趣。我希望我可以寫:
lambda{ print(this.to_ruby); print(".call") }.call
這樣不是帥氣多了嗎?於是我開始試著思索實作這東西的可能。接著我忽然想到,所謂 this 不正是指在 call stack 最上端的 function/method 嗎?因為當我們執行到這個 function/method 時,this 一定是指同一 function, 不可能忽然去指涉其他 function, 而另外一個 function 進 call stack 時,不把他解掉也不可能會執行到 this. 於是可以把 this 寫成一個 function, 不吃任何引數,回傳一個 Proc/Method 代表正在 call stack 頂端的那個 function.
而我記得 Ruby 是有方法可以去存取 call stack... 雖然好像是用很蠢的方法,也確實是有點蠢,但總之可以用模擬的。隨意 google 了一下,找到一個很簡單的方式,就是用 set_trace_func, 丟一個 callback 進去,於是 Ruby 在各個 function 間做動作的時候,都會呼叫這個 callback. 感覺就是效率會變狂差,不過呢,至少暫時是可以用的。
接著可以利用 Thread.current[:symbol] 來儲存 current thread call stack info, 任何 function call 時,push 資料進這個假的 call stack, function return 時,pop 資料出來。這樣就有一個很簡單的 call stack info 可以用了。
以下程式歡迎任意使用,licensed under Apache License 2.0, 複製到檔案用的話希望可以把以下這段 copy 到檔案最前面… XD
# Copyright (c) 2007, Lin Jen-Shin(a.k.a. godfat 真常)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module Kernel
# 由於 google 到的參考程式把抓 call stack 叫 invoker,
# 所以這裡沿用他的名字。有個常數比較容易看懂程式在做什麼。
INVOKER_EVENT = 0
INVOKER_FILE = 1
INVOKER_LINE = 2
INVOKER_MSG = 3
INVOKER_BINDING = 4
INVOKER_CLASS = 5
# -1 就是 top 的意思囉
def invoker levels = -1
st = Thread.current[:callstack]
# st 有可能是 nil, 如果 invoker 先被 call 到的話。
# 雖然我不知道什麼時候會發生這種事…。levels - 2 的原因是:
# 0(stack bottom) => function that you called(this is what we want)
# 1 => Kernel#invoker
# 2 => Array #[]
# 所以去掉額外不要的額外兩個資訊。
st && st[levels - 2]
end
def this
# 因為多 call 了 this, 所以要再多去掉一個額外資訊。
info = invoker(-2)
# 這邊我本來寫成 lambda 的形式,可以正確執行,但有一個狀況
# 卻是失敗的。就是 lambda{yield}.call{} 這樣是會 error 的 :(
# 試了多次還是找不到 Proc.call 吃 block({}) 的方法,只好改寫
# 成用 Method 的形式。不知為何,Method 就可以正確使用 block...
eval("self", info[INVOKER_BINDING]).method(info[INVOKER_MSG])
end
end
set_trace_func lambda{ |*args|
case args[INVOKER_EVENT]
# 可能的有 call 和 c-call, 都是 function
when /call$/
# 這邊我搞不清楚到底是誰會先被 call, 是 call 還是 return?
# google 來的是把初始化寫在 call 裡,可是我測試都顯示是在
# return 上,所以反而是 return 的地方需要初始化。或是乾脆
# 全部拉出來在最上面初始化也可以 :)
(Thread.current[:callstack] ||= []).push args
# 同上可能有 return 和 c-return
when /return$/
(Thread.current[:callstack] ||= []).pop
end
}
以上不管有沒有問題,都可以來看一下我額外寫的幾個 unit test, 參考一下幾個我目前想到的用法。
require 'test/unit'
class TestThis < Test::Unit::TestCase
def test_fact
assert_equal(120, fact(5))
assert_equal(3628800, fact(10))
# 試用 recursive lambda
assert_equal(5040, lambda{|n| return n*this[n-1] if n>0; 1}[7])
end
def fact n
# 恐怕是最常見的用法
return n*this[n-1] if n > 0
1
end
##
def test_pass_around
# 這邊流程可能很怪,因為只是我隨便寫的,單純測試正確性罷了。
assert_equal(method(:pass_around_forward), pass_around.call(lambda{|v| v}))
end
def pass_around mode = 'pass'
case mode
when 'pass'
pass_around_forward this
else
'value'
end
end
def pass_around_forward func
assert_equal('value', func['value'])
this
end
##
def test_with_block
# 同上,流程亂寫的,單純測試正確性。
with_block{|b| assert_equal('value', b['value'])}
end
def with_block mode = 'pass', &block
case mode
when 'pass'
block[this]
else
'value'
end
end
##
def test_more_args
# Proc 就是死在這個測試,block 展開怎麼做都失敗 :(
# 改成 Method 後這邊就可以通過測試了。
more_args('get_this'){}.call('call', 1, 2, 3, 4, 5, λ{6})
more_args('get_this'){}.call('call', 1, 2, 3, 4, 5){6}
end
def more_args mode, a1=nil, a2=nil, a3=nil, *as, &block
case mode
when 'get_this'
this
else
assert_equal(1, a1)
assert_equal(2, a2)
assert_equal(3, a3)
assert_equal(4, as[0])
assert_equal(5, as[1])
assert_equal(nil, as[2])
assert_equal(6, yield)
assert_equal(6, block.call)
end
end
end
最後,我可以把 quine 改寫成:
#!/usr/bin/ruby
require 'rubygems'
require 'ruby2ruby'
require 'invoker'
def f
puts("#!/usr/bin/ruby")
puts
puts("require 'rubygems'")
puts("require 'ruby2ruby'")
puts("require 'invoker'")
puts
print(this.to_ruby)
print("\nf")
end
f
為什麼要用 def f; end 呢??這樣不就失去 this 的意義了??因為不曉得為什麼,Ruby2Ruby 跑 lambda + this 都會有奇怪的 runtime error, 而這個錯誤是來自 class RubyToRuby 的 rewrite_defn(exp), 最後的:「raise "Unknown :defn format: #{name.inspect} #{args.inspect} #{body.inspect}"」這我一時不知道要怎麼解決,不知道會是誰的錯,所以只好暫時用 def f; end 這種蠢方式了。
另外,還有一些無聊的花枝可以玩:
def just_print_it n
print n
this
end
然後就可以:
just_print_it(1)[2][3][4][5]
輸出:12345
def add_attr attr
($attr ||= []).push attr
this
end
add_attr('hello')['world']['and then?']['good-bye']
或是很簡單的流程控制:
def fight step = :ready
case step
when :ready
ready this
when :go
go this
when :finish
finish this
end
end
def ready callback
play_ready_animate
if blah
callback[:go]
else
callback[:finish]
end
cleanup_ready
end
def go callback
gogogo
if blah
callback[:finish]
else
callback[:ready]
end
cleanup_go
end
類推,我也不知道有什麼用,搞不好有什麼 cleanup 是要等所有的事都做完才能做?總而言之,就是這樣啦,沒什麼營養,但我卻覺得很重要的功能。在很多時候可以少打很多字。搞不好哪一天也會想到什麼真的很有價值的應用也說不定。總覺得真的有太多事是無心插柳柳橙汁。雖然大部份都來不及喝就乾掉了。
2007.04.16 godfat 真常
发表评论
-
ludy 0.0.4 released
2007-08-12 17:00 1159花了一點時間再測試了一下 curry 的實做,i am gla ... -
ludy 0.0.3 released
2007-08-07 06:09 1277睽違已久,忽然心血來 ... -
[心得] RubyCocoa
2007-07-25 14:37 1461轉自 ptt MacDev 板作者 godfat (godfa ... -
ruby facets
2007-07-08 14:22 1133老實講,ruby 有一個地方真討厭,那就是每次都把我想做的東西 ... -
心愛的 Object 變心啦
2007-05-15 15:36 886剛剛發現一個很有趣的事情,寫 code 的時候,有兩個 Mod ... -
Struct:簡單的宣告物件方式
2007-04-04 03:08 1274在 PHP 裡面,很多時候我們會用到 Hash 來傳遞變數,像 ... -
class 與 instance
2007-03-27 12:28 1162不知道為何,最近不管是私事或公事似乎都很多。造成的結果就是很多 ... -
Gentoo 上面跑 DRB 可能出現的問題
2007-03-21 13:35 1173有時候在 Gentoo 上面使用一些有關 DRB 的東西,像是 ... -
SWIG/Ruby
2007-03-18 07:36 1772以下文章最早發表於 200 ... -
why scripting?
2007-03-16 15:00 1093why scripting?簡單一句話就是:「為了增進生產力」 ... -
為啥我得升級 Ruby 1.8.6
2007-03-16 16:11 1200為什麼我得升級 Ruby 1.8.6?會跟 Rails 衝突, ... -
Ruby 1.8.6 Release:要升級請三思
2007-03-13 14:29 1091今天早上宣布的,想看詳細情形,或是下載 Source 請看這裡 ... -
M$ 也加入 Ruby 這個大戰場了嗎?
2007-02-25 09:04 1188InfoWorld 上面有消息指出,M$ 對 Ruby 這個程 ... -
Ruby on PSP?
2007-02-03 04:06 1186DSCN0841Originally uploaded ... -
[轉錄] 世界喜愛 Ruby 的理由 - 專訪松本行弘(摘要)
2007-01-06 03:26 1340這是日経 BP主辦的「次世代開發論壇」時的訪談 Matz (R ...
相关推荐
标题"Recursive_recursive_"和描述"Introduction to recursive programming"都指向了递归编程的主题,这是计算机科学中的一个核心概念。下面我们将深入探讨递归编程的基础、原理以及如何在实际编程中应用。 递归的...
postgre sql recursive sql. 在postgoresql 中使用recursive的脚本实现循环查询结果
In this book, hyperarithmetic theory is developed at length and used to lift classical recursion theory from integers to recursive ordinals (metarecursion). Two further liftings are then made, first ...
"mkdir-recursive" 是一个专门针对这种情况的开源库,它提供了在前端环境中实现递归创建或删除目录的功能,无论是异步还是同步方式。这个库对于那些需要在用户浏览器上进行本地存储或者模拟服务器端文件操作的应用...
`laravel-recursive-collection`是一个专为解决此类问题设计的包,它扩展了Laravel的内置集合(Collections)类,允许开发者以更优雅的方式对嵌套数组和关联数组进行迭代和转换,生成嵌套的集合对象。 一、Laravel...
这就是`recursive-watch`库的作用,它提供了一个最小化的递归文件监视器,可以监测指定目录及其子目录下的文件变化。 **一、安装与使用** 在你的项目中,你可以通过npm(Node.js的包管理器)来安装`recursive-...
本资源"recursive.rar"包含了关于如何将递归函数转换为非递归函数的方法,以及使用Python语言编写的示例代码,旨在帮助开发者理解这一转换过程,并对比不同实现方式的执行效率。 递归函数的主要特点在于它会将大...
Theory.of.Recursive.Functions
Introduction to Recursive Programming 英文azw3 本资源转载自网络,如有侵权,请联系上传者或csdn删除 本资源转载自网络,如有侵权,请联系上传者或csdn删除
Introduction to Recursive Programming 英文epub 本资源转载自网络,如有侵权,请联系上传者或csdn删除 本资源转载自网络,如有侵权,请联系上传者或csdn删除
Recursive Methods in Economic Dynamics.Stokey.Lucas
Recursive Mathematics - Volume 1 Recursive Model TheoryRecursive Mathematics - Volume 1 Recursive Model TheoryRecursive Mathematics - Volume 1 Recursive Model Theory
本压缩包文件"Recursive-Gaussian-filter.rar_recursive gaussian"包含了基于OpenCV库实现的递归高斯滤波器代码,文件名为"opencv.cpp"。 首先,我们要理解高斯滤波器的工作原理。高斯滤波器是基于二维高斯函数的...
Recursive Projection Clustering(RPC)是一种在机器学习领域中用于数据聚类的算法,它结合了投影和递归的思想,旨在发现数据集中的潜在结构。RPC 方法以其独特的方式处理高维数据,试图找到能够最好地区分不同类别...
《Super-Recursive Algorithms》这本书深入探讨了C++编程语言中的超级递归算法,这是一类在计算理论和算法设计中至关重要的技术。超级递归不仅仅是简单的递归调用,它涉及到了更复杂的数学和计算机科学概念,如元...
Recursion is one of the most fundamental concepts in computer science and a key programming technique that, similarly to iteration, allows computations to be carried out repeatedly
"Recursive LS - Recursive Search" 是一个开源项目,其主要功能是提供一个跨平台的递归文件搜索库。这个库的设计目标是为了在各种操作系统上高效地查找指定目录及其子目录下的文件,而无需依赖特定的系统API。项目...
In this book, hyperarithmetic theory is developed at length and used to lift classical recursion theory from integers to recursive ordinals (metarecursion). Two further liftings are then made, first ...
在图像插帧领域中对真实运动向量进行估计的算法,此算法较为经典,3DRS