yin-杨puzzle in Ruby

Yin-yang puzzle in Ruby

为了尝试更多地了解 call/cc,我看到了 How does the yin-yang puzzle work? question and this explaination 阴阳谜题:

(let*
    (
        (yin (
            (lambda (cc) (display #\@) cc)
            (call/cc (lambda (c) c))
        ))
        (yang (
            (lambda (cc) (display #\*) cc)
            (call/cc (lambda (c) c))
        ))
    )
    (yin yang)
)

到目前为止,我可能(或可能不)理解阴阳谜题的概念。但是我发现scheme的语法不是特别好懂,一查发现ruby有Continuation模块。由于 ruby 语法遵循程序风格,我发现 ruby 代码比方案代码更容易阅读。因此,我决定将拼图翻译成 ruby 版本(我在 scheme 和 ruby 方面都是新手):

require "continuation"

yin = (lambda do |cc|
    print "@"
    return cc
end).call(callcc {|c| c})

yang = (lambda do |cc|
    print "*"
    return cc
end).call(callcc {|c| c})

yin.call(yang)

但是这个版本打印出 @*@***********... (demo here) 而不是 @*@**@***@****@*****@**...,这不是我所期望的。

我的 ruby 版本正确吗?如果它不正确,那么我真的不知道从这里该做什么...

我认为你的问题 yinyang 将变成 Continuation 并且它们不会一起调用,而只有 yang 嵌套在 yin 中。

yin = (lambda do |cc|
  print "@"
  return cc # (3) return Continuation (1)
end).call(callcc {|c| c}) # (1) this params call first

# (2) lambda will call immediately -> print the first @
# so yin = Continuation (1)

yang = (lambda do |cc|
  print "*"
  return cc # (6) return Continuation (4)
end).call(callcc {|c| c}) # (4) this params call first *

# (5) lambda will call immediately -> print the first *
# so yang = Continuation (4)

yin.call(yang)

现在我们可以按如下方式解释您的代码

yin = callcc {|c| c} # yin context
  print '@'
  yang = callcc {|cc| cc} # yang context
    print '*'
    yin.call(yang)
  # end yang context
# end yin context

如你所见,在第一次调用(第二个@和*)后,最后一行yin.call(yang)将继续调用yang yang ( * yang ( * yang ( ...,如果你替换为yin.call(yin),输出将是 @*@*@*@*...

最后,这是我的解决方案,想法是 yinyang 将嵌套在一起,下一个 yang 将包含上一个 yin + ' *' 和下一个 yin 将包含前一个 yang + '@'

require "continuation"

yin = lambda { |yang|
  cc = callcc { |cc| cc }
  print "@"
  yang.call(cc)
}
  
yang = lambda { |yin|
  cc = callcc { |cc| cc }
  print "*"
  yin.call(cc)
}

yin.call(yang)