• Revista PROGRAMAR: Já está disponível a edição #53 da revista programar. Faz já o download aqui!

pedrotuga

Algumas perguntas sobre blocos para os programadores de ruby

10 mensagens neste tópico

Isto quando se aprende uma linguagem e se lê algures que qualquer coisa é uma das características mais únicas e mais poderosas, frquentemente o que isso quer dizer na verdade é que se trata de uma coisa esquisita e com formato ou aspecto pouco natural. Vamos aqui ver uns exemplos simples:

irb(main):019:0* Array(1..3).each do |a|
irb(main):020:1* puts "eu digo #{a}"
irb(main):021:1> end
eu digo 1
eu digo 2
eu digo 3
=> [1, 2, 3]

Ok, funciona, yay! Eu posso desde já apontar algumas coisas que não gosto: tenho que chamar o método each para me devolver um Enumerable. Adicionalmente tenho que saber o nome desse método e o que ele devolve.

Pergunta 1:

Dada um objecto de uma classe qualquer, como é que sabem qual o método para obter um enumerable ou se sequer existe?

Outro exemplo:

irb(main):022:0> 3.times do |a|
irb(main):023:1* puts a
irb(main):024:1> end
0
1
2
=> 3
irb(main):025:0> 

Tambem posso obter um enumerable de um inteiro, mas tenho que saber qual é o método que mo devolve. Neste caso tem outro nome.

Mas há mais:

irb(main):036:0> comida.each do |a,b|
irb(main):037:1* puts "#{a} é #{b}."
irb(main):038:1> end
fruta é saudavel.
chocolate é mau.
=> {"fruta"=>"saudavel", "chocolate"=>"mau"}
irb(main):039:0> 

Uau, tambem funciona com hashes, fixe!

Espera aí... vamos lá ver melhor:

irb(main):039:0> comida.each do |a|
irb(main):040:1* puts a
irb(main):041:1> end
fruta
saudavel
chocolate
mau

aaa... isto é um pouco estúpido... deita tudo cá para fora à bruta para alem de que o primeiro argumento do bloco é inconsistente entre este últimos dois casos. No exemplo anterior contem a chave (não fazia mais sentido o conteudo?) e neste exemplo contem uma mistura de chaves e conteudos.

O que quer dizer que o programador tem obrigatoriamente que saber os parâmetros TODOS.

Pergunta 2:

Dado um objecto iterable como é que sabem os seus atributos?

Eu sou um zé ninguem comparado com o pessoal que escreve linguagens de programação. Mas isto não é um pouco misturar a sintaxe de uma linguagem com algumas classes que vêm com o ruby?

Tomemos como contra-exemplo o python. Toda a funcionalidade está no object model. Se se quiser implementar uma determinada funcionalidade numa classe, então implementa-se um dos métodos existentes para o efeito. Seja iteração, seja a forma como ele responde a determinado operador ou a qualquer operação.

Do ponto de vista do programador eu acho que isto é mais consistente. Se um objecto faz uma coisa que é suposto fazer, então essa coisa tem um nome que todos sabemos qual é como funciona.

O duck typing é outro caso, essa discussão ficará para outra dia.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Eu não pesco nada de Ruby portanto posso estar a dizer altas bacuradas. Fica desde já o aviso..

Isto quando se aprende uma linguagem e se lê algures que qualquer coisa é uma das características mais únicas e mais poderosas, frquentemente o que isso quer dizer na verdade é que se trata de uma coisa esquisita e com formato ou aspecto pouco natural.

O que não quer dizer que realmente não seja poderoso. E se é algo inovador é normal que seja esquisito, se não fosse esquisito é porque já existe e então não seria inovador :)

irb(main):019:0* Array(1..3).each do |a|
irb(main):020:1* puts "eu digo #{a}"
irb(main):021:1> end
eu digo 1
eu digo 2
eu digo 3
=> [1, 2, 3]

Ok, funciona, yay! Eu posso desde já apontar algumas coisas que não gosto: tenho que chamar o método each para me devolver um Enumerable. Adicionalmente tenho que saber o nome desse método e o que ele devolve.

