Поиск динамического метода отправки через автоматическое построение Hash - PullRequest
0 голосов
/ 18 мая 2019

Я строю стохастические имитационные модели.Переходы между состояниями обрабатываются методами событий, но порядок их возникновения зависит от случайности событий, поэтому мне нужна некоторая форма динамической отправки.Вот уже более десяти лет это прекрасно работает для меня в Ruby с использованием send, но меня привлекает скорость Crystal, поэтому я пытаюсь создать каркас для построения симуляций в кристаллическом режиме.

Природа моделей заключается в том, что методы событий инициируют определенные подмножества других событий на основе случайных условий (и после случайных временных задержек, но я это охватил), поэтому события действительно должны быть идентифицированы читаемым пользователем тегом некоторыхсортировать для целей планирования.Я выбрал подход использования Hash, который отображает идентификаторы событий на соответствующие им Proc s, но хочу отделить логику модели от вызова события, как в следующем классе и модуле «модель».(Пожалуйста, имейте в виду, что реальный код будет более сложным, чем этот, с методами событий, которые планируют последующие события со случайными задержками через очередь приоритетов. Это подразумевается как MCVE только для аспекта проблемы с динамической отправкой по имени.)

Модель:

require "./my_module"

class UserClass
  include MyModule

  def initialize
    @method_set = {
      :m1 => ->m1,
      :m2 => ->m2,
      :m3 => ->m3
    }
    p methods
  end

  def m1
    puts "In method1"
  end

  def m2
    puts "In method2"
  end

  def m3
    puts "In method3"
  end
end

UserClass.new.run(5)

Выполнение логики управления, которая является общей для всех моделей:

module MyModule
  # would like to replace this with a macro that
  # automates construction of the hash of procs.
  macro methods
    {{ @type.methods.map &.name.stringify }}
  end

  @method_set = {} of Symbol => Proc(Nil)

  def run(iterations)
    keys = @method_set.keys
    iterations.times { @method_set[keys[rand(keys.size)]].call }
  end
end

Теперь перейдем к актуальному вопросу.В серьезных моделях могут быть десятки или сотни методов событий, поэтому я хотел бы использовать макросы для автоматизации построения Hash.Я провел некоторое исследование и нашел, как получить имена методов с помощью макроса, но не могу найти правильное заклинание, чтобы выкашлять Symbol -привод Hash, подобное тому, которое я создаю вручную в конструкторе.Буду признателен за любую помощь или предложения для альтернативных подходов.

1 Ответ

3 голосов
/ 18 мая 2019

Поскольку вы используете символы в качестве ключей поиска, я предполагаю, что вам не нужно искать методы по их имени во время выполнения. Кажется, вам может понадобиться способ ссылки на методы.

Для этого вы можете просто пропустить проки без каких-либо косвенных символов:

module MyModule
  macro methods
    [{{ @type.methods.map{|method| "-> #{method.name}"}.join(",").id }}]
  end

  def run(iterations)
    iterations.times { methods.sample.call }
  end
end

В случае, если вам нужна полная динамическая диспетчеризация от пользовательской строки, например от "m1" до UserClass#m1 (что было бы невозможно с символьными клавишами, поэтому я не думаю, что вы это делаете), я просто сопоставил бы имена, используя сгенерированный макросом case с прямым вызовом метода, вместо поиска по хешу и процедур.

UPDATE: В случае, если вам нужно фактическое разрешение имен, вы можете использовать следующий макрос для генерации хеш-отображения из имени метода в proc:

module MyModule
  macro methods
    {
      {% for method in @type.methods %}
        {{method.name.stringify}} => -> {{method.name}},
      {% end %}
    }
  end
end
...