Python 静态类型元编程?

Python 静态类型元编程?,python,scala,f#,metaprogramming,Python,Scala,F#,Metaprogramming,我一直在思考将一些Python代码移植到静态类型语言(如F#或Scala)时会错过什么;这些库可以替换,简洁性相当,但我有很多python代码,如下所示: @specialclass class Thing(object): @specialFunc def method1(arg1, arg2): ... @specialFunc def method2(arg3, arg4, arg5): ... 其中装饰器做了大量的工作:用

我一直在思考将一些Python代码移植到静态类型语言(如F#或Scala)时会错过什么;这些库可以替换,简洁性相当,但我有很多python代码,如下所示:

@specialclass
class Thing(object):
    @specialFunc
    def method1(arg1, arg2):
        ...
    @specialFunc
    def method2(arg3, arg4, arg5):
        ...
其中装饰器做了大量的工作:用状态的可调用对象替换方法,用额外的数据和属性扩充类,等等。。尽管Python允许任何人随时随地进行动态monkey patch元编程,但我发现基本上我所有的元编程都是在程序的一个单独的“阶段”完成的。i、 e:

load/compile .py files
transform using decorators
// maybe transform a few more times using decorators
execute code // no more transformations!
这些阶段基本上是完全不同的;我没有在decorators中运行任何应用程序级代码,也没有在主应用程序代码中用其他类执行任何ninja替换类或用其他函数替换函数。尽管这种语言的“动态”特性说明我可以在任何地方这样做,但我从不在主应用程序代码中替换函数或重新定义类,因为它很快就会变得疯狂

本质上,我是在开始运行代码之前对代码执行一次重新编译

我所知道的静态类型语言中唯一类似的元编程是反射:即从字符串获取函数/类,使用参数数组调用方法等。然而,这基本上将静态类型语言转换为动态类型语言,失去了所有类型安全性(如果我错了,请纠正我?)。我认为,理想情况下,我会有如下内容:

load/parse application files 
load/compile transformer
transform application files using transformer
compile
execute code
本质上,您将使用使用普通编译器编译的任意代码来扩充编译过程,这些代码将在主应用程序代码上执行转换。关键是它本质上模拟了“加载、转换、执行”工作流,同时严格维护了类型安全性

如果应用程序代码被屏蔽,编译器会抱怨,如果转换器代码被屏蔽,编译器会抱怨,如果转换器代码编译但没有做正确的事情,要么它会崩溃,要么后面的编译步骤会抱怨最后的类型没有加起来。在任何情况下,通过使用反射进行动态调度,您永远不会得到可能的运行时类型错误:在每一步都会静态检查

所以我的问题是,这可能吗?是否已经用一些我不知道的语言或框架完成了?理论上不可能吗?我不太熟悉编译器或形式语言理论,我知道这会使编译步骤图灵完整,并且不保证终止,但在我看来,这是我需要的,以匹配我在动态语言中获得的那种方便的代码转换,同时保持静态类型检查

编辑:一个示例用例是一个完全通用的缓存装饰器。在python中,它将是:

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
虽然高阶函数可以做一些这方面的工作,或者具有内部函数的对象可以做一些这方面的工作,但是在维护类型安全性的同时,它们不能被推广到使用任何具有任意参数集并返回任意类型的函数。我可以做一些事情,比如:

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)
    }
}
但是所有的铸造都完全破坏了类型安全性


编辑:这是一个简单的示例,函数签名不会更改。理想情况下,我所寻找的可以修改函数签名,更改输入参数或输出类型(a.l.a.函数组合),同时仍保持类型检查。

非常有趣的问题

有关Scala中元编程的一些要点:

  • 在scala 2.10中,将有以下方面的发展:

  • 源代码到源代码转换(宏)中有一些工作,这是您正在寻找的:scalamacros.org

  • Java有内省(通过反射api),但不允许自我修改。但是,您可以使用工具来支持这一点(例如)。理论上,您可以在Scala中使用这些工具来实现更多的自我反省

  • 从我对您的开发过程的理解来看,您将域代码与装饰器(或者交叉关注点,如果您愿意的话)分离开来,从而实现模块化和代码简单性。这对于面向方面的编程是一个很好的用途,它允许这样做。对于Java,有一个库(),但是我怀疑它是否能与Scala一起运行

    • 如果不知道为什么要这样做,就很难知道这种方法在Scala或F#中是否正确。但是现在忽略这一点,至少在Scala中是可以实现的,尽管不是在语言级别

      编译器插件允许您访问该树,并允许您对该树执行各种操作,所有操作都是完全类型检查的

      在Scala编译器插件中生成合成方法有一些困难——我很难知道这是否会给您带来问题

      可以通过创建一个编译器插件来解决这个问题,该插件生成源代码,然后在单独的过程中进行编译。例如,这就是工作原理

      所以我的问题是,这可能吗

      在静态类型编程语言中,有许多方法可以达到相同的效果

      您基本上已经描述了在执行程序之前对程序进行术语重写的过程。这个功能可能以Lisp宏的形式最为人所知,但一些静态类型语言也有宏系统,最著名的是OCaml的camlp4宏系统,它可以用来扩展语言

      更一般地说,您描述的是一种语言扩展性。有很多选择,不同的语言提供不同的技术。有关更多信息,请参阅我的博客文章。请注意,这些语言中的许多都是研究项目,因此动机是添加新的特性,而不一定是好的特性,因此它们很少使用