多个调度系统中的函数是否可变?
Are functions mutable in multiple dispatch systems?
我是否理解正确,在(大多数?一些?)多种调度语言中,每个方法都会在程序执行的某个时间点添加到函数。
然后我可以得出结论,多重分派作为一个特性强制函数可变吗?
是否有一种多重调度语言,其中所有方法都附加到一个(通用)函数(在加载时?),以便无法在不同时间点看到不同状态的函数?
at some point in time of program's execution.
在 Common Lisp 中,方法在执行方法定义时得到 added/replaced - 对于编译系统,这通常是在编译代码的加载时 - 不一定在程序执行期间。
请记住,Common Lisp 有一个 对象系统(CLOS,Common Lisp 对象系统),这是由其行为定义的。它与 语言 或 语言扩展 .
略有不同
Common Lisp 允许运行时修改对象系统。例如还有 adding/removing/replacing 方法。
Common Lisp 还可以组合 多个适用方法为有效方法,然后执行。典型示例:所有适用的:before
方法和最具体适用的主要方法将合并为一个有效方法。
在一些实现中存在 CLOS 扩展,密封 通用函数以防止更改。
有关 对象系统 思想的更详细处理,请参阅:The Structure of a Programming Language Revolution 作者 Richard P. Gabriel。
转述自优秀的“Getting started with Julia”书中有一个很好的部分(强调我的):
We already saw that functions are inherently defined as generic, that is, they can be used for different types of their arguments. The compiler will generate a separate version of the function each time it is called with arguments of a new type. A concrete version of a function for a specific combination of argument types is called a method in Julia. To define a new method for a function (also called overloading), just use the same function name but a different signature, that is, with different argument types.
A list of all the methods is stored in a virtual method table ( vtable ) on the function itself; methods do not belong to a particular type. When a function is called, Julia will do a lookup in that vtable at runtime to find which concrete method it should call based on the types of all its arguments; this is Julia's mechanism of multiple dispatch, which neither Python, nor C++ or Fortran implements. It allows open extensions where normal object-oriented code would have forced you to change a class or subclass an existing class and thus change your library. Note that only the positional arguments are taken into account for multiple dispatch, and not the keyword arguments.
For each of these different methods, specialized low-level code is generated, targeted to the processor's instruction set. In contrast to object-oriented (OO) languages, vtable is stored in the function, and not in the type (or class). In OO languages, a method is called on a single object, object.method(), which is generally called single dispatch. In Julia, one can say that a function belongs to multiple types, or that a function is specialized or overloaded for different types. Julia's ability to compile code that reads like a high-level dynamic language into machine code that performs like C almost entirely is derived from its ability to do multiple dispatch.
因此,我的理解方式(我可能是错的)是:
- 泛型函数需要在session中定义后才能使用
- 具体参数的显式定义方法被添加到函数的多分派查找中 table 在它们被定义的地方。
- 每当使用不存在显式定义方法的特定参数调用函数时,将编译这些参数的具体版本并将其添加到 vtable。 (但是,如果您 运行
methods()
在该函数名称上,这不会显示为显式方法)
- 第一次调用这样的函数会产生一些编译开销;但是,后续调用将使用现有的编译版本*。
我不会说这使得函数 mutable 不过,这是一个完全不同的问题。您可以在函数 'handle'.
上使用 isimmutable()
函数来确认它们是 immutable
*我知道模块可以预编译,但我不完全确定这些即时编译版本是否以任何形式在会话之间保存-- 欢迎评论:)
即使仅用于调试,动态性也是您应用程序中的一项真正资产。试图阻止函数以后被更新、重新定义等可能有点短视。但是如果你确定你想要静态调度,你可以定义你自己的 class 通用函数,这要归功于 MOP,即元对象协议,它不是标准的一部分,但仍然在很大程度上得到支持。这就是 Inlined-Generic-Function 库提供的功能(这是可能的,因为 CLOS 对扩展开放)。
在 Common Lisp 中,您可以从规范中阅读以下内容:
7.6.1 Introduction to Generic Functions
When a defgeneric
form is evaluated, one of three actions is taken (due to ensure-generic-function
):
- If a generic function of the given name already exists, the existing generic function object is modified. Methods specified by the current
defgeneric
form are added, and any methods in the existing generic function that were defined by a previous defgeneric
form are removed. Methods added by the current defgeneric
form might replace methods defined by defmethod
, defclass
, define-condition
, or defstruct
. No other methods in the generic function are affected or replaced.
- If the given name names an ordinary function, a macro, or a special operator, an error is signaled.
- Otherwise a generic function is created with the methods specified by the method definitions in the
defgeneric
form.
When a method-defining form is evaluated, a method object is created and one of four actions is taken:
- If a generic function of the given name already exists and if a method object already exists that agrees with the new one on parameter specializers and qualifiers, the new method object replaces the old one. For a definition of one method agreeing with another on parameter specializers and qualifiers, see Section 7.6.3 (Agreement on Parameter Specializers and Qualifiers).
- If a generic function of the given name already exists and if there is no method object that agrees with the new one on parameter specializers and qualifiers, the existing generic function object is modified to contain the new method object.
- If the given name names an ordinary function, a macro, or a special operator, an error is signaled.
- Otherwise a generic function is created with the method specified by the method-defining form.
If function-name specifies a generic function that has a different value for the :lambda-list
argument, and the new value is congruent with the lambda lists of all existing methods or there are no methods, the value is changed; otherwise an error is signaled.
If function-name specifies a generic function that has a different value for the :generic-function-class
argument and if the new generic function class is compatible with the old, change-class
is called to change the class of the generic function; otherwise an error is signaled.
If function-name specifies a generic function that has a different value for the :method-class
argument, the value is changed, but any existing methods are not changed.
你还有add-method
and remove-method
.
如您所见,泛型函数在 defmethod
定义之间,甚至在 defgeneric
定义之间保留它们的标识。通用函数在 Common Lisp 中是可变的。
在 Julia 中,您可以从文档中阅读以下内容:
To define a function with multiple methods, one simply defines the function multiple times, with different numbers and types of arguments. The first method definition for a function creates the function object, and subsequent method definitions add new methods to the existing function object.
如您所见,函数对象在 Julia 中是可变的。
这并没有说明所有其他多调度语言。你现在可以发明一种多重调度语言,只是为了展示你可以用不变性来做到这一点,例如添加方法将 return 一个与之前的函数相似但具有添加的方法的新函数。或者一种在编译时静态生成函数的语言,这样您就无法在运行时以任何方式更改它,甚至不能添加或删除方法。
在 Dylan 中,方法通常在编译时添加到泛型函数中,但它们也可能在 运行 时添加(通过 add-method or remove-method). However, a generic function may be sealed,这会阻止除其中的库之外的库g.f。是通过添加方法定义的。所以为了回答你的问题,在 Dylan 中,泛型函数在定义库中总是可变的,但它们可能对其他库不可变。
我是否理解正确,在(大多数?一些?)多种调度语言中,每个方法都会在程序执行的某个时间点添加到函数。
然后我可以得出结论,多重分派作为一个特性强制函数可变吗?
是否有一种多重调度语言,其中所有方法都附加到一个(通用)函数(在加载时?),以便无法在不同时间点看到不同状态的函数?
at some point in time of program's execution.
在 Common Lisp 中,方法在执行方法定义时得到 added/replaced - 对于编译系统,这通常是在编译代码的加载时 - 不一定在程序执行期间。
请记住,Common Lisp 有一个 对象系统(CLOS,Common Lisp 对象系统),这是由其行为定义的。它与 语言 或 语言扩展 .
略有不同Common Lisp 允许运行时修改对象系统。例如还有 adding/removing/replacing 方法。
Common Lisp 还可以组合 多个适用方法为有效方法,然后执行。典型示例:所有适用的:before
方法和最具体适用的主要方法将合并为一个有效方法。
在一些实现中存在 CLOS 扩展,密封 通用函数以防止更改。
有关 对象系统 思想的更详细处理,请参阅:The Structure of a Programming Language Revolution 作者 Richard P. Gabriel。
转述自优秀的“Getting started with Julia”书中有一个很好的部分(强调我的):
We already saw that functions are inherently defined as generic, that is, they can be used for different types of their arguments. The compiler will generate a separate version of the function each time it is called with arguments of a new type. A concrete version of a function for a specific combination of argument types is called a method in Julia. To define a new method for a function (also called overloading), just use the same function name but a different signature, that is, with different argument types.
A list of all the methods is stored in a virtual method table ( vtable ) on the function itself; methods do not belong to a particular type. When a function is called, Julia will do a lookup in that vtable at runtime to find which concrete method it should call based on the types of all its arguments; this is Julia's mechanism of multiple dispatch, which neither Python, nor C++ or Fortran implements. It allows open extensions where normal object-oriented code would have forced you to change a class or subclass an existing class and thus change your library. Note that only the positional arguments are taken into account for multiple dispatch, and not the keyword arguments.
For each of these different methods, specialized low-level code is generated, targeted to the processor's instruction set. In contrast to object-oriented (OO) languages, vtable is stored in the function, and not in the type (or class). In OO languages, a method is called on a single object, object.method(), which is generally called single dispatch. In Julia, one can say that a function belongs to multiple types, or that a function is specialized or overloaded for different types. Julia's ability to compile code that reads like a high-level dynamic language into machine code that performs like C almost entirely is derived from its ability to do multiple dispatch.
因此,我的理解方式(我可能是错的)是:
- 泛型函数需要在session中定义后才能使用
- 具体参数的显式定义方法被添加到函数的多分派查找中 table 在它们被定义的地方。
- 每当使用不存在显式定义方法的特定参数调用函数时,将编译这些参数的具体版本并将其添加到 vtable。 (但是,如果您 运行
methods()
在该函数名称上,这不会显示为显式方法) - 第一次调用这样的函数会产生一些编译开销;但是,后续调用将使用现有的编译版本*。
我不会说这使得函数 mutable 不过,这是一个完全不同的问题。您可以在函数 'handle'.
上使用isimmutable()
函数来确认它们是 immutable
*我知道模块可以预编译,但我不完全确定这些即时编译版本是否以任何形式在会话之间保存-- 欢迎评论:)
即使仅用于调试,动态性也是您应用程序中的一项真正资产。试图阻止函数以后被更新、重新定义等可能有点短视。但是如果你确定你想要静态调度,你可以定义你自己的 class 通用函数,这要归功于 MOP,即元对象协议,它不是标准的一部分,但仍然在很大程度上得到支持。这就是 Inlined-Generic-Function 库提供的功能(这是可能的,因为 CLOS 对扩展开放)。
在 Common Lisp 中,您可以从规范中阅读以下内容:
7.6.1 Introduction to Generic Functions
When a
defgeneric
form is evaluated, one of three actions is taken (due toensure-generic-function
):
- If a generic function of the given name already exists, the existing generic function object is modified. Methods specified by the current
defgeneric
form are added, and any methods in the existing generic function that were defined by a previousdefgeneric
form are removed. Methods added by the currentdefgeneric
form might replace methods defined bydefmethod
,defclass
,define-condition
, ordefstruct
. No other methods in the generic function are affected or replaced.- If the given name names an ordinary function, a macro, or a special operator, an error is signaled.
- Otherwise a generic function is created with the methods specified by the method definitions in the
defgeneric
form.
When a method-defining form is evaluated, a method object is created and one of four actions is taken:
- If a generic function of the given name already exists and if a method object already exists that agrees with the new one on parameter specializers and qualifiers, the new method object replaces the old one. For a definition of one method agreeing with another on parameter specializers and qualifiers, see Section 7.6.3 (Agreement on Parameter Specializers and Qualifiers).
- If a generic function of the given name already exists and if there is no method object that agrees with the new one on parameter specializers and qualifiers, the existing generic function object is modified to contain the new method object.
- If the given name names an ordinary function, a macro, or a special operator, an error is signaled.
- Otherwise a generic function is created with the method specified by the method-defining form.
If function-name specifies a generic function that has a different value for the
:lambda-list
argument, and the new value is congruent with the lambda lists of all existing methods or there are no methods, the value is changed; otherwise an error is signaled.If function-name specifies a generic function that has a different value for the
:generic-function-class
argument and if the new generic function class is compatible with the old,change-class
is called to change the class of the generic function; otherwise an error is signaled.If function-name specifies a generic function that has a different value for the
:method-class
argument, the value is changed, but any existing methods are not changed.
你还有add-method
and remove-method
.
如您所见,泛型函数在 defmethod
定义之间,甚至在 defgeneric
定义之间保留它们的标识。通用函数在 Common Lisp 中是可变的。
在 Julia 中,您可以从文档中阅读以下内容:
To define a function with multiple methods, one simply defines the function multiple times, with different numbers and types of arguments. The first method definition for a function creates the function object, and subsequent method definitions add new methods to the existing function object.
如您所见,函数对象在 Julia 中是可变的。
这并没有说明所有其他多调度语言。你现在可以发明一种多重调度语言,只是为了展示你可以用不变性来做到这一点,例如添加方法将 return 一个与之前的函数相似但具有添加的方法的新函数。或者一种在编译时静态生成函数的语言,这样您就无法在运行时以任何方式更改它,甚至不能添加或删除方法。
在 Dylan 中,方法通常在编译时添加到泛型函数中,但它们也可能在 运行 时添加(通过 add-method or remove-method). However, a generic function may be sealed,这会阻止除其中的库之外的库g.f。是通过添加方法定义的。所以为了回答你的问题,在 Dylan 中,泛型函数在定义库中总是可变的,但它们可能对其他库不可变。