共递归
例子 > Factorial

A classic example of recursion is computing the factorial, which is defined recursively as  0!:=1 and  n!:=n\times (n-1)!
To recursively compute its result on a given input, a recursive function calls (a copy of) itself with a different ("smaller" in some way) input and uses the result of this call to construct its result. The recursive call does the same, unless the base case has been reached. Thus a call stack develops in the process. For example, to compute fac(3), this recursively calls in turn fac(2), fac(1), fac(0) ("winding up" the stack), at which point recursion terminates with fac(0) = 1, and then the stack unwinds in reverse order and the results are calculated on the way back along the call stack to the initial call frame fac(3), where the final result is calculated as 3*2 =: 6 and finally returned. In this example a function returns a single value.
This stack unwinding can be explicated, defining the factorial corecursively, as an iterator, where one starts with the case of  1=:0!, then from this starting value constructs factorial values for increasing numbers 1, 2, 3... as in the above recursive definition with "time arrow" reversed, as it were, by reading it backwards as  n!\times (n+1)=:(n+1)!. The corecursive algorithm thus defined produces a stream of all factorials. This may be concretely implemented as a generator. Symbolically, noting that computing next factorial value requires keeping track of both n and f (a previous factorial value), this can be represented as:
or in Haskell,
(\(n,f) -> (n+1, f*(n+1))) `iterate` (0,1)
meaning, "starting from  n,f=0,1, on each step the next values are calculated as  n+1,f\times (n+1)". This is mathematically equivalent and almost identical to the recursive definition, but the  +1 emphasizes that the factorial values are being built up, going forwards from the starting case, rather than being computed after first going backwards, down to the base case, with a  -1 decrement. Note also that the direct output of the corecursive function does not simply contain the factorial  n! values, but also includes for each value the auxiliary data of its index n in the sequence, so that any one specific result can be selected among them all, as and when needed.
Note the connection with denotational semantics, where the denotations of recursive programs is built up corecursively in this way.
In Python, a recursive factorial function can be defined as:
def factorial(n):
    if n == 0:
        return 1
    else:
        return n * factorial(n - 1)
This could then be called for example as factorial(5) to compute 5!.
A corresponding corecursive generator can be defined as:
def factorials():
    n, f = 0, 1
    while True:
        yield f
        n, f = n + 1, f * (n + 1)
This generates an infinite stream of factorials in order; a finite portion of it can be produced by:
def n_factorials(k):
    n, f = 0, 1
    while n <= k:
        yield f
        n, f = n + 1, f * (n + 1)
This could then be called to produce the factorials up to 5! via:
for f in n_factorials(5):
    print(f)
If we're only interested in a certain factorial, just the last value can be taken, or we can fuse the production and the access into one function,
def nth_factorial(k):
    n, f = 0, 1
    while n < k:
        n, f = n + 1, f * (n + 1)
    yield f
As can be readily seen here, this is practically equivalent (just by substituting return for the only yield there) to the accumulator argument technique for tail recursion, unwound into an explicit loop. Thus it can be said that the concept of corecursion is an explication of the embodiment of iterative computation processes by recursive definitions, where applicable.