Clojure:如果在源代码中定义之前调用一个函数,为什么它应该是`declare` [英] Clojure: Why a function should be `declare` if it is called before definition in the source code

查看:15
本文介绍了Clojure:如果在源代码中定义之前调用一个函数,为什么它应该是`declare`的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 Clojure 中,如果您在定义之前调用函数,例如

In Clojure, if you call a function before its definition, e.g.

(foo (bar 'a))

(defn bar [] ...)

它没有被编译.一个应该添加

it is not compiled. One should add

(declare bar)

(foo (bar 'a)) 之前.为什么 Clojure 是这样设计的?我的意思是,在大多数语言中,除了 C/C++,比如 Java、Python、PHP、Scala、Haskell 甚至其他 Lisps,尤其是在动态类型语言中,不需要函数声明,即函数定义可以放在在通话之前或之后.我觉得用起来不舒服.

before (foo (bar 'a)). Why Clojure is designed as this? I mean, in most languages, except C/C++, such as Java, Python, PHP, Scala, Haskell or even other Lisps, especially in dynamic-type languages, function declaration is not needed, that is, function definition could be put either before or after a call. I feel it uncomfortable to use.

推荐答案

Clojure 进行单程编译(我简化了,请阅读以下链接):

Clojure does a single-pass compilation (well I simplify, read the following links) :

因此,如果您只阅读一次源代码,从上到下,您无法像前向声明这样的事情并且安全地做到这一点,这似乎是合乎逻辑的.

So it seems logical that if you read the source only one time, from top to bottom you cannot have things like forward declaration and do it safely.

引用 Rich(第一个链接):

To quote Rich (first link) :

但是,这里应该发生什么,当编译器以前从未见过吧?

But, what should happen here, when the compiler has never before seen bar?

`(defn foo [] (bar))`

或在 CL 中:

`(defun foo () (bar))`

CL 愉快地编译了它,如果 bar 从来没有定义,就会出现运行时错误.好的,但是,什么具体化的东西(符号)它在编译过程中是否用于 bar ?它收容的符号阅读表格时.那么,当您获得运行时会发生什么错误并意识到 bar 是在您忘记的另一个包中定义的进口.您尝试导入 other-package 并且,BAM!,另一个错误 -冲突,other-package:bar 与 read-in-package:bar 冲突.然后你去了解一下非实习.

CL happily compiles it, and if bar is never defined, a runtime error will occur. Ok, but, what reified thing (symbol) did it use for bar during compilation? The symbol it interned when the form was read. So, what happens when you get the runtime error and realize that bar is defined in another package you forgot to import. You try to import other-package and, BAM!, another error - conflict, other-package:bar conflicts with read-in-package:bar. Then you go learn about uninterning.

在 Clojure 中,表单无法编译,您收到一条消息,并且没有为 bar 实习的 var.你需要其他命名空间并继续.

In Clojure, the form doesn't compile, you get a message, and no var is interned for bar. You require other-namespace and continue.

我非常喜欢这种体验,所以做出了这些权衡.许多其他好处来自使用非实习读者,仅在定义/声明时实习.我不想放弃它们,也不想放弃前面提到的好处,为了支持循环引用.

I vastly prefer this experience, and so made these tradeoffs. Many other benefits came about from using a non-interning reader, and interning only on definition/declaration. I'm not inclined to give them up, nor the benefits mentioned earlier, in order to support circular reference.

这篇关于Clojure:如果在源代码中定义之前调用一个函数,为什么它应该是`declare`的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