Pergunta

O que há de errado no código?

def call_block(n)

  if n==1

    return 0
  elsif n== 2

    return 1
  else
    yield
    return call_block(n-1) + call_block(n-2)

  end

end


puts call_block(10) {puts "Take this"}

Estou tentando usar o rendimento para imprimir, pegue isso além do décimo número de Fibonacci.

Estou recebendo o erro: em `call_block ': nenhum bloco dado (localjumperror)

Até o código seguinte lança erro:

def call_block(n)

  if n==1
    yield
    return 0
  elsif n== 2
    yield
    return 1
  else
    yield
    return call_block(n-1) + call_block(n-2)

  end

end


puts call_block(10) {puts "Take this"}
Foi útil?

Solução

Você pode querer usar esta linha, como Adam Vandenberg dicas:

return call_block(n-1) { yield } + call_block(n-2) { yield }

Outras dicas

Primeiro, vamos limpar um pouco isso para que seja mais fácil ver o que está dando errado:

def call_block(n)
  return 0 if n == 1
  return 1 if n == 2

  yield

  call_block(n-1) + call_block(n-2)
end

puts call_block(10) { puts 'Take this' }

Agora vamos apenas rastreá -lo.

Começamos ligando

call_block(10) { puts 'Take this' }

Então, n é 10 e o bloco é {puts 'Take This'}. Desde n não é nenhum 1 nem 2, chegamos ao yield, que transfere o controle do bloco.

Agora estamos ligando

call_block(n-1)

qual é

call_block(9)

Observe que não estamos chamando isso com um bloco. Então, para esta nova chamada, n é 9 E não há bloco. Novamente, pulamos as duas primeiras linhas e chegamos ao yield.

Mas não há bloqueio para yield Para, e é por isso que o código explode aqui.

A solução é óbvia e sutil. A parte óbvia é: o problema é que não estamos passando um bloco, portanto, a solução é que precisamos passar o bloco. A parte sutil é: como fazemos isso?

O que torna os bloqueios de rubi tão sintaticamente leves é que eles são anônimos. Mas se o bloco não tiver um nome, não podemos nos referir a ele e, se não pudermos nos referir a ele, não podemos transmiti -lo.

A solução para isso é usar outro construto em Ruby, que é basicamente uma abstração mais pesada para a idéia de "um pedaço de código" do que um bloco: um Proc.

def call_block(n, blk)
  return 0 if n == 1
  return 1 if n == 2

  blk.()

  call_block(n-1, blk) + call_block(n-2, blk)
end

puts call_block(10, ->{ puts 'Take this' })

Como você pode ver, este é um pouco mais pesado sintaticamente, mas podemos dar o Proc um nome e, assim, transmiti -lo às chamadas recursivas.

No entanto, esse padrão é realmente comum o suficiente para que haja apoio especial em Ruby para ele. Se você colocar um & Sigil na frente de um nome de parâmetro em uma lista de parâmetros, Ruby "empacotará" um bloco que é passado como um argumento em um Proc Objeto e vincule -o a esse nome. E por outro lado, se você colocar um & sigil diante de uma expressão de argumento em uma lista de argumentos, ele "descompactará" que Proc em um quarteirão:

def call_block(n, &blk)
  return 0 if n == 1
  return 1 if n == 2

  yield # or `blk.()`, whichever you prefer

  call_block(n-1, &blk) + call_block(n-2, &blk)
end

puts call_block(10) { puts 'Take this' }

Isso é por causa da chamada recursiva ao método call_block sem passar em um bloco. Uma maneira de fazer isso seria:

def call_block(n, &blk)
    if n == 1
        return 0
    elsif n == 2
        return 1
    else
        blk.call()
        return call_block(n-1, &blk) + call_block(n-2, &blk)
    end
end

puts call_block(4) {puts "Take this"}

Editar: devo admitir que a solução Postado por Justice parece mais lógico.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top