Clojure,试图调用未绑定的fn

时间:2017-04-21 15:56:33

标签: clojure functional-programming

我尝试使用递归

在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思维方式?以相反的顺序键入所有内容感觉很尴尬。通过程序范式,思想的连续体直接映射到改变价值的新代码行。使用函数语法,对于操作当前值的每个步骤,我必须将新函数包装在表达式中,并且很难跟踪parens和scope。我是否应该学会以相反的顺序思考程序模型以流利地编写功能样式?

我理解没有可变状态和纯函数(更少的错误)的好处,但很难相信它失去编写过程代码的便利性。就目前而言,所有这些似乎过于夸张无组织的混乱,但也许它开始有意义。

1 个答案:

答案 0 :(得分:6)

关于您对功能和程序编程的关注的一些信息如下。它不是特别原创,但它可能会让你开始考虑如何考虑这些新东西。

功能编程不是反过来的程序编程。它是一个更高层次的抽象,我们与之交互的大多数东西都可以看作是一种抽象;否则,我们永远不会得到任何有用的东西,因为我们非常关心我们处理的每件小事的细节。同样,任何语言的所有代码最终都会成为CPU的一系列指令,而这些指令是“命令式”的缩影。或者"程序性的。"问题变成了,"为了解决我的问题,我需要对极低的细节进行多少控制?"

将一些数字加在一起的一种方法,非常明确(只是伪代码,希望意图很清楚):

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 / etc提供了一个名为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 / etc程序员for。它看起来很奇怪,就像汇编程序员第一次看到for的语法一样:

(reduce + (range 10))

所以我们在这里所做的就是抽象出循环的细节,以至于我们真的不太关注实际发生的循环。我们还抽象出了创建一个明确的数字范围的细节,并且只是说&#34;给我从0(包括)到10(不包括)&#34;的整数。它只是抽象出细节。结果通常是能够更多地关注手头的问题。

对于添加数字或思考更高级别,编程的功能性方法通常允许我们以更少的代码提高工作效率,同时我们让各级编译器为我们处理混乱的细节。但是,如果问题的水平很低,那么我们可能希望语言中的结构更适合我们的问题。关键是始终使用正确的工具来完成正确的工作。

当然,它并不是一个完美的世界,而且经常在clojure中我们被迫编写处理位和字节的低级细节,同步并发代码,循环等等。但一般来说,声明并陈述你想做什么,而不是更明确地如何这样做,有很多好处。

执行4clojure问题,给它一两个月开始真正有意义,让你的思想从变异变量转变为评估表达式。您很有可能会非常喜欢它,而最糟糕的情况是您可以开阔视野。祝你好运,玩得开心!