O método each não te devolve um enumerable. Esse método permite-te executar um bloco de código para cada elemento do array. Não estou a perceber o problema. Preferias desta forma? (linguagem fictícia)

foreach a in Array(1..3) do
   puts "eu dito #{a}"
end

Existem milhares de linguagens com esta funcionalidade. É exactamente a mesma coisa. Bem não é exactamente a mesma coisa, no 1º caso a funcionalidade está presa ao tipo do objecto enquanto no 2º caso a funcionalidade ta presa à linguagem. Ou seja, a 1º versão é muito mais poderosa, porque permite-te, como programador brincar com ela.

Pergunta 1:

Dada um objecto de uma classe qualquer, como é que sabem qual o método para obter um enumerable ou se sequer existe?

Apenas de 3 formas.

1 - Vais ver o código

2 - Vais ler a documentação

3 - Metes a chamar o método e corres a aplicação e vez se explode

Normalmente o pessoal usa a 3ª. Bem vindo ao mundo da tipagem dinâmica :D

Outro exemplo:

irb(main):022:0> 3.times do |a|
irb(main):023:1* puts a
irb(main):024:1> end
0
1
2
=> 3
irb(main):025:0> 

Tambem posso obter um enumerable de um inteiro, mas tenho que saber qual é o método que mo devolve. Neste caso tem outro nome.

Mais uma vez, não obtens um enumerable. Se calhar a principal confusão está aí. times é apenas um método que te permite fazer um ciclo com x interacções. times é tipo a função range de python, as principais diferenças é:

- o range é uma função e não um método

- o range devolve um enumeravel em que depois podes percorrer como quiseres, enquanto o times é para percorrer esse suposto enumeravel (que nunca é criado)

Mas há mais:

irb(main):036:0> comida.each do |a,b|
irb(main):037:1* puts "#{a} é #{b}."
irb(main):038:1> end
fruta é saudavel.
chocolate é mau.
=> {"fruta"=>"saudavel", "chocolate"=>"mau"}
irb(main):039:0> 

Uau, tambem funciona com hashes, fixe!

Espera aí... vamos lá ver melhor:

irb(main):039:0> comida.each do |a|
irb(main):040:1* puts a
irb(main):041:1> end
fruta
saudavel
chocolate
mau

aaa... isto é um pouco estúpido... deita tudo cá para fora à bruta para alem de que o primeiro argumento do bloco é inconsistente entre este últimos dois casos. No exemplo anterior contem a chave (não fazia mais sentido o conteudo?) e neste exemplo contem uma mistura de chaves e conteudos.

Não percebi. Que queres dizer com o 1º exemplo conter e chave em vez do conteúdo?

O que quer dizer que o programador tem obrigatoriamente que saber os parâmetros TODOS.

Não tem de saber sempre?

Pergunta 2:

Dado um objecto iterable como é que sabem os seus atributos?

Não percebi. Que queres dizer com os seus atributos?

Eu sou um zé ninguem comparado com o pessoal que escreve linguagens de programação. Mas isto não é um pouco misturar a sintaxe de uma linguagem com algumas classes que vêm com o ruby?

Tomemos como contra-exemplo o python. Toda a funcionalidade está no object model. Se se quiser implementar uma determinada funcionalidade numa classe, então implementa-se um dos métodos existentes para o efeito. Seja iteração, seja a forma como ele responde a determinado operador ou a qualquer operação.

Do ponto de vista do programador eu acho que isto é mais consistente. Se um objecto faz uma coisa que é suposto fazer, então essa coisa tem um nome que todos sabemos qual é como funciona.

Não percebi. Não é a mesma coisa em Ruby? Todos sabem que se quer iterar elemento a elemento usa-se a função each.
0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

O método each não te devolve um enumerable. Esse método permite-te executar um bloco de código para cada elemento do array. Não estou a perceber o problema. Preferias desta forma? (linguagem fictícia)

