[Ruby] А как передать метод без yield?

timefim


def inc x
x + 1
end

def test f
f 1
end

test inc #wrong number of arguments (0 for 1)

Вообще этот yield какая то сомнительная придумка.

karkar

Вариант с yield:

def test # получает блок как параметр и вызывает его с 1
yield 1
end

p test { |x| x+1 } # вызывает test с указанным блоком кода и выводит результат

Вариант без yield:

def test2(f) f.call 1 end # получает Proc как параметр и вызывает его с 1

p test2(lambda {|x| x+1}) # вызывает test2 с указанной лямбдой и выводит результат

Вообще этот yield какая то сомнительная придумка.

Зато довольно удобная. Например, функция, перемешивающая произвольный одномерный массив в случайном порядке, выглядит так:
def mix(m)   m.map{|x| [rand, x]}.sort.map{|p| p[1]}  end  

Как она будет выглядеть в петоне?

psihodog

Как она будет выглядеть в петоне?
random.shuffle(arr)

nikita270601

а если бы ее не было в библиотеке?

vall

а если бы ее не было в библиотеке?
её не может не быть =)

nikita270601

У меня, к примеру, нету.

vall

типо Ван Россум передумал и перепрятал в вашей библиотеке? =)
вообще-то да, наверно функция без класса Random это несекьюрно.

nikita270601

Нет, просто нету и все!

bleyman

def mix(m) m.map{|x| [rand, x]}.sort.map{|p| p[1]} end
def mix(x):
   return [a[1] for a in sorted([(random a) for a in x])]

bleyman

Или, в чисто функциональном стиле,
def mix(x):
return list(imap(tuple.__getitem__, sorted(zip(imaplambda x: random repeat(None x repeat(1
=)

timefim

test2(lambda {|x| x+1})
Нет, это аналог питоновского


test2(lambda x: x + 1)

Хочется передать не лямбду, а нормальную функцию.
Как она будет выглядеть в петоне?

Не осилил о чем там выше писали, но при наличии тех же функций оно бы выглядело практически идентично.

karkar

Хочется передать не лямбду, а нормальную функцию.

Насколько я понимаю, придется завернуть ее в лямбду или Proc (что одно и то же). Это как с делегатами в C#, но нет автоматического приведения.
def inc(x) x+1 end
def test(f) f.call 1 end
p test(lambda {|x| inc x})

Если речь о передаче одного метода другому, можно передавать его имя в виде символа и вызывать через send, но это некрасиво как-то.

klyv

Как она будет выглядеть в петоне?
Да почти так же :)

timefim

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

karkar

А continuations в нем есть (call/cc)?
Инструкция break с меткой?
И лямбды у него, как я понял, не есть полноценные замыкания?
В принципе, языки действительно одного уровня и совсем явных преимуществ одного перед другим назвать нельзя. Так что выбор определяется либо ограничениями реализации, либо привычками и вкусами программера. Мне лично Руби симпатичней, потому что
1) мне не нравится indent-sensitive синтаксис,
2) он более консистентно выдержан в ООП стиле (s.length вместо length(s a.sort вместо sorted(a) и т.д.)
3) Особенности синтаксиса (символы, необязательные скобки при вызове функций, передача блоков, все имеет значение - не обязателен return) очень хорошо подходят для создания DSL.
4) я не знаю петон :)
Вот реальный пример из моего проекта, когда я протащился от Руби.
Вот такой код на internal DSL:
zero = _int 0
_func(:stlen) { |s,n|
(p = _pbyte).point s
_while(zero < p) {
p.inc
}
n <= p - s
}

regcode = _pbyte 1
rclen = _int
stlen(regcode, rclen)

Это синтаксически корректный код на Руби, результатом исполнения которого является значение
[:do,
[:var, :r20],
[:set, :r20, 0],
[:var, :r1],
[:var, :r21],
[:var, :r22],
[:set, :r22, :r1],
[:while,
[:less,
:r20,
[:getb, :p22]
],
[:inc, :r22, 1]
],
[:set,
:r21,
[:sub, :r22, :r1]
]
]

