User:Cameron Chandoke/Recursion

From J Wiki
Jump to navigation Jump to search

Introduction

Demonstration of tail call and non-tail-call recursion in J. These are merely for comparative study, as tail calls are not optimized (i.e., unrolled into an iterative loop) in J.

Also a small collection of classic recursive examples.

"Tail call" refers to the final function call executed within a given expression (i.e., the function call at the top of the call stack).

To say that a given recursive function uses "tail-call recursion" means that in each recursive case, the recursive call is the final call executed in the expression.

For example, the following recursive verb, which calculates factorial (equivalent to the primitive verb !):

1:`{{y * $:<:y}}@.{{*y}} 7

is not tail-recursive because in the recursive subexpression {{y * $:<:y}}, the final verb call is the call to * .

By contrast, the following implementation of factorial is tail-recursive:

1 [`{{(x*y) $: <:y}}@.{{*y[x}} 7

because the verb that is executed last within the recursive subexpression {{(x*y) $: <:y}} is the recursive verb $: .

In the wider world of functional programming, the significance of tail-call recursion is that many languages turn a tail-recursive expression into a while-loop under the hood, so that the number of possible "recursive" calls will not be limited by the size of the call stack. (J is not among these languages.)

Collected examples

Recursion scoping adverb:

R=: {{ u{{u y}} : (u{{x u y}}) }}   
   ($:@<: [ echo)^:*R@>: 2
3
2
1
0

Concat -- foldr recursion:

   ({.,$:@}.)^:(0~:#) i.10                               
0 1 2 3 4 5 6 7 8 9

concat -- foldl recursion (dyadic call):

   '' (}.@]$:~{.@],[)`[@.(0=#@]) i.10   
9 8 7 6 5 4 3 2 1 0

concat -- foldl recursion (monadic call):

   ''&$: : (}.@]$:~{.@],[)`[@.(0=#@]) i.10          
9 8 7 6 5 4 3 2 1 0

Note how  seed&$: : tailRecDef  allows for elegantly passing the seed to tacit “go” function in acc-style recursion without requiring a named helper function.

foldr factorial:

   1:`(* $:@<:)@.*"0 i.7            
1 1 2 6 24 120 720

foldl factorial (dyadic call):

   1 [`(* $: <:@])@.(*@])"0 i.7                         
1 1 2 6 24 120 720

foldl factorial (monadic call):

   1&$: : ([`(* $: <:@])@.(*@]))"0 i.7                 
1 1 2 6 24 120 720

bi-partition quicksort:

   (((<:#[) ,&$: (>#[)) (?@#{]))^:(1<#@~.)  10?.50       
4 6 22 28 29 33 39 40 44 45

tri-partition quicksort:

   (($:@(<#[), (=#[), $:@(>#[)) (?@#{]))^:(1<#)  10?.50  
4 6 22 28 29 33 39 40 44 45

Ackermann function with anonymous recursion:

   c1 =: >:@]               
   c2 =: <:@[ $: 1:        
   c3 =: <:@[ $: ($: <:)  
   ack=: c1`(c2 f.)`(c3 f.)@.(,&* i. 0:)M.
   (i.4) ack"0] 3
4 5 9 61