3

我开始熟悉 Ruby 并遇到了一个以前从未见过的函数—— callcc
我已经了解了它的用途,但是当我尝试编写一个示例时,我得到了意想不到的结果。

require 'continuation'
def callcc_func
  i = 0
  while true
    c = nil
    callcc {|x| c = x}
    i += 1
    puts i    
    return c if (i % 3) == 0
  end
end

c = callcc_func()
puts
callcc_func.call

结果是无限循环。为什么?
我预计会是:

# for `c = callcc_func()` line
1
2
3

# callcc_func.call
4
5
6
#end here because of `return c if (i % 3) == 0`

PS
对不起我的英语,谢谢。

4

2 回答 2

2

这个答案有点晚了,但也许有人会感兴趣。

您只需将代码的最后一行更改为:

c.call

此功能的应用之一是制作发电机。这是示例随机数生成器(取自 Numerical Recipies 书中的常量):

def randomLCG(a,m,c,seed)
    initialized = false
    while true
        callcc {|x| $cc = x}
        if not initialized
            initialized = true
            return
        end
        seed = (a*seed + c) % m;
        return seed
    end
end

和用法:

> randomLCG( 1664525, 2147483647 , 1013904223, 107 )
 => nil 
> $cc.call
 => 1192008398 
> $cc.call
 => 2079128816 
> $cc.call
 => 667419302 

在 Python 中,我们可能会使用关键字yield来实现相同的目标(请注意,在 Ruby 中关键字yield会做不同的事情):

def randLCG (a , m , c , seed):
    while True:
        seed = ( a∗seed + c ) % m
        yield seed

用法:

>>> random = randLCG ( 1664525 , 2147483647 , 1013904223, 107 ) 
>>> random
<generator object randLCG at 0x7fdc790f70a0>
>>> random.next()
1192008398
>>> random.next()
2079128816
>>> random.next()
667419302

Ofc 在 Ruby ofc 中你可以使用闭包来解决这个问题,这样你的程序会更短:

require 'continuation'

def rand(a, m, c, seed)
    return lambda{ seed = (a*seed + c) % m; return seed }
end

c = rand( 1664525, 2147483647 , 1013904223, 107 )
c.call
c.call

我想到的第二个用法是实现mutual recursions

于 2014-07-21T13:56:56.977 回答
1

call-with-current-continuation(通常缩写为call/cc起源于 Scheme,所以如果您想了解更多信息,Scheme 文档是一个很好的起点:

至于您的 Ruby 问题:请查看此博客文章标题Continuations 和 ruby​​ ,它实现了与您正在尝试做的非常相似的事情。你会在那里找到解释:

作为由主 ruby​​ 解释器运行的脚本文件,这将循环 forerver,因为它捕获程序在何时何地被调用的控制状态,这包括返回延续,然后再次调用它。

于 2012-05-16T10:04:44.770 回答