Clojure:如果在源代码中的定义之前调用了函数,为什么要对它进行“声明” [英] Clojure: Why a function should be `declare` if it is called before definition in the source code

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

问题描述

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

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

(foo (bar 'a))

(defn bar [] ...)

它未编译。应该添加

(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) :

  • https://news.ycombinator.com/item?id=2467359
  • https://news.ycombinator.com/item?id=2466912

因此,如果您仅阅读源代码,这似乎是合乎逻辑的时间,从上到下,您将无法进行前向声明之类的事情。

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) :


但是,当编译器从未见过
bar时,应该怎么办?

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

`(defn foo [] (bar))`

或在CL中:

`(defun foo () (bar))`

CL会愉快地编译它,并且如果bar从未定义过ed,将发生运行时错误。好的,但是,在编译过程中它对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中,表单无法编译,
您会收到一条消息,并且没有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:如果在源代码中的定义之前调用了函数,为什么要对它进行“声明”的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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