В каких языках можно динамично переписать функции на лету?

Едва ли jQuery только, но я сделал миленький мост для Ajax MS и jQuery:

Sys.UI.Control.prototype.j = function Sys$UI$Control$j(){
  return $('#' + this.get_id());
}

действительно хорошо при выполнении большого количества Ajax ASP.NET так как jQuery поддерживается MS, теперь имеющим хорошие средства моста, что действительно легко сделать операции jQuery:

$get('#myControl').j().hide();

, Таким образом, вышеупомянутый пример не является большим, но если Вы пишете управление сервером Ajax ASP.NET, облегчает иметь jQuery в Вашей клиентской реализации управления.

5
задан Kara 23 June 2014 в 17:53
поделиться

12 ответов

LISP - лучший язык для этого. Функции LISP представляют собой фактические списки LISP, то есть вы можете управлять исходным кодом LISP, как если бы это была любая другая структура данных.

Вот очень тривиальный пример того, как это работает:

(define hi 
  (lambda () (display "Hello World\n")))
;; Displays Hello World
(hi)
(set! hi
      (lambda () (display "Hola World\n")))
;; Displays Hola World
(hi)

Это, однако, возможно на любом языке, где функции являются объектами первого класса. Одна из самых интересных демонстраций силы этого синтаксиса для LISP - это его макросистема. Я действительно не думаю, что смогу передать эту тему должным образом, поэтому прочтите эти ссылки, если вам интересно:

http://en.wikipedia.org/wiki/Macro_ (computer_science) #Lisp_macros

http: / /cl-cookbook.sourceforge.net/macros.html[1215 impression

9
ответ дан 18 December 2019 в 07:31
поделиться

Самомодифицирующийся код также называется вырожденным кодом. Обычно это считается плохим, и раньше целью языков высокого уровня было предотвратить его легкое написание.

Это из статьи в википедии:

Самомодифицирующийся код некоторые считают плохой практикой, которая затрудняет кодирование читать и поддерживать. Однако существуют способы, которыми самомодификация, тем не менее, считается приемлемой, например, когда указатели подпрограмм динамически изменяются - даже если эффект почти идентичен прямому изменению.

2
ответ дан 18 December 2019 в 07:31
поделиться

Я думаю, что так обстоит дело с большинством динамических языков. Вот пример на Python

def f(x):
    print x

def new_function(x): print "hello", x

f("world")    
f = new_function
f("world")

. Результат -

world
hello world

Я думаю, что такую ​​технику следует использовать осторожно

2
ответ дан 18 December 2019 в 07:31
поделиться

Схема позволяет это сделать.

(define (salute-english name) (display "Hello ") (display name))
(define (salute-french nom) (display "Salut ") (display nom))

Теперь вы переопределяете функцию, назначая переменную salute правой функции, либо salute-english ] или salute-french , например:

(define salute salute-english)