Estás enganado. O método each, devolve um Enumerable como podes ver aqui.

O int.times tambem devolve um enumerable, e muitos outros métodos de muitas outras classes o fazem, só acho que isso tem pouca utilidade pois tens que saber o nome deles de cor e chama-los explicitamente.

irb(main):013:0> Array(0..9).each
=> #<Enumerable::Enumerator:0xb7c50a28>

O que faz o ciclo não é o 'each'. É o 'do', se o 'do' receber um Enumerable então executa o bloco enquanto puder iterar. O 'do' é um pouco como uma função lambda misturada com um mapeamento como o map do python.

De resto o código que escreveste até é ruby válido como podes ver. Lol :)

irb(main):017:0> for i in Array(0..9)
irb(main):018:1> puts i
irb(main):019:1> end
0
1
2
3
4
5
6
7
8
9
=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
irb(main):020:0> 

Só que aqui não tens que chamar o iterador. E com isto já estou a responder a mim próprio porque andei a ler mais sobre iteradores e afinal o 'for', pelo que percebi usa precisamente o método 'each'. Pelo que podemos implementar iteradores tal como em python e usar sempre o for.

Ou seja... já estou um pouco a responder a mim próprio. O ruby vem ronto para suportar mais do que um tipo de iteração na mesma classe e usa-los facilmente. Mas para todos os efeitos, o iterador que é chamado por defeito pelo for é o 'each'. Pelo menos foi isso que percbi da documentação que por aí anda.

Assim sendo não é a linguagem que é esquisita, os programdores de ruby é que são zealots ao ponto de usar sempre blocos para uma coisa que deve ser deixada para um 'for'. Os blocos servem para outra coisa, nomeadamente para passar funções como parâmetros para um bloco.

Mas isso tambem já não me surpreende, os programadores de python tambem estão sempre a usar funções lambda onde podiam usar uma função normal.

O que eu não tinha percebido (e há muito pouco código escrito dessa forma por aí) é que o ruby suporta um iterador genérico que pode ser usado em qualquer lado, é o método com o nome 'each'.

Em relação à segunda pergunta e aos exemplos que dei. Aí tens um exemplo de dois casos em que se devia iterar usando um ciclo for e não usando o completo overkill do blocos que nem sequer servem para isto.

O que aconteceu foi que, no primeiro exemplo, o primeiro parâmetro passado ao bloco vai atirar para dentro do bloco tantos atributos quantos a função que está antes do bloco lhe enviar. O que quer dier que dentro do bloco tens que saber exactamente quantos e quais atributos são enviados. Se acrescentares outro parâmetro ao bloco (entre os ||) vais estar a interferir com o primeiro parâmetro e por conseguinte o código todo do bloco passará a ser inválido.

Se reparares, no primeiro exemplo o 'a' quer dizer uma coisa, mas no segundo já quer dizer outra.

Se usares simplesmente um ciclo 'for', esse problema nem se coloca. Em resumo, usar um bloco para fazer um simples ciclo é misturar iteração com mapeamento desnecessariamente e resulta em código menos reusável.

Adicionalmente, acho que não faz muito sentido Hash.each devolver as chaves e os conteudos tudo ao molho, mas isso lá terei que me habituar.

Não percebi. Não é a mesma coisa em Ruby? Todos sabem que se quer iterar elemento a elemento usa-se a função each.

Quanto a isto, sim. De facto é. Eu é que ainda não tinha percebido isso.

E vou por as culpas ao livro da colecção 'pragmatic programmers bookshelf' que não só falha em referir isso como induz o leitor em erro com esta bacorada:

A Ruby iterator is simply a method that can invoke a block of code. At first sight, a block in Ruby looks just like a block in C, Java, or Perl. Unfortunately, in this case looks are deceiving---a Ruby block is a way of grouping statements, but not in the conventional way.

...NOT! Não é isso que é um iterador. Um iterador não é um output mapeável.

Na verdade, como tu disseste e bem, o iterador é o método 'each', era isso que deviam ter dito.