Это дерево передается на вход моему компилятору (тоже на Руби, конечно который превращает его вот в такой текст:
MOV|RV, 20, 0,
MOV|RR, 22, 1,
MOV|RV, 21, 0,
MOVB|RP, 21, 22,
LE|RR, 20, 21,
JZ, 7,
ADD|RV, 22, 1,
JMP, -14,
MOV|RR, 23, 22,
SUB|RR, 23, 1,
MOV|RR, 21, 23

Который используется в коде на С++:
  int code[] = {
#include "code.r"
};

И задает байткод для виртуальной машины, которая его уже выполнит с нужными параметрами. Тем самым имею свой компилятор с бесплатным лексическим и синтаксическим анализом. Он стал возможен благодаря таким удобным вещам в Руби как символы, yield и гибкий синтаксис.

timefim

А continuations в нем есть (call/cc)?
Инструкция break с меткой?
И лямбды у него, как я понял, не есть полноценные замыкания?
Да.
Что то ничего кроме break if я не нашол, что это?
Да, вроде так какие то проблеммы с этим имеются.
А чем было обосновано писание компилятора на руби? Думаю любой нормальный функциональный язык не уступил бы ему по выразительности, да и скорость была бы на порядки выше.

nikita270601

А continuations в нем есть (call/cc)?
Да.
Да?

tipnote

Гугл говорит:
1) можно реализовать
2) можно воспользоваться stackless python реализацией - там все "из коробки"

nikita270601

But we don't have continuations in Python. Luckily we can fake them. At least we can fake them in a limited way that is sufficient to show what to do with them.
Впрочем, мне лень разбираться, чтобы понять, что там к чему.

nikita270601

2) можно воспользоваться stackless python реализацией - там все "из коробки"
Это уже интереснее. Кто-нибудь пользовался этим?

karkar

Что то ничего кроме break if я не нашол, что это?
Возможность из вложенного цикла выйти на нужный уровень.
В Перле есть такая штука:
my $counter = 0;
OUTER: foreach my $outer (1..5) {
foreach my $inner ('A'..'E') {
print "$outer: $inner\n";
last OUTER if ++$counter > 4
}
}

В Руби аналогичная вещь называется catch:
counter = 0
catch :OUTER do
1.upto(5) do |outer|
'A'.upto'E' do |inner|
puts "#{outer}: #{inner}"
throw :OUTER if (counter += 1) > 4
end
end
end

Это НЕ исключения и их обработка, для них есть другая конструкция (begin/rescue).
А чем было обосновано писание компилятора на руби? Думаю любой нормальный функциональный язык не уступил бы ему по выразительности, да и скорость была бы на порядки выше.
Мне не известен ни один язык, в котором я мог бы средствами самого языка изобразить подобный DSL и иметь лексер с парсером нахаляву. На функциональных языках обычно идут по пути внешних DSL - пишут очередной лексер, парсер и дальнейшую интерпретацию AST либо кодогенерацию, это гораздо больше возни. А скорость тут особо не причем - исполняется-то целевая программа не интерпретатором Руби, а моей виртуальной машиной, которая весьма быстра (медленнее, чем натив и JIT, но быстрее всех распространенных байткодовых интерпретаторов). Что же до скорости компиляции, то на необходимых мне объемах исходников текущей хватает за глаза - все работает мгновенно.

tipnote

http://www.stackless.com/wiki/Applications
Я не пользовался, мне пока не нужны микротреды и прочий альтернативный шедулинг, ради чего он и затевался. При этом, вроде как, он чуть ли не полностью совместим с CPython и является набором патчей над ним же, то есть должен быть относительно безопасен в смысле стабильности, так как не пишет новый интерпретатор, а только слегка патчит старый.

timefim

Возможность из вложенного цикла выйти на нужный уровень.
А чем оно отличается от goto?

karkar

Ну, goto considered harmful, а это - видимо нет, раз оно присутствует в ряде языков, где нет goto (Java, JavaScript, Groovy, Nemerle и даже PHP).
Оставить комментарий
Имя или ник:
Комментарий: