This commit is contained in:
Ingy döt Net 2013-04-10 21:29:02 -07:00
parent 764da6cbbb
commit db842d013d
19005 changed files with 197040 additions and 7 deletions

View file

@ -0,0 +1,34 @@
This task is an exercise in [[wp:Call-by-name#Call_by_name|call by name]].
'''Jensen's Device''' is a computer programming technique devised by Danish computer scientist [[wp:Jørn_Jensen|Jørn Jensen]] after studying the [[ALGOL 60]] Report.
The following program was proposed to illustrate the technique. It computes the 100th [[wp:Harmonic_number|harmonic number]]:
'''begin'''
'''integer''' i;
'''real procedure''' sum (i, lo, hi, term);
'''value''' lo, hi;
'''integer''' i, lo, hi;
'''real''' term;
'''comment''' term is passed by-name, and so is i;
'''begin'''
'''real''' temp;
temp := 0;
'''for''' i := lo '''step''' 1 '''until''' hi '''do'''
temp := temp + term;
sum := temp
'''end''';
'''comment''' note the correspondence between the mathematical notation and the call to sum;
print (sum (i, 1, 100, 1/i))
'''end'''
The above exploits [[wp:Call-by-name#Call_by_name|call by name]] to produce the correct answer (5.187...). It depends on the assumption that an expression passed as an actual parameter to a procedure would be re-evaluated every time the corresponding formal parameter's value was required. If the last parameter to ''sum'' had been passed by value, and assuming the initial value of ''i'' were 1, the result would have been 100 × 1/1 = 100.
Moreover, the ''first'' parameter to ''sum'',
representing the "bound" variable of the summation,
must also be passed by name, otherwise it would not be possible
to compute the values to be added.
(On the other hand, the global variable does not have to use the same identifier,
in this case ''i'', as the formal parameter.)
[[wp:Donald_Knuth|Donald Knuth]] later proposed the [[Man or boy test|Man or Boy Test]] as a more rigorous exercise.

View file

@ -0,0 +1,2 @@
---
note: Classic CS problems and programs

View file

@ -0,0 +1,16 @@
BEGIN
INT i;
PROC sum = (REF INT i, INT lo, hi, PROC REAL term)REAL:
COMMENT term is passed by-name, and so is i COMMENT
BEGIN
REAL temp := 0;
i := lo;
WHILE i <= hi DO # ALGOL 68 has a "for" loop but it creates a distinct #
temp +:= term; # variable which would not be shared with the passed "i" #
i +:= 1 # Here the actual passed "i" is incremented. #
OD;
temp
END;
COMMENT note the correspondence between the mathematical notation and the call to sum COMMENT
print (sum (i, 1, 100, REAL: 1/i))
END

View file

@ -0,0 +1,26 @@
with Ada.Text_IO; use Ada.Text_IO;
procedure Jensen_Device is
function Sum
( I : not null access Float;
Lo, Hi : Float;
F : access function return Float
) return Float is
Temp : Float := 0.0;
begin
I.all := Lo;
while I.all <= Hi loop
Temp := Temp + F.all;
I.all := I.all + 1.0;
end loop;
return Temp;
end Sum;
I : aliased Float;
function Inv_I return Float is
begin
return 1.0 / I;
end Inv_I;
begin
Put_Line (Float'Image (Sum (I'Access, 1.0, 100.0, Inv_I'Access)));
end Jensen_Device;

View file

@ -0,0 +1,17 @@
set i to 0
on jsum(i, lo, hi, term)
set {temp, i's contents} to {0, lo}
repeat while i's contents hi
set {temp, i's contents} to {temp + (term's f(i)), (i's contents) + 1}
end repeat
return temp
end jsum
script term_func
on f(i)
return 1 / i
end f
end script
return jsum(a reference to i, 1, 100, term_func)

View file

@ -0,0 +1,11 @@
PRINT FNsum(j, 1, 100, FNreciprocal)
END
DEF FNsum(RETURN i, lo, hi, RETURN func)
LOCAL temp
FOR i = lo TO hi
temp += FN(^func)
NEXT
= temp
DEF FNreciprocal = 1/i

View file

@ -0,0 +1,16 @@
#include <iostream>
int i;
double sum(int &i, int lo, int hi, double (*term)()) {
double temp = 0;
for (i = lo; i <= hi; i++)
temp += term();
return temp;
}
double term_func() { return 1.0 / i; }
int main () {
std::cout << sum(i, 1, 100, term_func) << std::endl;
return 0;
}

View file

@ -0,0 +1,20 @@
using System;
class JensensDevice
{
public static double Sum(ref int i, int lo, int hi, Func<double> term)
{
double temp = 0.0;
for (i = lo; i <= hi; i++)
{
temp += term();
}
return temp;
}
static void Main()
{
int i = 0;
Console.WriteLine(Sum(ref i, 1, 100, () => 1.0 / i));
}
}

View file

@ -0,0 +1,16 @@
#include <stdio.h>
int i;
double sum(int *i, int lo, int hi, double (*term)()) {
double temp = 0;
for (*i = lo; *i <= hi; (*i)++)
temp += term();
return temp;
}
double term_func() { return 1.0 / i; }
int main () {
printf("%f\n", sum(&i, 1, 100, term_func));
return 0;
}

View file

@ -0,0 +1,19 @@
#include <stdio.h>
int i;
#define sum(i, lo_byname, hi_byname, term) \
({ \
int lo = lo_byname; \
int hi = hi_byname; \
\
double temp = 0; \
for (i = lo; i <= hi; ++i) \
temp += term; \
temp; \
})
int main () {
printf("%f\n", sum(i, 1, 100, 1.0 / i));
return 0;
}

View file

@ -0,0 +1,20 @@
// Jensen's device in Clipper (or Harbour)
// A fairly direct translation of the Algol 60
// John M Skelton 11-Feb-2012
function main()
local i
? transform(sum(@i, 1, 100, {|| 1 / i}), "##.###############")
// @ is the quite rarely used pass by ref, {|| ...} is a
// code block (an anonymous function, here without arguments)
// The @i makes it clear that something unusual is occurring;
// a called function which modifies a parameter is commonly
// poor design!
return 0
function sum(i, lo, hi, bFunc)
local temp := 0
for i = lo to hi
temp += eval(bFunc)
next i
return temp

View file

@ -0,0 +1,7 @@
(declaim (inline %sum))
(defun %sum (lo hi func)
(loop for i from lo to hi sum (funcall func i)))
(defmacro sum (i lo hi term)
`(%sum ,lo ,hi (lambda (,i) ,term)))

View file

@ -0,0 +1,4 @@
CL-USER> (sum i 1 100 (/ 1 i))
14466636279520351160221518043104131447711/2788815009188499086581352357412492142272
CL-USER> (float (sum i 1 100 (/ 1 i)))
5.1873775

View file

@ -0,0 +1,14 @@
import std.stdio;
double sum(ref int i, in int lo, in int hi, lazy double term)
pure @safe {
double result = 0.0;
for (i = lo; i <= hi; i++)
result += term();
return result;
}
void main() {
int i;
writeln(sum(i, 1, 100, 1.0/i));
}

View file

@ -0,0 +1,12 @@
function sum(var i : Integer; lo, hi : Integer; lazy term : Float) : Float;
begin
i:=lo;
while i<=hi do begin
Result += term;
Inc(i);
end;
end;
var i : Integer;
PrintLn(sum(i, 1, 100, 1.0/i));

View file

@ -0,0 +1,14 @@
pragma.enable("one-method-object") # "def _.get" is experimental shorthand
def sum(&i, lo, hi, &term) { # bind i and term to passed slots
var temp := 0
i := lo
while (i <= hi) { # E has numeric-range iteration but it creates a distinct
temp += term # variable which would not be shared with the passed i
i += 1
}
return temp
}
{
var i := null
sum(&i, 1, 100, def _.get() { return 1/i })
}

View file

@ -0,0 +1,6 @@
def sum(lo, hi, f) {
var temp := 0
for i in lo..hi { temp += f(i) }
return temp
}
sum(1, 100, fn i { 1/i })

View file

@ -0,0 +1,3 @@
: s>f s>d d>f ;
: sum 0 s>f 1+ swap ?do i over execute f+ loop drop ;
:noname s>f 1 s>f fswap f/ ; 1 100 sum f.

View file

@ -0,0 +1,13 @@
import Control.Monad
import Control.Monad.ST
import Data.STRef
sum' ref_i lo hi term =
return sum `ap`
mapM (\i -> writeSTRef ref_i i >> term) [lo..hi]
foo = runST $ do
i <- newSTRef undefined -- initial value doesn't matter
sum' i 1 100 $ return recip `ap` readSTRef i
main = print foo

View file

@ -0,0 +1,13 @@
record mutable(value) # record wrapper to provide mutable access to immutable types
procedure main()
A := mutable()
write( sum(A, 1, 100, create 1.0/A.value) )
end
procedure sum(A, lo, hi, term)
temp := 0
every A.value := lo to hi do
temp +:= @^term
return temp
end

View file

@ -0,0 +1,3 @@
write( sum(A, 1, 100, create |1.0/A.value) )
...
temp +:= @term

View file

@ -0,0 +1,6 @@
write( sum{A.value, 1, 100, 1.0/A.value} )
...
procedure sum(X)
...
every @X[1] := @X[2] to @X[3] do
temp +:= @^X[4]

View file

@ -0,0 +1,8 @@
jensen=: monad define
'name lo hi expression'=. y
temp=. 0
for_n. lo+i.1+hi-lo do.
(name)=. n
temp=. temp + ".expression
end.
)

View file

@ -0,0 +1,2 @@
jensen 'i';1;100;'1%i'
5.18738

View file

@ -0,0 +1,11 @@
var obj;
function sum(o, lo, hi, term) {
var tmp = 0;
for (o.val = lo; o.val <= hi; o.val++)
tmp += term();
return tmp;
}
obj = {val: 0};
alert(sum(obj, 1, 100, function() {return 1 / obj.val}));

View file

@ -0,0 +1 @@
100 [0] [[1.0 swap /] dip +] primrec.

View file

@ -0,0 +1,8 @@
function sum(var, a, b, str)
local ret = 0
for i = a, b do
ret = ret + setfenv(loadstring("return "..str), {[var] = i})()
end
return ret
end
print(sum("i", 1, 100, "1/i"))

View file

@ -0,0 +1,8 @@
define(`for',
`ifelse($#,0,``$0'',
`ifelse(eval($2<=$3),1,
`pushdef(`$1',$2)$4`'popdef(`$1')$0(`$1',incr($2),$3,`$4')')')')
define(`sum',
`pushdef(`temp',0)`'for(`$1',$2,$3,
`define(`temp',eval(temp+$4))')`'temp`'popdef(`temp')')
sum(`i',1,100,`1000/i')

View file

@ -0,0 +1,4 @@
sum[term_, i_, lo_, hi_] := Block[{temp = 0},
Do[temp = temp + term, {i, lo, hi}];
temp];
SetAttributes[sum, HoldFirst];

View file

@ -0,0 +1,15 @@
mysum(e, v, lo, hi) := block([s: 0], for i from lo thru hi do s: s + subst(v=i, e), s)$
mysum(1/n, n, 1, 10);
7381/2520
/* compare with builtin sum */
sum(1/n, n, 1, 10);
7381/2520
/* what if n is assigned a value ? */
n: 200$
/* still works */
mysum(1/n, n, 1, 10);
7381/2520

View file

@ -0,0 +1,24 @@
$i;
function sum (&$i, $lo, $hi, $term) {
$temp = 0;
for ($i = $lo; $i <= $hi; $i++) {
$temp += $term();
}
return $temp;
}
echo sum($i, 1, 100, create_function('', 'global $i; return 1 / $i;')), "\n";
//Output: 5.18737751764 (5.1873775176396)
function sum ($lo,$hi)
{
$temp = 0;
for ($i = $lo; $i <= $hi; $i++)
{
$temp += (1 / $i);
}
return $temp;
}
echo sum(1,100);
//Output: 5.1873775176396

View file

@ -0,0 +1,11 @@
my $i;
sub sum {
my ($i, $lo, $hi, $term) = @_;
my $temp = 0;
for ($$i = $lo; $$i <= $hi; $$i++) {
$temp += $term->();
}
return $temp;
}
print sum(\$i, 1, 100, sub { 1 / $i }), "\n";

View file

@ -0,0 +1,11 @@
my $i;
sub sum {
my (undef, $lo, $hi, $term) = @_;
my $temp = 0;
for ($_[0] = $lo; $_[0] <= $hi; $_[0]++) {
$temp += $term->();
}
return $temp;
}
print sum($i, 1, 100, sub { 1 / $i }), "\n";

View file

@ -0,0 +1,14 @@
(scl 6)
(de jensen (I Lo Hi Term)
(let Temp 0
(set I Lo)
(while (>= Hi (val I))
(inc 'Temp (Term))
(inc I) )
Temp ) )
(let I (box) # Create indirect reference
(format
(jensen I 1 100 '(() (*/ 1.0 (val I))))
*Scl ) )

View file

@ -0,0 +1,18 @@
class Ref(object):
def __init__(self, value=None):
self.value = value
def harmonic_sum(i, lo, hi, term):
# term is passed by-name, and so is i
temp = 0
i.value = lo
while i.value <= hi: # Python "for" loop creates a distinct which
temp += term() # would not be shared with the passed "i"
i.value += 1 # Here the actual passed "i" is incremented.
return temp
i = Ref()
# note the correspondence between the mathematical notation and the
# call to sum it's almost as good as sum(1/i for i in range(1,101))
print harmonic_sum(i, 1, 100, lambda: 1.0/i.value)

View file

@ -0,0 +1,15 @@
sum <- function(var, lo, hi, term)
eval(substitute({
.temp <- 0;
for (var in lo:hi) {
.temp <- .temp + term
}
.temp
}, as.list(match.call()[-1])),
enclos=parent.frame())
sum(i, 1, 100, 1/i) #prints 5.187378
##and because of enclos=parent.frame(), the term can involve variables in the caller's scope:
x <- -1
sum(i, 1, 100, i^x) #5.187378

View file

@ -0,0 +1,11 @@
/*REXX program to demonstrate Jensen's device (call sub, arg by name). */
numeric digits 50 /*might as well get some accuracy*/
say sum( 'i', "1", '100', "1/i" ) /*invoke SUM (100th harmonic num)*/
exit /*stick a fork in it, we're done.*/
/*──────────────────────────────────SUM subroutine──────────────────────*/
sum: procedure; parse arg i,start,finish,term; sum=0
interpret 'do' i '=' start 'to' finish'; sum=sum+'term'; end'
return sum

View file

@ -0,0 +1,18 @@
#lang algol60
begin
integer i;
real procedure sum (i, lo, hi, term);
value lo, hi;
integer i, lo, hi;
real term;
comment term is passed by-name, and so is i;
begin
real temp;
temp := 0;
for i := lo step 1 until hi do
temp := temp + term;
sum := temp
end;
comment note the correspondence between the mathematical notation and the call to sum;
printnln (sum (i, 1, 100, 1/i))
end

View file

@ -0,0 +1,4 @@
#lang racket/base
(define (sum lo hi f)
(for/sum ([i (in-range lo (add1 hi))]) (f i)))
(sum 1 100 (λ(i) (/ 1.0 i)))

View file

@ -0,0 +1,8 @@
def sum(var, lo, hi, term, context)
sum = 0.0
lo.upto(hi) do |n|
sum += eval "#{var} = #{n}; #{term}", context
end
sum
end
p sum "i", 1, 100, "1.0 / i", binding # => 5.18737751763962

View file

@ -0,0 +1,4 @@
def sum2(lo, hi)
lo.upto(hi).inject(0.0) {|sum, n| sum += yield n}
end
p sum2(1, 100) {|i| 1.0/i} # => 5.18737751763962

View file

@ -0,0 +1,12 @@
class MyInt { var i: Int = _ }
val i = new MyInt
def sum(i: MyInt, lo: Int, hi: Int, term: => Double) = {
var temp = 0.0
i.i = lo
while(i.i <= hi) {
temp = temp + term
i.i += 1
}
temp
}
sum(i, 1, 100, 1.0 / i.i)

View file

@ -0,0 +1,9 @@
(define-syntax sum
(syntax-rules ()
((sum var low high . body)
(let loop ((var low)
(result 0))
(if (> var high)
result
(loop (+ var 1)
(+ result . body)))))))

View file

@ -0,0 +1,9 @@
proc sum {var lo hi term} {
upvar 1 $var x
set sum 0.0
for {set x $lo} {$x < $hi} {incr x} {
set sum [expr {$sum + [uplevel 1 [list expr $term]]}]
}
return $sum
}
puts [sum i 1 100 {1.0/$i}] ;# 5.177377517639621

View file

@ -0,0 +1,8 @@
proc sum2 {lo hi lambda} {
set sum 0.0
for {set n $lo} {$n < $hi} {incr n} {
set sum [expr {$sum + [apply $lambda $n]}]
}
return $sum
}
puts [sum2 1 100 {i {expr {1.0/$i}}}] ;# 5.177377517639621