Li isso aqui:

http://www.rubycentral.com/book/tut_containers.html

Não leam esse livro.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

O método each não te devolve um enumerable. Esse método permite-te executar um bloco de código para cada elemento do array. Não estou a perceber o problema. Preferias desta forma? (linguagem fictícia)

Estás enganado. O método each, devolve um Enumerable como podes ver aqui.

O int.times tambem devolve um enumerable, e muitos outros métodos de muitas outras classes o fazem, só acho que isso tem pouca utilidade pois tens que saber o nome deles de cor e chama-los explicitamente.

irb(main):013:0> Array(0..9).each
=> #<Enumerable::Enumerator:0xb7c50a28>

O que faz o ciclo não é o 'each'. É o 'do', se o 'do' receber um Enumerable então executa o bloco enquanto puder iterar. O 'do' é um pouco como uma função lambda misturada com um mapeamento como o map do python.

Não. Estás equivocado. O 'each' é quem faz o ciclo e para cada iteração invoca a execução do bloco delimitado pelo 'do'. O 'do' só serve mesmo para isso para delimitar um bloco de código.

Tu ao averiguares o Array.each e obteres esse resultado é porque não lhe deste um bloco de código, então a execução do ciclo fica pendente (penso eu), daí estar a indicar o endereço de memória do enumerable (que é criado internamente pelo each), porque ele precisa do bloco de código para executar.

Mas se fores comparar com python, o 'each' é o 'map' e o 'do' é o 'lambda'. A diferença é que o map é built-in enquanto o each é um método de um objecto e que o map aceita mais do que uma enumeração.

De resto o código que escreveste até é ruby válido como podes ver. Lol :P

Eu sei, eu só tinha deixado o foreach para a sintaxe ficar semelhante :P

Assim sendo não é a linguagem que é esquisita, os programdores de ruby é que são zealots ao ponto de usar sempre blocos para uma coisa que deve ser deixada para um 'for'. Os blocos servem para outra coisa, nomeadamente para passar funções como parâmetros para um bloco.

