Как упомянуто, чисто функциональные языки по сути parallelizable. Однако императивные языки намного более интуитивны для многих людей, и мы глубоко укреплены в обязательном унаследованном коде. Основная проблема - то, что чистые функциональные языки выражают побочные эффекты явно, в то время как побочные эффекты выражаются неявно на императивных языках по приказу операторов.
я полагаю, что методы для декларативного выражения побочных эффектов (например, в объектно-ориентированной платформе) позволят компиляторам разлагать исполняемые операторы на свои функциональные отношения. Это должно тогда позволить коду быть автоматически параллелизированным почти таким же способом, которым был бы чистый функциональный код.
, Конечно, так же, как сегодня все еще желательно записать определенный критический по отношению к производительности код в ассемблере, это все еще будет необходимо для критического по отношению к производительности записи, явно параллельны коду завтра. Однако методы, такие как я обрисовал в общих чертах, должен помочь автоматически использовать в своих интересах manycore архитектуру с минимальным усилием, израсходованным разработчиком.
Вы можете поместить свои методы в массив, а затем выполнить все в этом массиве
l= []
l << :method_a if a
l << :method_b if b
l << :method_c if c
l.inject(object) { |obj, method| obj.send(method) }
Object # send
выполняет метод с заданным именем. Enumerable # inject
выполняет итерацию по массиву, передавая блоку последнее возвращенное значение и текущий элемент массива.
Если вы хотите, чтобы ваш метод принимал аргументы, вы также можете сделать это следующим образом
l= []
l << [:method_a, arg_a1, arg_a2] if a
l << [:method_b, arg_b1] if b
l << [:method_c, arg_c1, arg_c2, arg_c3] if c
l.inject(object) { |obj, method_and_args| obj.send(*method_and_args) }
Вы можете использовать tap
:
my_object.tap{|o|o.method_a if a}.tap{|o|o.method_b if b}.tap{|o|o.method_c if c}
Хотя метод впрыска вполне допустим, такое использование Enumerable сбивает людей с толку и страдает от ограничений, связанных с невозможностью передавать произвольные параметры.
Подобный шаблон может быть лучше для этого приложения:
object = my_object
if (a)
object = object.method_a(:arg_a)
end
if (b)
object = object.method_b
end
if (c)
object = object.method_c('arg_c1', 'arg_c2')
end
Я обнаружил, что это полезно при использовании named объемы. Например:
scope = Person
if (params[:filter_by_age])
scope = scope.in_age_group(params[:filter_by_age])
end
if (params[:country])
scope = scope.in_country(params[:country])
end
# Usually a will_paginate-type call is made here, too
@people = scope.all
Я использую этот шаблон:
class A
def some_method_because_of_a
...
return self
end
def some_method_because_of_b
...
return self
end
end
a = A.new
a.some_method_because_of_a().some_method_because_of_b()
Возможно, ваша ситуация сложнее, но почему бы и нет:
my_object.method_a if a
my_object.method_b if b
my_object.method_c if c