Scheme和Lisp最佳实践:对于Scheme的递归是,对于Lisp是否为no?

147*_*7pm 4 scheme elisp common-lisp racket

据我所知 - 如果错误我会在这里纠正 - 良好的Scheme实践是做任何需要循环的事情,重复递归,而且溢出不会成为问题,因为尾部递归是内置的.Lisp的,但是,没有保护免受溢出,因此,所有的循环迭代宏(loop,while,等).因此在现实世界的Lisp中,你通常不使用递归,而Scheme只需要它.

如果我的假设是正确的,有没有办法用Lisp"纯粹"而不是冒险溢出?或者这对游戏来说太过游泳以在Lisp中使用递归?我从The Little Schemer回忆起他们如何通过递归给你一个彻底的锻炼.还有一个名为The Little Lisper的早期版本.它是否在Lisp中为您提供相同的递归训练?然后Land of Lisp让我对循环或递归是否是"最佳实践"感到困惑.

我要做的是决定是否在Emacs组织模式中使用Racket,或者只为初学者使用内置的Elisp.我希望学生保持尽可能纯粹的功能,例如,我不想解释递归的新的和困难的话题,然后说"哦,但我们不会使用它......"

cor*_*ump 6

据我所知 - 如果错误我会在这里纠正 - 良好的Scheme实践是做任何需要循环的事情,重复递归,而且溢出不会成为问题,因为尾部递归是内置的.

据我所知,这是正确的.

但是,Lisp没有溢出保护[...]

不完全是.大多数自我相应的Common Lisp实现提供尾调用合并(有一些限制,请参阅https://0branch.com/notes/tco-cl.html).不同之处在于语言规范没有要求.这样可以在实现各种Common Lisp功能时为编译器编写者提供更多自由.Emacs Lisp没有TCO,除了以recurtco(自递归)等库的形式.

...因此,所有循环迭代宏(循环,而等).因此在现实世界的Lisp中,你通常不使用递归,而Scheme只需要它.

差异主要是文化.取一个REPL(Read-Eval-Print- Loop).我认为将交互视为循环而不是无限尾递归函数更有意义.不知何故,在纯函数式语言中似乎有些不情愿甚至将循环视为原始控制结构,而迭代过程被认为更优雅.为什么不两个?

如果我的假设是正确的,有没有办法用Lisp"纯粹"而不是冒险溢出?或者这对游戏来说太过游泳以在Lisp中使用递归?

你肯定可以在Lisp中使用递归,只要你不滥用它,小程序就不应该这样.例如,考虑map在OCaml中不是尾递归,但人们仍然经常使用它.如果您使用SBCL,手册中有一节说明如何强制执行尾部呼叫消除.

我要做的是决定是否在Emacs组织模式中使用Racket,或者只为初学者使用内置的Elisp.我希望学生保持尽可能纯粹的功能,例如,我不想解释递归的新的和困难的话题,然后说"哦,但我们不会使用它......"

如果您想教授函数式编程,请使用功能更强大的语言.换句话说,在Racket和Emacs Lisp之间,我会说Racket更适合学生.使用Racket教授功能编程的材料还有很多,还有Typed Racket.

  • 我本可以将DrRacket作为IDE使用,并使用lambda的高级学生.它允许学生单步执行代码,这是其他语言无法实现的.我学习了Java的递归.我不认为TCO应该是学习语言的问题,但我认为所有语言都应该获得它.我的第一个口齿不清是CL,它有很多好的部分. (2认同)

Rai*_*wig 5

典型的Lisp方言和各种Scheme方言之间存在很多差异:

方案

  • 需要尾调用优化
  • 有利于在命令式循环结构上的尾递归
  • 不喜欢势在必行的控制流程
  • 提供功能抽象
  • 尝试将控制结构映射到函数(请参阅例如CALL-WITH-CURRENT-CONTINUATION)
  • 实现一些循环宏作为扩展

口齿不清

部分内容适用于Lisp方言,如Emacs Lisp,Common Lisp或ISLisp.

  • 具有低级控制流,例如GOTO类构造:不要在用户级代码中使用它们,有时它们可​​能在宏中很有用.
  • 没有标准化甚至提供尾部调用优化:为了最大程度的可移植性,您的代码中不需要TCO
  • 提供简单的宏:DO,DOTIMES,DOLIST:在直接适用的地方使用它们
  • 提供复杂的宏:LOOP或ITERATE作为库
  • 提供MAP,MAPCAR,REDUCE等功能抽象

实现通常对堆栈大小有严格的限制,这使得非TCO递归函数成为问题.通常,可以预先设置较大的堆栈大小或在运行时扩展堆栈大小.

尾调用优化与动态范围构造(如特殊变量或类似变量)有一些不兼容性.

有关Common Lisp中的TCO支持,请参阅:Common Lisp实现中的尾调用优化

样式

  • 有些人更喜欢递归函数,但我不会一般使用它.一般来说,我(这是我个人的观点)比一般递归调用更喜欢显式循环结构.其他人更喜欢使用递归函数的更多数学方法.
  • 如果存在像MAP这样的高阶函数,请使用它.
  • 如果循环代码变得更复杂,使用强大的LOOP语句可能很有用