Não é serem zealots. Zealots é um termo muito pesado e refere-se aquelas pessoas que não veem mais nada que a linguagem preferida deles (tipo eu com Haskell :(). Neste caso particular em relação ao Ruby, os programadores usam os blocos porque é essa a filosofia da linguagem. Bem, e é um conceito poderoso, não esqueçamos disso. Por exemplo, apesar de não ser a mesma coisa é parecido. Lembrei-me de um post meu antigo que tinha haver com esta área. Fazer o que fiz em Ruby é bastante fácil (como é em Haskell) porque as funcionalidades de controlo da linguagem não são built-ins mas sim como outros elementos naturais da linguagem. Em Haskell são funções normais, em Ruby são métodos.

Em relação à segunda pergunta e aos exemplos que dei. Aí tens um exemplo de dois casos em que se devia iterar usando um ciclo for e não usando o completo overkill do blocos que nem sequer servem para isto.

O que aconteceu foi que, no primeiro exemplo, o primeiro parâmetro passado ao bloco vai atirar para dentro do bloco tantos atributos quantos a função que está antes do bloco lhe enviar. O que quer dier que dentro do bloco tens que saber exactamente quantos e quais atributos são enviados. Se acrescentares outro parâmetro ao bloco (entre os ||) vais estar a interferir com o primeiro parâmetro e por conseguinte o código todo do bloco passará a ser inválido.

Se reparares, no primeiro exemplo o 'a' quer dizer uma coisa, mas no segundo já quer dizer outra.

Se usares simplesmente um ciclo 'for', esse problema nem se coloca. Em resumo, usar um bloco para fazer um simples ciclo é misturar iteração com mapeamento desnecessariamente e resulta em código menos reusável.

Adicionalmente, acho que não faz muito sentido Hash.each devolver as chaves e os conteudos tudo ao molho, mas isso lá terei que me habituar.

Se usares o for o problema coloca-se na mesma. Acontece exactamente a mesma situação.

O link que puzeste, faz referencia a esse problema.

Although it is common to pass just one value to a block, this is not a requirement; a block may have any number of arguments. What happens if a block has a different number of parameters than are given to the yield? By a staggering coincidence, the rules we discuss under parallel assignment come into play (with a slight twist: multiple parameters passed to a yield are converted to an array if the block has just one argument).

Parameters to a block may be existing local variables; if so, the new value of the variable will be retained after the block completes. This may lead to unexpected behavior, but there is also a performance gain to be had by using variables that already exist.[For more information on this and other ``gotchas,'' see the list beginning on page 127; more performance information begins on page 128.']

A Ruby iterator is simply a method that can invoke a block of code. At first sight, a block in Ruby looks just like a block in C, Java, or Perl. Unfortunately, in this case looks are deceiving---a Ruby block is a way of grouping statements, but not in the conventional way.

E vou por as culpas ao livro da colecção 'pragmatic programmers bookshelf' que não só falha em referir isso como induz o leitor em erro com esta bacorada:

...NOT! Não é isso que é um iterador. Um iterador não é um output mapeável.

Na verdade, como tu disseste e bem, o iterador é o método 'each', era isso que deviam ter dito.

Não percebo. Eu acho que o livro está correcto. Um iterador em Ruby é um método em que mandas-lhe um bloco de código a indicar o que fazer em cada iteração. Mas essa citação estão a dar mais destaque ao bloco do que ao iterador, a realçar que o bloco de código não é como um bloco de código numa outra linguagem. E na realidade não é, em Ruby é mais estilo uma função anónima, que poderá ser executada n vezes com o seu próprio scope.

E o iterador não é o 'each'. O 'each' é um dos mais habituais mas não é o único. Aliás o Ruby confere o poder e a liberdade de uma pessoa poder fazer os nossos próprios iteradores. Algo muito nice que o Ruby herdou de Smalltalk. O link que puzeste até tem mais à frente um exemplo muito fixe. Basicamente criaram uma função que permite iterar sobre os números de fibonnaci. Tinha mais lógica fazerem antes como um método para os inteiros tornado o código mais elegante, mas presumo que no livro ainda seja cedo para falar de adicionar métodos às classes.

E em relação a essa mini-fúria com o livro, mais abaixo o livro realça o 'each'.

Some iterators are common to many types of Ruby collections. We've looked at find already. Two others are each and collect. each is probably the simplest iterator---all it does is yield successive elements of its collection.
0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Betovsky, estou a concordar contigo, excepto nessa parte final.

O problema é que essa definição de iteração é pobre porque um bloco só vai iterar se redeber um Enumerable.

Tipo... Olhar para estes exemplos depis dessa definição deixa um gajo assim um pouco tipo WTF?

irb(main):004:0> Array(0..9) do |a|
irb(main):005:1* puts a
irb(main):006:1> end
=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
irb(main):007:0> Array(0..9).each do |a|
irb(main):008:1* puts a
irb(main):009:1> end
0
1
2
3
4
5
6
7
8
9
=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
irb(main):010:0> 

Quero dizer... há coisa mais óbvia deva ser iterável do que um array?

Eu acho que o livro não está correcto porque um método que possa enviar valores para um bloco... isso é qualquer método. Envia sempre alguma coisa, nem que seja nil.

Acho que deviam ter dito que é um método que possa enviar um Enumerable.

De qualquer das formas... se não fosse esta discussão já me tinha passado muita coisa ao lado.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Não. O bloco não recebe nenhum enumerável. O bloco só recebe um item de cada vez (ou mais, depende do nº de argumentos).

É como dizeres que a função lambda em python no map recebe um enumerável.

Um método não envia sempre alguma coisa. O facto de passares um bloco de código para um método não indica que esse bloco vá ser executado. O teu primeiro exemplo demonstra isso mesmo. O bloco só será executado se o método que o recebe alguma vez evocar o yield. Se não evocar o yield o bloco de código nunca será executado.

Basicamente posto, para um método ser um iterador tem de evocar yields, o Array não é um iterador, não evoca yields, logo o bloco nunca irá ser executado.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Não sei se estou a perceber... podes dar um exemplo?

Tipo... se eu quiser implementar um iterador que peque numa string percorra caracteres de dois em dois como faria?

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Penso que seria algo tipo:

class String
   def each2
      for i in 0..(size/2 - 1)
         c1 = self[i*2,1]
         c2 = self[i*2+1,1]
         yield c1, c2
      end
   end
end

a = "1234567890"

a.each2 do |x,y|
  puts "#{x} - #{y}"
end

Não sei muito de Ruby. É bem provável que exista uma maneira melhor.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Boas,

tenho que chamar o método each para me devolver um Enumerable

O metodo each não devolve nenhum Enumerable. Normalmente quando se chama o metodo each, é para iterar sobre o objecto, e passamos também um bloco. O metodo each depois vai iterar sobre os valores do objecto, chamando o yield com cada valor.

irb(main):013:0> Array(0..9).each
=> #<Enumerable::Enumerator:0xb7c50a28>

Se chamares o metodo each sem passar nenhum bloco, coisa que acho que não faz muito sentido, ele retorna um Enumerator. Os Enumerators para funcionarem precisam do metodo each definido, como podes ver neste exemplo:

irb(main):001:0> require 'enumerator'
irb(main):002:0> a = [1,2]
irb(main):003:0> def a.each
irb(main):004:1>    puts "bye bye"
irb(main):005:1> end
irb(main):006:0> a.to_enum.each { }
bye bye
=> nil
irb(main):007:0> a.to_enum.map { }
bye bye
=> []

Adicionalmente tenho que saber o nome desse método e o que ele devolve.

Isso é como dizer que tens que saber que o for serve para iterar. Se não gostas do each podes optar por não usa-lo. O que é interessante do each é que é um metodo como outro qualquer, sendo possivel muda-lo, fazer override dele, etc. Mas atenção, se realmente usares o for, ele utiliza o metodo each para iterar sobre o elemento:

irb(main):009:0> for i in a
irb(main):010:1>   puts i
irb(main):011:1> end
bye bye
=> nil

Em em relação àquilo que o each devolve, ao ver o código do Array de Rubinius (http://github.com/evanphx/rubinius/blob/6536694b26a0021726e3785d5b245d7a8503f559/lib/1.8.7/array.rb) dá para ver que no fim é devolvido o próprio objecto. Normalmente ignora-se o retorno, mas ao menos temos essa hipotese.

Tambem posso obter um enumerable de um inteiro, mas tenho que saber qual é o método que mo devolve. Neste caso tem outro nome.

Como no each, no times não obtens nenhum Enumerable. O metodo times é um metodo normal, que pega no número dado e vai até zero, passando cada valor intermédio ao bloco fornecido.

Como é dito no Pickaxe:

Similarly, many looping constructs that are built into languages such as C and Java are simply method calls in Ruby, with the methods invoking the associated block zero or more times.

Podes usar os loops de while e outros loop constructs que ruby fornece. É contigo, mas eu prefiro fazer:

0.upto(4) { |i| puts i }

Do que:

i = 0
while i < 5 do
   puts i
   i += 1
end

Talvez era bem pensado leres mais coisas sobre como o Enumerator funciona e que funcionalidades ele fornece(map, inject, etc.) ao definires o metodo each para um objecto: http://www.ruby-doc.org/docs/ProgrammingRuby/html/ref_m_enumerable.html

irb(main):039:0> comida.each do |a|
irb(main):040:1* puts a
irb(main):041:1> end
fruta
saudavel
chocolate
mau

aaa... isto é um pouco estúpido... deita tudo cá para fora à bruta para alem de que o primeiro argumento do bloco é inconsistente entre este últimos dois casos. No exemplo anterior contem a chave (não fazia mais sentido o conteudo?) e neste exemplo contem uma mistura de chaves e conteudos.

O que quer dizer que o programador tem obrigatoriamente que saber os parâmetros TODOS.

Desculpa, mas o problema está no teu exemplo e não em Ruby. O each numa Hash chama um bloco que aceita 2 argumentos: a chave e o valor correspondente. Se só quiseres as chaves, usa each_key. Se só quiseres os valores, usa each_value. Até podias usar hash.keys.each e hash.values.each. Mas usares um bloco que só aceita um argumento com Hash#each é errado.

Não sei porquê é que esse exemplo não dá nenhum warning, mas repara neste:

irb(main):018:0> def test
irb(main):019:1>   yield 1,2
irb(main):020:1> end
=> nil
irb(main):021:0> test { |i| puts i }
(irb):21: warning: multiple values for a block parameter (2 for 1)
from (irb):19
1
2
=> nil

Mas se fores comparar com python, o 'each' é o 'map' e o 'do' é o 'lambda'. A diferença é que o map é built-in enquanto o each é um método de um objecto e que o map aceita mais do que uma enumeração.

Acho que essa comparação não é a mais correcta. O map do python (http://docs.python.org/tutorial/datastructures.html#functional-programming-tools) parece muito semelhante ao map que o Enumerator fornece em Ruby (http://www.ruby-doc.org/core/classes/Array.html#M002189). O do...end e {...} servem para delimitar blocos. Não conheco bem o Python, mas não sei se o 'do' é o 'lambda', porque, presumindo que lambda cria uma funcao anónima, só o 'do' não faz isso. Para criares uma função anonima em ruby podes usar "lambda do ... end" ou "proc do ... end"

Está aqui um artigo interessante que explica umas coisas dos blocos de Ruby: http://blog.rubybestpractices.com/posts/gregory/009-beautiful-blocks.html

Eu acho que o livro não está correcto porque um método que possa enviar valores para um bloco... isso é qualquer método. Envia sempre alguma coisa, nem que seja nil.

Acho que deviam ter dito que é um método que possa enviar um Enumerable.

Eu acho que é mais provável tu não teres percebido bem o básico e estares enganado do que o livro, que foi feito por pessoas que trabalham com Ruby há bastante tempo. Não sei, mas parece-me que estas a complicar as coisas. Talvez seja por seres um Pythonista e tens alguma resistência em tudo o que é Ruby? :thumbsup: Podias experimentar fazer um curso online (e gratuito se não me engano) sobre Core Ruby para perceberes os conceitos correctamente: http://rubylearning.org/class/. Também tens este tutorial para explicar Core Ruby: http://rubylearning.com/satishtalim/tutorial.html

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Vou responder à minha própria dúvida:

Não sei porquê é que esse exemplo não dá nenhum warning

Fui ver o código do Hash do Rubinius: http://github.com/evanphx/rubinius/blob/6536694b26a0021726e3785d5b245d7a8503f559/lib/1.8.7/hash.rb

E ao olhar para o metodo each percebi, o que ele faz é yield da chave e do valor correspondente. Ou seja, faz "yield [key, value]" (Linha 53).

É por isso que no teu exemplo:

irb(main):039:0> comida.each do |a|
irb(main):040:1* puts a
irb(main):041:1> end
fruta
saudavel
chocolate
mau

que ele imprime tudo. Porque o que está na variavel 'a' é um Array, e ao fazer puts de um array, ele imprime cada elemento em linhas seperadas.

Portanto retiro o que disse sobre usar Hash#each com apenas 1 argumento estar errado. Afinal está certo, mas é preciso peceber que aquela variavel é na realidade um Array. É no que dá não ter lido a documentação como deve de ser: "Calls block once for each key in hsh, passing the key and value to the block as a two-element array" (http://www.ruby-doc.org/core/classes/Hash.html#M002861) :thumbsup:

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Crie uma conta ou ligue-se para comentar

Só membros podem comentar

Criar nova conta

Registe para ter uma conta na nossa comunidade. É fácil!


Registar nova conta

Entra

Já tem conta? Inicie sessão aqui.


Entrar Agora