Синтаксическая ошибка в Ruby, неожиданный символ конвейера в Do - PullRequest
2 голосов
/ 10 июля 2010

Я постараюсь быть кратким на этот раз! Я все еще работаю над Project Euler, на этот раз возвращаясь к # 2. Моя настоящая проблема в том, что я ужасен с Руби. Когда я запускаю следующий код

x = 1
y = 2
sum = 2
while x >= 4_000_000 do |x|

  sum += y if y % 2 == 0

  z = x + y

  x = x ^ y   # xor magic
  y = x ^ y   # xor magic
  x = x ^ y   # xor magic

  y = z 
end

p sum

Мой переводчик выводит следующий вывод:

/Users/Andy/Documents/Programming/Ruby/ProjectEuler/P2.rb:4: syntax error, unexpected '|'
while x >= 4_000_000 do |x|
                         ^

Я читаю , почему (Poignant) Руководство по Ruby , и я почти уверен, что у меня правильный синтаксис канала для Do. Может ли кто-нибудь указать, что я здесь делаю неправильно? Я пытался поиграть разными способами, и я иду с короткими руками

Ответы [ 4 ]

6 голосов
/ 10 июля 2010

while не занимает блок. Удалить do |x| деталь.

6 голосов
/ 10 июля 2010
while (x >= 4_000_000)
    foo
end

Вам даже не нужно вводить x, потому что он доступен в области действия включающего блока.

4 голосов
/ 10 июля 2010

while это не метод, который принимает блок, это оператор цикла ruby. Он считает, что часть между while и do (или новой строкой) является логическим тестом, а часть между ключевыми словами do (или новой строкой) и end - телом цикла.

while x < 10 do x += 1; puts x; end
while x < 10
  x += 1
  puts x
end

Сравните это с чем-то вроде метода each массива, который принимает блок. Здесь каждый метод вызывает ваш блок для каждого элемента массива (передается в блок как x)

[1,2,3].each do |x|  
  puts x
end

Вы случайно скомбинировали их, попросив цикл while вызвать ваш блок кода со счетчиком цикла, который будет передан как x. Это не то, как время работает ... отсюда исключение при разборе.

2 голосов
/ 10 июля 2010

Какой интересный вопрос!Это вдохновило меня и на решение этой проблемы.Вот мое решение.

Сначала подготовительная работа:

class Enumerator
  def lazy_select
    Enumerator.new do |y|
      each do |el|
        y.yield(el) if yield el
      end
    end
  end

  alias_method :lazy_find_all, :lazy_select
end

module Enumerable
  def sum
    reduce(:+)
  end
end

module Math
  ROOT5 = Math.sqrt(5)
  PHI = 0.5 + ROOT5/2

  def self.fibonacci(n)
    Integer(0.5 + PHI**n/ROOT5)
  end
end

class Integer
  def fibonacci
    Math.fibonacci(self)
  end
end

Теперь Enumerator, который генерирует бесконечную последовательность чисел Фибоначчи:

fibs = Enumerator.new do |y|
  n = -1
  loop do
    y.yield (n += 1).fibonacci
  end
end

Ихорошо, что теперь мы можем напрямую выразить исходное утверждение задачи в коде:

Найти сумму всех четных членов в последовательности, которые не превышают четырех миллионов.

puts fibs.lazy_find_all(&:even?).take_while {|n| n <= 4_000_000 }.sum

Я думаю, что это гораздо более рубиновый способ решения проблемы.Вы пишете в своем вопросе, что вы ужасны с Руби.Но это на самом деле не проблема.Проблема real в том, что с C у вас все хорошо!Другими словами, настоящая проблема в том, что вы просто не пишете на Ruby, вы пишете на языке C с синтаксисом Ruby.

Два хороших примера:

y % 2 == 0

и

x = x ^ y
y = x ^ y
x = x ^ y

В Ruby их можно написать

y.even?

и

x, y = y, x
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...