-
Notifications
You must be signed in to change notification settings - Fork 372
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Proper tail recursion #728
Closed
Closed
Changes from 7 commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
03485c2
Proper tail recursion in Hy
Tritlo ed01286
Added some tests for proper tail recursion
Tritlo f4526d0
Added documentation for TailRec, removed empty lines from tests.
Tritlo 96d2052
Merge remote-tracking branch 'upstream/master'
Tritlo 7c39552
Merge branch 'master' of git://github.com/hylang/hy
Tritlo 24d96e9
Merge branch 'master' of github.com:hylang/hy
Tritlo d71b665
Added clarification on trampoline and recur
Tritlo 3d8dba7
CamelCase to _
Tritlo 28047b8
Fix flake8 error
Tritlo File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
========== | ||
__future__ features | ||
========== | ||
|
||
.. versionadded:: 0.10.2 | ||
|
||
Importing from ``__future__`` allows you to add features to | ||
Hy that are not yet in the main language, due to slowing or | ||
being harder to debug. | ||
|
||
|
||
.. _tailrec: | ||
|
||
|
||
``TailRec`` | ||
=========== | ||
|
||
The ``(import [__future__ [TailRec]])`` command | ||
gives programmers a simple way to use tail-call optimization | ||
(TCO) in their Hy code, with no need for trampoline or recur. | ||
Supports mutually recursive functions. | ||
|
||
A tail call is a subroutine call that happens inside another | ||
procedure as its final action; it may produce a return value which | ||
is then immediately returned by the calling procedure. If any call | ||
that a subroutine performs, such that it might eventually lead to | ||
this same subroutine being called again down the call chain, is in | ||
tail position, such a subroutine is said to be tail-recursive, | ||
which is a special case of recursion. Tail calls are significant | ||
because they can be implemented without adding a new stack frame | ||
to the call stack. Most of the frame of the current procedure is | ||
not needed any more, and it can be replaced by the frame of the | ||
tail call. The program can then jump to the called | ||
subroutine. Producing such code instead of a standard call | ||
sequence is called tail call elimination, or tail call | ||
optimization. Tail call elimination allows procedure calls in tail | ||
position to be implemented as efficiently as goto statements, thus | ||
allowing efficient structured programming. | ||
|
||
-- Wikipedia (http://en.wikipedia.org/wiki/Tail_call) | ||
|
||
Example: | ||
|
||
.. code-block:: hy | ||
|
||
(import [__future__ [TailRec]]) | ||
|
||
(defn fact [n] | ||
(defn facthelper [n acc] | ||
(if (= n 0) | ||
acc | ||
(facthelper (- n 1) (* n acc)))) | ||
(do | ||
(print "Using fact!") | ||
(facthelper n 1))) | ||
|
||
(print (fact 10000)) | ||
|
||
(defn odd [n] | ||
(if (= n 0) | ||
False | ||
(even (- n 1)))) | ||
|
||
(defn even [n] | ||
(if (= n 0) | ||
True | ||
(odd (- n 1)))) | ||
|
||
(print (even 1000)) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,3 +10,4 @@ Contents: | |
anaphoric | ||
loop | ||
multi | ||
future |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
STDLIB = [ | ||
"hy.core.language", | ||
"hy.core.tailrec", | ||
"hy.core.shadow" | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
|
||
(defclass HyTailCall [Exception] | ||
"An exeception to implement Proper Tail Recursion" | ||
[[--init-- | ||
(fn [self __TCFunc &rest args &kwargs kwargs] | ||
(setv self.func __TCFunc) | ||
(setv self.args args) | ||
(setv self.kwargs kwargs) | ||
nil)]]) | ||
|
||
(defn HyTailRec [func] | ||
"""A decorator that takes functions that end in raise HyTailCall(func, *args, **kwargs) | ||
and makes them tail recursive""" | ||
(if (hasattr func "__nonTCO") | ||
func | ||
(do | ||
(defn funcwrapper [&rest args &kwargs kwargs] | ||
(setv funcwrapper.__nonTCO func) | ||
(setv tc (apply HyTailCall (cons func (list args)) kwargs)) | ||
(while True | ||
(try (if (hasattr tc.func "__nonTCO") | ||
(setv ret (apply tc.func.__nonTCO (list tc.args) tc.kwargs)) | ||
(setv ret (apply tc.func (list tc.args) tc.kwargs))) | ||
(catch [err HyTailCall] | ||
(setv tc err)) | ||
(else (break)))) | ||
ret) | ||
funcwrapper))) | ||
|
||
(setv *exports* '[HyTailCall HyTailRec]) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
(import [__future__ [TailRec]]) | ||
|
||
(defn test-mutualtailrec [] | ||
"Testing whether tail recursion in mutually recursive functions work" | ||
(do | ||
(defn tcodd [n] (if (= n 0) False (tceven (- n 1)))) | ||
(defn tceven [n] (if (= n 0) True (tcodd (- n 1)))) | ||
(assert (tceven 1000)))) | ||
|
||
(defn test-selfrecur [] | ||
"Testing whether tail recusion in self recursive functions work" | ||
(do | ||
(defn fact [n] | ||
(defn facthelper [n acc] | ||
(if (= n 0) | ||
acc | ||
(facthelper (- n 1) (* n acc)))) | ||
(facthelper n 1)) | ||
(assert (< 0 (fact 1000))))) |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We use snake-casting rather than camel casing :)