(define (redefined-the-salute-function language)
  (if (eq? language 'french)
      (set! salute salute-french)
      (set! salute salute-english)))

В более общем смысле функциональный язык программирования позволяет вам делать это, или поскольку функции являются первоклассной ценностью. Функциями можно управлять, передавать их, иногда назначать переменным и так далее. Затем список включает: Lisp , Scheme , Dylan , OCaml и SML . Некоторые языки, имеющие функции первого класса, включают Python , Ruby , Smalltalk и, я думаю, Perl .

2
ответ дан 18 December 2019 в 07:31
поделиться

Я всегда делал это в TCL, это было легко и прекрасно работало. Я мог исследовать какой-то интерфейс по сети, а затем на лету создать индивидуальный интерфейс для доступа и управления вещами. Например, вы можете создать собственный интерфейс SNMP из общей библиотеки SNMP.

Я не использовал его, но в C # есть встроенная поддержка для генерации собственного байтового кода, что довольно впечатляет.

Я делал такие вещи и на C, но там он непереносимый и почти никогда не стоит хлопот. Это метод, который иногда используется для "самооптимизирующегося" кода для генерации соответствующей функции C для оптимальной обработки заданного набора данных.

1
ответ дан 18 December 2019 в 07:31
поделиться

Вы могли бы сделать это на C ++, но это было бы нелегко, безопасно или рекомендовано.

  1. Сгенерировать текст исходного кода
  2. вызвать компилятор (fork & exec ) для создания динамической библиотеки. В gcc вы можете передать исходный код, который хотите скомпилировать, на стандартный ввод, он не обязательно должен быть в файле.
  3. Загрузите библиотеку (LoadLibrary () в Windows, dlopen () в Linux)
  4. получить указатель функции на любую функцию, которую вы хотите (GetProcAddress () в Windows, dlsym () в Linux)
  5. Если вы хотите заменить существующую функцию, если это виртуальная функция, вы можете изменить v-таблицу, чтобы она указывала на новая функция (особенно эта часть - ужасная идея, чреватая опасностями). Расположение v-таблицы или ее формат не является частью стандарта C ++, но все инструменты I ' Они были последовательны внутри себя, поэтому, как только вы поймете, как они это делают, он, вероятно, не сломается.
1
ответ дан 18 December 2019 в 07:31
поделиться

В PLSQL:

create or replace procedure test
as
begin
 execute immediate '
create or replace procedure test2
as
begin
  null;
end;
 ';
end;
/
0
ответ дан 18 December 2019 в 07:31
поделиться

Достаточно просто на Perl.

*some_func = sub($) {
    my $arg = shift;
    print $arg, "\n";
};
some_func('foo');

По запросу Сэма Шафрана:

*hello_world = sub() {
    print "oops";
};
hello_world();
*hello_world = sub() {
    print "hello world";
};
hello_world();
1
ответ дан 18 December 2019 в 07:31
поделиться

Думаю, это зависит от того, что именно вы определяете как «легко динамическое перезапись». Например, в .Net у вас есть тип Func и лямбда-выражения, которые позволяют вам определять функции как переменные или как временные анонимные функции, например.

int[] numbers = {1, 2, 3, 4, 5};

Func<int[], int> somefunc;
if (someCondition) 
{
   somefunc = (is => is.Sum());
} else {
   somefunc = (is => is.Count());
}

Console.WriteLine(somefunc(numbers).ToString());

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

Примечание. Не указывайте, пожалуйста, на то, что эти вещи могут быть легко выполнены без лямбда-выражений (что они, очевидно, могут). Я просто пытался написать очень простой пример, чтобы продемонстрировать концепцию в C #

3
ответ дан 18 December 2019 в 07:31
поделиться

Здесь есть кое-что еще в Python ( в дополнение к ответу luc), который я не рекомендую, а просто чтобы показать его - есть exec, который может выполнять строку, которую вы можете построить в виде любого кода ...

Показанный здесь ввод-вывод взят из Сеанс интерпретатора Python 2.5.2. Просто несколько простых примеров построения строк для выполнения из подстрок (>>> - это приглашение интерпретатора) ...

>>> def_string = 'def my_func'
>>> param_string_1 = '():'
>>> param_string_2 = '(x):'
>>> do_string_1 = '  print "Do whatever."'
>>> do_string_2 = '  print "Do something with", x'
>>> do_string_3 = '  print "Do whatever else."'
>>> do_string_4 = '  print "Do something else with", x'
>>> def_1 = '\n'.join([def_string+param_string_1, do_string_1, do_string_3])
>>> print def_1
def my_func():
  print "Do whatever."
  print "Do whatever else."
>>> exec def_1
>>> my_func()
Do whatever.
Do whatever else.
>>> def_2 = '\n'.join([def_string+param_string_2, do_string_2, do_string_4])
>>> print def_2
def my_func(x):
  print "Do something with", x
  print "Do something else with", x
>>> exec def_2
>>> my_func('Tom Ritter')
Do something with Tom Ritter
Do something else with Tom Ritter
>>> 
0
ответ дан 18 December 2019 в 07:31
поделиться

Тривиально в Ruby:

def hello_world; puts "oops"; end
hello_world
# oops
def hello_world; puts "hello world"; end
hello_world
# hello world

Конечно, этот пример скучен:

require "benchmark"
# why oh _why 
class Object
  def metaclass; class << self; self; end; end
  def meta_eval &blk; metaclass.instance_eval &blk; end
end

class Turtle
end

def make_it_move(klass)
  klass.send(:define_method, :move) { |distance|
    puts "moving #{distance} meters"
    sleep(0.1 * distance)
  }
end

make_it_move(Turtle)

turtle = Turtle.new
turtle.move(1)
# moving 1 meters

def profile(instance, method)
  instance.meta_eval do
    m = instance_method(method)
    define_method method do |*a|
      puts "Benchmarking #{instance.class} #{method}"
      puts Benchmark.measure {
        m.bind(instance).call(*a)
      }
    end
  end
end

profile(turtle, :move)

turtle.move(10)
# Benchmarking Turtle move
# moving 10 meters
#  0.000000   0.000000   0.000000 (  1.000994)


Turtle.new.move(3)
# moving 3 meters 

Приведенный выше код:

  1. Определяет пустой класс
  2. Добавляет к нему метод
  3. Захваты экземпляр
  4. Перехватывает этот метод только на этом экземпляре
0
ответ дан 18 December 2019 в 07:31
поделиться

Изменение того, что делает функция, поддерживается на многих языках, и это не так сложно, как вы думаете. В функциональных языках функции - это значения, а имена функций - это символы, которые связаны с ними, как с любой переменной. Если язык позволяет вам переназначить символ другой функции, это тривиально.

Я думаю, что более интересными функциями являются возможность получить исходный код для функции ( toString выше) и создать новую функцию из строки (в данном случае eval ).

0
ответ дан 18 December 2019 в 07:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: