Add all the A tasks

This commit is contained in:
Ingy döt Net 2013-04-10 14:58:50 -07:00
parent 2dd7375f96
commit 051504d65b
1608 changed files with 18584 additions and 0 deletions

View file

@ -0,0 +1,15 @@
While implementing a recursive function, it often happens that we must resort to a separate "helper function" to handle the actual recursion.
This is usually the case when directly calling the current function would waste too many resources (stack space, execution time), cause unwanted side-effects, and/or the function doesn't have the right arguments and/and return values.
So we end up inventing some silly name like "foo2" or "foo_helper". I have always found it painful to come up with a proper name, and see a quite some disadvantages:
* You have to think up a name, which then pollutes the namespace
* A function is created which is called from nowhere else
* The program flow in the source code is interrupted
Some languages allow you to embed recursion directly in-place. This might work via a label, a local ''gosub'' instruction, or some special keyword.
Anonymous recursion can also be accomplished using the [[Y combinator]].
If possible, demonstrate this by writing the recursive version of the fibonacci function (see [[Fibonacci sequence]]) which checks for a negative argument before doing the actual recursion.

View file

@ -0,0 +1,2 @@
---
note: Recursion

View file

@ -0,0 +1,16 @@
function Fib (X: in Integer) return Integer is
function Actual_Fib (N: in Integer) return Integer is
begin
if N < 2 then
return N;
else
return Actual_Fib (N-1) + Actual_Fib (N-2);
end if;
end Actual_Fib;
begin
if X < 0 then
raise Constraint_Error;
else
return Actual_Fib (X);
end if;
end Fib;

View file

@ -0,0 +1,8 @@
fib(n)
{ if(n < 0)
return error
else if(n < 2)
return 1
else
return n * fib(n-1)
}

View file

@ -0,0 +1,3 @@
fib(n)
{ return n < 0 ? "error" : n < 2 ? 1 : n * fib(n-1)
}

View file

@ -0,0 +1,10 @@
)abbrev package TESTP TestPackage
Z ==> Integer
TestPackage : with
fib : Z -> Z
== add
fib x ==
x <= 0 => error "argument outside of range"
f : Reference((Z,Z,Z) -> Z) := ref((n, v1, v2) +-> 0)
f() := (n, v1, v2) +-> if n<2 then v2 else f()(n-1,v2,v1+v2)
f()(x,1,1)

View file

@ -0,0 +1,10 @@
#include "aldor";
#include "aldorio";
import from Integer;
Z ==> Integer;
fib(x:Z):Z == {
x <= 0 => throw SyntaxException;
f(n:Z,v1:Z,v2:Z):Z == if n<2 then v2 else f(n-1,v2,v1+v2);
f(x,1,1);
}
stdout << fib(10000);

View file

@ -0,0 +1,29 @@
#include <stdio.h>
long fib(long x)
{
long fib_i(long n) { return n < 2 ? n : fib_i(n - 2) + fib_i(n - 1); };
if (x < 0) {
printf("Bad argument: fib(%ld)\n", x);
return -1;
}
return fib_i(x);
}
long fib_i(long n) /* just to show the fib_i() inside fib() has no bearing outside it */
{
printf("This is not the fib you are looking for\n");
return -1;
}
int main()
{
long x;
for (x = -1; x < 4; x ++)
printf("fib %ld = %ld\n", x, fib(x));
printf("calling fib_i from outside fib:\n");
fib_i(3);
return 0;
}

View file

@ -0,0 +1,7 @@
(defn fib [n]
(when (neg? n)
(throw (new IllegalArgumentException "n should be > 0")))
(loop [n n, v1 1, v2 1]
(if (< n 2)
v2
(recur (dec n) v2 (+ v1 v2)))))

View file

@ -0,0 +1,17 @@
# This is a rather obscure technique to have an anonymous
# function call itself.
fibonacci = (n) ->
throw "Argument cannot be negative" if n < 0
do (n) ->
return n if n <= 1
arguments.callee(n-2) + arguments.callee(n-1)
# Since it's pretty lightweight to assign an anonymous
# function to a local variable, the idiom below might be
# more preferred.
fibonacci2 = (n) ->
throw "Argument cannot be negative" if n < 0
recurse = (n) ->
return n if n <= 1
recurse(n-2) + recurse(n-1)
recurse(n)

View file

@ -0,0 +1,13 @@
define function fib (n)
when (n < 0)
error("Can't take fibonacci of negative integer: %d\n", n)
end;
local method fib1 (n, a, b)
if (n = 0)
a
else
fib1(n - 1, b, a + b)
end
end;
fib1(n, 0, 1)
end

View file

@ -0,0 +1,7 @@
:noname ( n -- n' )
dup 2 < ?exit
1- dup recurse swap 1- recurse + ; ( xt )
: fib ( +n -- n' )
dup 0< abort" Negative numbers don't exist."
[ ( xt from the :NONAME above ) compile, ] ;

View file

@ -0,0 +1,5 @@
( xt from :noname in the previous example )
variable pocket pocket !
: fib ( +n -- n' )
dup 0< abort" Negative numbers don't exist."
[ pocket @ compile, ] ;

View file

@ -0,0 +1,18 @@
integer function fib(n)
integer, intent(in) :: n
if (n < 0 ) then
write (*,*) 'Bad argument: fib(',n,')'
stop
else
fib = purefib(n)
end if
contains
recursive pure integer function purefib(n) result(f)
integer, intent(in) :: n
if (n < 2 ) then
f = n
else
f = purefib(n-1) + purefib(n-2)
end if
end function purefib
end function fib

View file

@ -0,0 +1,47 @@
package main
import "fmt"
func main() {
for _, n := range []int{0, 1, 2, 3, 4, 5, 10, 40, -1} {
f, ok := arFib(n)
if ok {
fmt.Printf("fib %d = %d\n", n, f)
} else {
fmt.Println("fib undefined for negative numbers")
}
}
}
func arFib(n int) (int, bool) {
switch {
case n < 0:
return 0, false
case n < 2:
return n, true
}
return yc(func(recurse fn) fn {
return func(left, term1, term2 int) int {
if left == 0 {
return term1+term2
}
return recurse(left-1, term1+term2, term1)
}
})(n-2, 1, 0), true
}
type fn func(int, int, int) int
type ff func(fn) fn
type fx func(fx) fn
func yc(f ff) fn {
return func(x fx) fn {
return f(func(a1, a2, a3 int) int {
return x(x)(a1, a2, a3)
})
}(func(x fx) fn {
return f(func(a1, a2, a3 int) int {
return x(x)(a1, a2, a3)
})
})
}

View file

@ -0,0 +1,7 @@
fib :: Integer -> Maybe Integer
fib n
| n < 0 = Nothing
| otherwise = Just $ real n
where real 0 = 1
real 1 = 1
real n = real (n-1) + real (n-2)

View file

@ -0,0 +1,6 @@
import Data.Function (fix)
fib :: Integer -> Maybe Integer
fib n
| n < 0 = Nothing
| otherwise = Just $ fix (\f -> (\n -> if n > 1 then f (n-1) + f (n-2) else 1)) n

View file

@ -0,0 +1,2 @@
ghci> map fib [-4..10]
[Nothing,Nothing,Nothing,Nothing,Just 1,Just 1,Just 2,Just 3,Just 5,Just 8,Just 13,Just 21,Just 34,Just 55,Just 89]

View file

@ -0,0 +1,9 @@
public static long fib(int n)
{
if (n < 0)
throw new IllegalArgumentException("n can not be a negative number");
return new Object() {
private long fibInner(int n)
{ return (n < 2) ? n : (fibInner(n - 1) + fibInner(n - 2)); }
}.fibInner(n);
}

View file

@ -0,0 +1,24 @@
import java.util.function.Function;
@FunctionalInterface
interface SelfApplicable<OUTPUT> {
OUTPUT apply(SelfApplicable<OUTPUT> input);
}
class Utils {
public static <INPUT, OUTPUT> SelfApplicable<Function<Function<Function<INPUT, OUTPUT>, Function<INPUT, OUTPUT>>, Function<INPUT, OUTPUT>>> y(Class<INPUT> input, Class<OUTPUT> output) {
return y -> f -> x -> f.apply(y.apply(y).apply(f)).apply(x);
}
public static <INPUT, OUTPUT> Function<Function<Function<INPUT, OUTPUT>, Function<INPUT, OUTPUT>>, Function<INPUT, OUTPUT>> fix(Class<INPUT> input, Class<OUTPUT> output) {
return y(input, output).apply(y(input, output));
}
public static long fib(int m) {
if (m < 0)
throw new IllegalArgumentException("n can not be a negative number");
return fix(Integer.class, Long.class).apply(
f -> n -> (n < 2) ? n : (f.apply(n - 1) + f.apply(n - 2))
).apply(m);
}
}

View file

@ -0,0 +1,11 @@
function fibo(n) {
if (n < 0)
throw "Argument cannot be negative";
else
return (function(n) {
if (n < 2)
return 1;
else
return arguments.callee(n-1) + arguments.callee(n-2);
})(n);
}

View file

@ -0,0 +1,11 @@
function fibo(n) {
if (n < 0)
throw "Argument cannot be negative";
else
return (function fib(n) {
if (n < 2)
return 1;
else
return fib(n-1) + fib(n-2);
})(n);
}

View file

@ -0,0 +1,7 @@
local function Y(x) return (function (f) return f(f) end)(function(y) return x(function(z) return y(y)(z) end) end) end
return Y(function(fibs)
return function(n)
return n < 2 and 1 or fibs(n - 1) + fibs(n - 2)
end
end)

View file

@ -0,0 +1,4 @@
return setmetatable({1,1},{__index = function(self, n)
self[n] = self[n-1] + self[n-2]
return self[n]
end})

View file

@ -0,0 +1,13 @@
<?php
function fib($n) {
if ($n < 0)
throw new Exception('Negative numbers not allowed');
else if ($n < 2)
return 1;
else {
$f = __FUNCTION__;
return $f($n-1) + $f($n-2);
}
}
echo fib(8), "\n";
?>

View file

@ -0,0 +1,14 @@
<?php
function fib($n) {
if ($n < 0)
throw new Exception('Negative numbers not allowed');
$f = function($n) use (&$f) {
if ($n < 2)
return 1;
else
return $f($n-1) + $f($n-2);
};
return $f($n);
}
echo fib(8), "\n";
?>

View file

@ -0,0 +1,14 @@
sub recur (&@) {
my $f = shift;
local *recurse = $f;
$f->(@_);
}
sub fibo {
my $n = shift;
$n < 0 and die 'Negative argument';
recur {
my $m = shift;
$m < 3 ? 1 : recurse($m - 1) + recurse($m - 2);
} $n;
}

View file

@ -0,0 +1,13 @@
sub fib {
my ($n) = @_;
die "negative arg $n" if $n < 0;
# put anon sub on stack and do a magic goto to it
@_ = ($n, sub {
my ($n, $f) = @_;
# anon sub recurs with the sub ref on stack
$n < 2 ? $n : $f->($n - 1, $f) + $f->($n - 2, $f)
});
goto $_[1];
}
print(fib($_), " ") for (0 .. 10);

View file

@ -0,0 +1,6 @@
sub fibo {
my $n = shift;
$n < 0 and die 'Negative argument';
no strict 'refs';
$n < 3 ? 1 : (caller(0))[3]->($n - 1) + (caller(0))[3]->($n - 2);
}

View file

@ -0,0 +1,5 @@
use v5.16;
say sub {
my $n = shift;
$n < 2 ? $n : __SUB__->($n-2) + __SUB__->($n-1)
}->($_) for 0..10

View file

@ -0,0 +1,7 @@
(de fibo (N)
(if (lt0 N)
(quit "Illegal argument" N) )
(recur (N)
(if (> 2 N)
1
(+ (recurse (dec N)) (recurse (- N 2))) ) ) )

View file

@ -0,0 +1,2 @@
(de recur recurse
(run (cdr recurse)) )

View file

@ -0,0 +1,23 @@
:- use_module(lambda).
fib(N, _F) :-
N < 0, !,
write('fib is undefined for negative numbers.'), nl.
fib(N, F) :-
% code of Fibonacci
PF = \Nb^R^Rr1^(Nb < 2 ->
R = Nb
;
N1 is Nb - 1,
N2 is Nb - 2,
call(Rr1,N1,R1,Rr1),
call(Rr1,N2,R2,Rr1),
R is R1 + R2
),
% The Y combinator.
Pred = PF +\Nb2^F2^call(PF,Nb2,F2,PF),
call(Pred,N,F).

View file

@ -0,0 +1,4 @@
>>> Y = lambda f: (lambda x: x(x))(lambda y: f(lambda *args: y(y)(*args)))
>>> fib = lambda f: lambda n: None if n < 0 else (0 if n == 0 else (1 if n == 1 else f(n-1) + f(n-2)))
>>> [ Y(fib)(i) for i in range(-2, 10) ]
[None, None, 0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

View file

@ -0,0 +1,4 @@
>>> Y = lambda f: (lambda x: x(x))(lambda y: lambda *args: f(y(y), *args))
>>> fib = lambda f, n: None if n < 0 else (0 if n == 0 else (1 if n == 1 else f(n-1) + f(n-2)))
>>> [ Y(fib)(i) for i in range(-2, 10) ]
[None, None, 0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

View file

@ -0,0 +1,5 @@
>>> from functools import partial
>>> Y = lambda f: partial(f, f)
>>> fib = lambda f, n: None if n < 0 else (0 if n == 0 else (1 if n == 1 else f(f, n-1) + f(f, n-2)))
>>> [ Y(fib)(i) for i in range(-2, 10) ]
[None, None, 0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

View file

@ -0,0 +1,4 @@
fib2 <- function(n) {
(n >= 0) || stop("bad argument")
( function(n) if (n <= 1) 1 else Recall(n-1)+Recall(n-2) )(n)
}

View file

@ -0,0 +1,11 @@
/*REXX program to show anonymous recursion (of a function/subroutine). */
numeric digits 1e6 /*in case the user goes kaa-razy.*/
do j=0 to word(arg(1) 12, 1) /*use argument or the default: 12*/
say 'fibonacci('j") =" fib(j) /*show Fibonacci sequence: 0──►x */
end /*j*/
exit /*stick a fork in it, we're done.*/
/*──────────────────────────────────subroutines─────────────────────────*/
fib: procedure; if arg(1)>=0 then return .(arg(1))
say "***error!*** argument can't be negative."; exit
.:procedure; arg _; if _<2 then return _; return .(_-1)+.(_-2)

View file

@ -0,0 +1,18 @@
#lang racket
;; Natural -> Natural
;; Calculate factorial
(define (fact n)
(define (fact-helper n acc)
(if (= n 0)
acc
(fact-helper (sub1 n) (* n acc))))
(unless (exact-nonnegative-integer? n)
(raise-argument-error 'fact "natural" n))
(fact-helper n 1))
;; Unit tests, works in v5.3 and newer
(module+ test
(require rackunit)
(check-equal? (fact 0) 1)
(check-equal? (fact 5) 120))

View file

@ -0,0 +1,20 @@
#lang racket
;; Natural -> Natural
;; Calculate fibonacci
(define (fibb n)
(define (fibb-helper n fibb_n-1 fibb_n-2)
(if (= 1 n)
fibb_n-1
(fibb-helper (sub1 n) (+ fibb_n-1 fibb_n-2) fibb_n-1)))
(unless (exact-nonnegative-integer? n)
(raise-argument-error 'fibb "natural" n))
(if (zero? n) 0 (fibb-helper n 1 0)))
;; Unit tests, works in v5.3 and newer
(module+ test
(require rackunit)
(check-exn exn:fail? (lambda () (fibb -2)))
(check-equal?
(for/list ([i (in-range 21)]) (fibb i))
'(0 1 1 2 3 5 8 13 21 34 55 89 144 233
377 610 987 1597 2584 4181 6765)))

View file

@ -0,0 +1,4 @@
def fib(n)
raise RangeError, "fib of negative" if n < 0
(fib2 = proc { |m| m < 2 ? m : fib2[m - 1] + fib2[m - 2] })[n]
end

View file

@ -0,0 +1,2 @@
(-2..12).map { |i| fib i rescue :error }
=> [:error, :error, 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144]

View file

@ -0,0 +1,4 @@
def fib(n)
raise RangeError, "fib of negative" if n < 0
(fib2 = proc { |n| n < 2 ? n : fib2[n - 1] + fib2[n - 2] })[n]
end

View file

@ -0,0 +1,7 @@
# Ruby 1.9
(-2..12).map { |i| fib i rescue :error }
=> [:error, :error, 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144]
# Ruby 1.8
(-2..12).map { |i| fib i rescue :error }
=> [:error, :error, 0, 1, 0, -3, -8, -15, -24, -35, -48, -63, -80, -99, -120]

View file

@ -0,0 +1,5 @@
def fib(n)
raise RangeError, "fib of negative" if n < 0
Hash.new { |fib2, m|
fib2[m] = (m < 2 ? m : fib2[m - 1] + fib2[m - 2]) }[n]
end

View file

@ -0,0 +1,20 @@
require 'continuation' unless defined? Continuation
module Kernel
module_function
def recur(*args, &block)
cont = catch(:recur) { return block[*args] }
cont[block]
end
def recurse(*args)
block = callcc { |cont| throw(:recur, cont) }
block[*args]
end
end
def fib(n)
raise RangeError, "fib of negative" if n < 0
recur(n) { |m| m < 2 ? m : (recurse m - 1) + (recurse m - 2) }
end

View file

@ -0,0 +1,32 @@
require 'continuation' unless defined? Continuation
module Kernel
module_function
def function(&block)
f = (proc do |*args|
(class << args; self; end).class_eval do
define_method(:callee) { f }
end
ret = nil
cont = catch(:function) { ret = block.call(*args); nil }
cont[args] if cont
ret
end)
end
def arguments
callcc { |cont| throw(:function, cont) }
end
end
def fib(n)
raise RangeError, "fib of negative" if n < 0
function { |m|
if m < 2
m
else
arguments.callee[m - 1] + arguments.callee[m - 2]
end
}[n]
end

View file

@ -0,0 +1,9 @@
def Y[A, B](f: (A B) (A B)): A B = f(Y(f))(_)
def fib(n: Int): Option[Int] =
if (n < 0) None
else Some(Y[Int, Int](f i
if (i < 2) 1
else f(i - 1) + f(i - 2))(n))
-2 to 5 map (n (n, fib(n))) foreach println

View file

@ -0,0 +1,9 @@
(define (fibonacci n)
(if (> 0 n)
"Error: argument must not be negative."
(let aux ((a 1) (b 0) (count n))
(if (= count 0)
b
(aux (+ a b) a (- count 1))))))
(map fibonacci '(1 2 3 4 5 6 7 8 9 10))

View file

@ -0,0 +1,10 @@
proc fib n {
# sanity checks
if {[incr n 0] < 0} {error "argument may not be negative"}
apply {x {
if {$x < 2} {return $x}
# Extract the lambda term from the stack introspector for brevity
set f [lindex [info level 0] 1]
expr {[apply $f [incr x -1]] + [apply $f [incr x -1]]}
}} $n
}

View file

@ -0,0 +1 @@
puts [fib 12]

View file

@ -0,0 +1,9 @@
proc fib n {
if {[incr n 0] < 0} {error "argument may not be negative"}
apply {x {expr {
$x < 2
? $x
: [apply [lindex [info level 0] 1] [incr x -1]]
+ [apply [lindex [info level 0] 1] [incr x -1]]
}}} $n
}

View file

@ -0,0 +1,8 @@
# Pick the lambda term out of the introspected caller's stack frame
proc tcl::mathfunc::recurse args {apply [lindex [info level -1] 1] {*}$args}
proc fib n {
if {[incr n 0] < 0} {error "argument may not be negative"}
apply {x {expr {
$x < 2 ? $x : recurse([incr x -1]) + recurse([incr x -1])
}}} $n
}