问题描述
我一直在考虑将某些Python代码移植到静态类型的语言(例如F#或Scala)时会错过什么?库可以被替换,简洁性是可比的,但是我有很多python代码,如下所示:
I've been thinking about what I would miss in porting some Python code to a statically typed language such as F# or Scala; the libraries can be substituted, the conciseness is comparable, but I have lots of python code which is as follows:
@specialclass
class Thing(object):
@specialFunc
def method1(arg1, arg2):
...
@specialFunc
def method2(arg3, arg4, arg5):
...
装饰器在哪里做大量工作:用状态可调用对象替换方法,用其他数据和属性扩展类,等等.尽管Python允许任何人随时随地进行动态猴子补丁元编程,但我发现基本上,我所有的元编程都是在程序的单独阶段"中完成的.即:
Where the decorators do a huge amount: replacing the methods with callable objects with state, augmenting the class with additional data and properties, etc.. Although Python allows dynamic monkey-patch metaprogramming anywhere, anytime, by anyone, I find that essentially all my metaprogramming is done in a separate "phase" of the program. i.e.:
load/compile .py files
transform using decorators
// maybe transform a few more times using decorators
execute code // no more transformations!
这些阶段基本上是完全不同的;我不在修饰器中运行任何应用程序级代码,也没有在主应用程序代码中执行任何忍者用其他类替换类或用其他功能替换功能.尽管这种语言的动态性"表明我可以在任何需要的地方执行此操作,但是我从来没有回避替换主应用程序代码中的函数或重新定义类,因为它很快就会变得疯狂.
These phases are basically completely distinct; I do not run any application level code in the decorators, nor do I perform any ninja replace-class-with-other-class or replace-function-with-other-function in the main application code. Although the "dynamic"ness of the language says I can do so anywhere I want, I never go around replacing functions or redefining classes in the main application code because it gets crazy very quickly.
从本质上讲,我是在开始运行代码之前对代码执行一次重新编译.
I am, essentially, performing a single re-compile on the code before i start running it.
我在静态类型语言中认识到的唯一相似的元象形图就是反射:即从字符串获取函数/类,使用参数数组调用方法等.但是,这基本上将静态类型语言转换为动态类型语言,从而丢失了所有内容输入安全性(如果我输入错了,请纠正我吗?).理想情况下,我认为我应该有以下内容:
The only similar metapogramming i know of in statically typed languages is reflection: i.e. getting functions/classes from strings, invoking methods using argument arrays, etc. However, this basically converts the statically typed language into a dynamically typed language, losing all type safety (correct me if i'm wrong?). Ideally, I think, I would have something like the following:
load/parse application files
load/compile transformer
transform application files using transformer
compile
execute code
从本质上讲,您将使用通过常规编译器编译的任意代码来扩展编译过程,该代码将对主要应用程序代码执行转换.关键是它实际上是在严格保持类型安全的同时模拟加载,转换,执行"工作流.
Essentially, you would be augmenting the compilation process with arbitrary code, compiled using the normal compiler, that will perform transformations on the main application code. The point is that it essentially emulates the "load, transform(s), execute" workflow while strictly maintaining type safety.
如果应用程序代码被拒绝,则编译器将投诉,如果转换器代码被拒绝,则编译器将投诉,如果转换器代码编译但未执行正确的操作,则它将崩溃或之后的编译步骤将抱怨最后的类型不累加.无论如何,通过使用反射来进行动态调度,您将永远不会出现运行时类型错误:在每一步都将对其进行静态检查.
If the application code are borked the compiler will complain, if the transformer code is borked the compiler will complain, if the transformer code compiles but doesn't do the right thing, either it will crash or the compilation step after will complain that the final types don't add up. In any case, you will never get the runtime type-errors possible by using reflection to do dynamic dispatch: it would all be statically checked at every step.
所以我的问题是,这可能吗?已经用我不知道的某种语言或框架完成了吗?理论上不可能吗?我对编译器或形式语言理论不是很熟悉,我知道它将使编译步骤完成并且不保证会终止,但是在我看来,这就是我需要匹配的便捷代码类型,转换时,我会使用动态语言,同时保持静态类型检查.
So my question is, is this possible? Has it already been done in some language or framework which I do not know about? Is it theoretically impossible? I'm not very familiar with compiler or formal language theory, I know it would make the compilation step turing complete and with no guarantee of termination, but it seems to me that this is what I would need to match the sort of convenient code-transformation i get in a dynamic language while maintaining static type checking.
一个示例用例是一个完全通用的缓存装饰器.在python中将是:
One example use case would be a completely generic caching decorator. In python it would be:
cacheDict = {}
def cache(func):
@functools.wraps(func)
def wrapped(*args, **kwargs):
cachekey = hash((args, kwargs))
if cachekey not in cacheDict.keys():
cacheDict[cachekey] = func(*args, **kwargs)
return cacheDict[cachekey]
return wrapped
@cache
def expensivepurefunction(arg1, arg2):
# do stuff
return result
虽然高阶函数可以执行某些操作,而内部带功能的对象可以执行某些操作,但是AFAIK不能将它们通用化为与使用任意参数集并在保持类型的同时返回任意类型的任何函数一起使用安全.我可以做类似的事情:
While higher order functions can do some of this or objects-with-functions-inside can do some of this, AFAIK they cannot be generalized to work with any function taking an arbitrary set of parameters and returning an arbitrary type while maintaining type safety. I could do stuff like:
public Thingy wrap(Object O){ //this probably won't compile, but you get the idea
return (params Object[] args) => {
//check cache
return InvokeWithReflection(O, args)
}
}
但是所有的强制转换完全破坏了类型安全性.
But all the casting completely kills type safety.
这是一个简单的示例,其中函数签名未更改.理想情况下,我正在寻找的内容可以修改函数签名,更改输入参数或输出类型(即a.l.a.函数组成),同时仍保持类型检查.
This is a simple example, where the function signature does not change. Ideally what I am looking for could modify the function signature, changing the input parameters or output type (a.l.a. function composition) while still maintaining type checking.
推荐答案
一个非常有趣的问题.
有关Scala元编程的一些要点:
Some points regarding metaprogramming in Scala:
-
在scala 2.10中, scala反射
您正在寻找源到源转换(宏)方面的工作:scalamacros.org
There is work in source to source transformation (macros) which is something you are looking for: scalamacros.org
Java具有自省功能(通过反射api),但不允许自我修改.但是,您可以使用工具来支持此功能(例如 javassist ).从理论上讲,您可以在Scala中使用这些工具实现自省.
Java has introspection (through the reflection api) but does not allow self modification. However you can use tools to support this (such as javassist). In theory you could use these tools in Scala to achieve more than introspection.
根据我对您开发过程的了解,您将域代码与修饰符(或者您可能会横切的关注点)分离开来,从而实现了模块化和代码简化.对于面向方面的编程,这可能是一个很好的用途,它可以做到这一点.对于Java,有一个库( aspectJ ),但是我怀疑它是否可以与Scala一起运行.
From what I could understand of your development process, you separate your domain code from your decorators (or a cross cutting concern if you will) which allow to achieve modularity and code simplicity. This can be a good use for aspect oriented programming, which allows to just that. For Java theres is a library (aspectJ), however I'm dubious it will run with Scala.
这篇关于静态类型的元编程?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!