Programming languages 您可以用什么语言动态地重写函数?

Programming languages 您可以用什么语言动态地重写函数?,programming-languages,lisp,dynamic-languages,Programming Languages,Lisp,Dynamic Languages,我最近有必要用javascript动态地重写javascript函数。我做这件事的轻松程度和乐趣让我大吃一惊 在这里,我有一些HTML: <div id="excelExport1234" onclick="if(somestuff) location.href='http://server/excelExport.aspx?id=56789&something=else'; else alert('not important');" >Click here

我最近有必要用javascript动态地重写javascript函数。我做这件事的轻松程度和乐趣让我大吃一惊

在这里,我有一些HTML:

<div id="excelExport1234" 
     onclick="if(somestuff) location.href='http://server/excelExport.aspx?id=56789&something=else'; else alert('not important');"
  >Click here to export to excel</div>
它就像一个冠军!excelExport.onclick返回一个函数对象,我将其转换为字符串,并对其执行一些字符串管理。由于它现在是“function(){…}”的形式,我只需返回并将其分配给dom对象的onclick事件。必须使用eval有点难看,但毕竟没有一个javascript函数构造函数可以接受一个字符串代码并将其很好地转换为对象

无论如何,我的观点不是我超级聪明(我不是),我的观点是这很酷。我知道javascript并不是唯一能做到这一点的语言。我听说lisp多年来一直使用宏来实现这一目的。除了要真正理解宏,你需要真正理解lisp,我不理解它,我只是“有点理解”

因此,我的问题是:您可以(轻松地)用哪些其他语言动态重写函数,您能给我举个简单的例子吗?我想看看您还可以在哪里执行此操作,以及如何执行此操作


(另外,我不知道该怎么称呼它,所以我随机猜测)

我在TCL一直都是这么做的,这是一件轻而易举的事,工作得非常出色。我可以通过网络调查somethings接口,然后动态创建一个定制接口来访问和控制内容。例如,您可以从通用SNMP库创建自定义SNMP接口

我没有使用过它,但C#有一些内置的支持来生成自己的字节码,这相当令人印象深刻


我在C语言中也做过类似的事情,但它不可移植,几乎不值得这么麻烦。这是一种有时用于“自我优化”代码的技术,用于生成适当的C函数以优化处理给定的数据集。

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这种语法的强大功能最有趣的展示之一就是它的宏系统。我真的觉得我不能公正地讨论这个话题,所以如果你感兴趣,请阅读以下链接:

用Perl很容易

*some_func = sub($) {
    my $arg = shift;
    print $arg, "\n";
};
some_func('foo');
关于Sam Saffron的请求:

*hello_world = sub() {
    print "oops";
};
hello_world();
*hello_world = sub() {
    print "hello world";
};
hello_world();
也称为退化码。这通常被认为是一件坏事,高级语言的目标是防止它被轻松编写

这来自维基百科条目:

一些人认为自修改代码是一种糟糕的做法,这会使代码更难阅读和维护。然而,也有一些自修改被认为是可以接受的方式,例如当子例程指针被动态修改时——即使效果与直接修改几乎相同


我想这取决于你定义的“轻松动态重写”。例如,在.Net中有Func类型和lambdas,它允许您将函数定义为变量或临时匿名函数,例如

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());
int[]数字={1,2,3,4,5};
Func somefunc;
如果(某些条件)
{
somefunc=(is=>is.Sum());
}否则{
somefunc=(is=>is.Count());
}
Console.WriteLine(somefunc(numbers.ToString());
上面是一个非常做作的例子,要么计算整数数组中的项,要么求和,然后根据某些任意条件使用动态创建的函数


注意-请不要指出,没有lambdas,这些事情很容易就能完成(它们显然可以做到)。我只是想写一个非常简单的例子,用C#

来演示这个概念。我认为大多数动态语言都是这样。下面是一个Python示例

def f(x): print x def new_function(x): print "hello", x f("world") f = new_function f("world") def f(x): 打印x def新功能(x):打印“hello”,x f(“世界”) f=新的_函数 f(“世界”) 输出是

world hello world 世界 你好,世界
我认为应该谨慎使用这种技术,因为Scheme允许您这样做

(define (salute-english name) (display "Hello ") (display name))
(define (salute-french nom) (display "Salut ") (display nom))
现在,您可以通过将
sallet
变量指定给右函数来重新定义函数,如
sallet english
sallet french
,如下所示:

(define salute salute-english)

(define (redefined-the-salute-function language)
  (if (eq? language 'french)
      (set! salute salute-french)
      (set! salute salute-english)))
更一般的函数式编程语言允许您这样做,或者函数是第一类值。函数可以被操作,传递,有时分配给变量等等。该列表包括:LispSchemeDylanOCamlSML。一些具有一流函数的语言包括PythonRubySmalltalk,我认为Perl

请注意,如果您有一种交互式语言,可以在其中以交互方式键入程序,则必须能够重新定义函数/方法:REPL必须能够这样做,以防您碰巧重新键入已定义函数的定义。

在PLSQL中:

create or replace procedure test
as
begin
 execute immediate '
create or replace procedure test2
as
begin
  null;
end;
 ';
end;
/

<>你可以用C++做,但是它不容易,安全,或者推荐。< /P>
  • 生成源代码的文本
  • 调用编译器(fork&exec)来构建动态库。在gcc中,您可以通过标准输入传递要编译的源代码,它不必在文件中
  • 加载库(windows上为LoadLibrary(),linux上为dlopen())
  • 获取指向所需函数的函数指针(windows上为GetProcAddress(),linux上为dlsym())
  • 如果您想替换现有函数,如果它是虚拟函数,您可以修改v-table以指向新函数(尤其是这一部分是一个充满危险的可怕想法)。v形工作台的位置或
    create or replace procedure test
    as
    begin
     execute immediate '
    create or replace procedure test2
    as
    begin
      null;
    end;
     ';
    end;
    /
    
    >>> 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
    >>> 
    
    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