Clojure,尝试调用未绑定的函数

3
我尝试使用递归在Clojure中创建阶乘函数。
(defn fac[x] (if (= x 1) 1 (* x (fac (- x 1)))))

现在,当我尝试调用函数 (fac 5) 时,出现了异常。
java.lang.IllegalStateException: Attempting to call unbound fn: #'sandbox11355/fac

这是否意味着在使用defn关键字定义函数时无法使用递归?
另外,我应该如何高效地掌握这种函数式语法,因为我习惯了命令式/OOP的思维方式?在反向输入所有内容时感觉非常尴尬。在过程范式中,思维的连续性直接映射到新代码行,从而改变值。在函数式语法中,为了操作当前值的每个步骤,我必须将新函数包装在表达式周围,并且很难跟踪括号和作用域。我应该学会以相反的顺序思考过程模型以流畅地编写函数式风格的代码吗?
我理解没有可变状态和纯函数的好处(更少的错误),但很难相信它值得放弃编写过程式代码的方便性。目前,所有这些似乎都是被夸大的、杂乱无章的东西,但也许开始变得有意义了。

2
我无法重现你所看到的异常,并且我期望它能正常工作。Lisp语法需要几天时间来适应 - 确保你使用一个可以为你对齐代码的编辑器,而不是编写冗长的单行表达式,这样会更清晰明了。 - undefined
我同意 - 这应该可以正常工作。你使用的Clojure版本是哪个? - undefined
你的 defn 没有问题。你正在编译的文件是否与此次编辑保持最新? - undefined
我正在使用 tryclj 在线 REPL。也许系统有缺陷。编辑:显然函数开始工作了,那个网站肯定有 bug。 - undefined
1个回答

7
关于函数式编程和过程式编程的一些信息如下。它并不是过程式编程的倒转,而是更高层次的抽象,我们所接触到的几乎所有东西都可以看作是抽象的;否则,我们将无法做任何有用的事情,因为我们将对每一个处理的细节感到非常关注。同样地,任何语言中的所有代码最终都成为了一系列指令,这些指令是"命令式"或"过程式"的典型代表。问题在于,“为了解决我的问题,我需要对极低层面的细节拥有多少控制权?”

以下是一种比较明显的加法方法(只是伪代码,希望意图清晰):

int nums[10] = {0,1,2,3,4,5,6,7,8,9};
int i = 0;
int acc = 0;

start_loop:
  if (i >= 10) goto done_loop;

  int num_address = (nums + i);
  int num_value = *num_address;
  acc = acc + num_value;
  i = i + 1;
  goto start_loop;

done_loop:
  return acc;

虽然有些繁琐,但比汇编代码要简单得多。为了抽象出一些循环的细节,C/java等语言提供了一个控制结构叫做for循环:

int nums[10] = {0,1,2,3,4,5,6,7,8,9};
int acc = 0;

for (int i = 0; i < 10; i++)
  acc += nums[i];

return acc;

当你经常编写命令式代码时,这似乎是完全正常的。你会迭代地思考并了解如何从其基础开始访问数组的每个偏移量的细节。然而,这也可以被认为是很烦琐的。我为什么要关心如何访问数组的每个成员的细节呢?任何函数式语言提供的进一步抽象被称为reduce。将其视为类似于在C / java等程序员中提供for工具的方式。它看起来很奇怪,就像汇编程序员第一次看到for语法时一样:

(reduce + (range 10))

所以我们在这里做的就是将循环的细节抽象出来,使我们不用过多考虑实际发生的循环。我们还抽象出了创建显式数字范围的细节,只需说“给我从0(包括)到10(不包括)的整数”。这只是抽象出细节。结果通常是更能集中精力解决问题。
对于加法或更高级别的思考,函数式编程通常允许我们更有效率地编写较少的代码,同时让各种级别的编译器为我们处理混乱的细节。然而,如果问题非常低级,则可能希望语言中的结构更适合我们的问题。关键始终是使用正确的工具来完成正确的工作。
当然,这不是一个完美的世界,通常在clojure中,我们不得不编写处理位和字节、同步并发代码、循环等低级细节。但通常,声明性地陈述您想要做什么,而不是更明确地说明如何做,有许多好处。
尝试一下4clojure问题,再给自己一个月或两个月的时间开始真正理解,并允许自己的思维从变异变量转向评估表达式。非常有可能你会喜欢它,最坏的情况是你可以拓展自己的视野。祝好运并玩得开心!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接