September 2017 Update

This commit is contained in:
Ingy döt Net 2017-09-23 10:01:46 +02:00
parent bba7bfd280
commit ba8067c3b7
14570 changed files with 153136 additions and 63871 deletions

View file

@ -0,0 +1,24 @@
(* ****** ****** *)
//
#include "share/atspre_staload.hats"
//
(* ****** ****** *)
//
fun
myfix
{a:type}
(
f: lazy(a) -<cloref1> a
) : lazy(a) = $delay(f(myfix(f)))
//
val
fact =
myfix{int-<cloref1>int}
(
lam(ff) => lam(x) => if x > 0 then x * !ff(x-1) else 1
)
(* ****** ****** *)
//
implement main0 () = println! ("fact(10) = ", !fact(10))
//
(* ****** ****** *)

View file

@ -1,64 +1,62 @@
-- Y COMBINATOR
-- Y COMBINATOR ---------------------------------------------------------------
on |Y|(f)
script
on lambda(y)
on |λ|(y)
script
on lambda(arg)
y's lambda(y)'s lambda(arg)
end lambda
on |λ|(x)
y's |λ|(y)'s |λ|(x)
end |λ|
end script
f's lambda(result)
end lambda
f's |λ|(result)
end |λ|
end script
result's lambda(result)
result's |λ|(result)
end |Y|
-- TEST
-- TEST -----------------------------------------------------------------------
on run
-- Factorial
script fact
on lambda(f)
on |λ|(f)
script
on lambda(n)
on |λ|(n)
if n = 0 then return 1
n * (f's lambda(n - 1))
end lambda
n * (f's |λ|(n - 1))
end |λ|
end script
end lambda
end |λ|
end script
-- Fibonacci
script fib
on lambda(f)
on |λ|(f)
script
on lambda(n)
on |λ|(n)
if n = 0 then return 0
if n = 1 then return 1
(f's lambda(n - 2)) + (f's lambda(n - 1))
end lambda
(f's |λ|(n - 2)) + (f's |λ|(n - 1))
end |λ|
end script
end lambda
end |λ|
end script
{facts:map(|Y|(fact), range(0, 11)), fibs:map(|Y|(fib), range(0, 20))}
{facts:map(|Y|(fact), enumFromTo(0, 11)), fibs:map(|Y|(fib), enumFromTo(0, 20))}
--> {facts:{1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800},
--> fibs:{0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765}}
--> fibs:{0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987,
-- 1597, 2584, 4181, 6765}}
end run
---------------------------------------------------------------------------
-- GENERIC FUNCTIONS (FOR TEST)
-- GENERIC FUNCTIONS FOR TEST -------------------------------------------------
-- map :: (a -> b) -> [a] -> [b]
on map(f, xs)
@ -66,14 +64,14 @@ on map(f, xs)
set lng to length of xs
set lst to {}
repeat with i from 1 to lng
set end of lst to lambda(item i of xs, i, xs)
set end of lst to |λ|(item i of xs, i, xs)
end repeat
return lst
end tell
end map
-- range :: Int -> Int -> [Int]
on range(m, n)
-- enumFromTo :: Int -> Int -> [Int]
on enumFromTo(m, n)
if n < m then
set d to -1
else
@ -84,7 +82,7 @@ on range(m, n)
set end of lst to i
end repeat
return lst
end range
end enumFromTo
-- Lift 2nd class handler function into 1st class script wrapper
-- mReturn :: Handler -> Script
@ -93,7 +91,7 @@ on mReturn(f)
f
else
script
property lambda : f
property |λ| : f
end script
end if
end mReturn

View file

@ -6,27 +6,25 @@
a potential parameter, to simulate closure */
typedef struct func_t *func;
typedef struct func_t {
func (*func) (func, func), _;
func (*fn) (func, func);
func _;
int num;
} func_t;
func new(func(*f)(func, func), func _) {
func x = malloc(sizeof(func_t));
x->func = f;
x->fn = f;
x->_ = _; /* closure, sort of */
x->num = 0;
return x;
}
func call(func f, func g) {
return f->func(f, g);
func call(func f, func n) {
return f->fn(f, n);
}
func Y(func(*f)(func, func)) {
func _(func x, func y) { return call(x->_, y); }
func_t __ = { _ };
func g = call(new(f, 0), &__);
func g = new(f, 0);
g->_ = g;
return g;
}
@ -37,26 +35,19 @@ func num(int n) {
return x;
}
func fac(func f, func _null) {
func _(func self, func n) {
int nn = n->num;
return nn > 1 ? num(nn * call(self->_, num(nn - 1))->num)
: num(1);
}
return new(_, f);
func fac(func self, func n) {
int nn = n->num;
return nn > 1 ? num(nn * call(self->_, num(nn - 1))->num)
: num(1);
}
func fib(func f, func _null) {
func _(func self, func n) {
int nn = n->num;
return nn > 1
? num( call(self->_, num(nn - 1))->num +
call(self->_, num(nn - 2))->num )
: num(1);
}
return new(_, f);
func fib(func self, func n) {
int nn = n->num;
return nn > 1
? num( call(self->_, num(nn - 1))->num +
call(self->_, num(nn - 2))->num )
: num(1);
}
void show(func n) { printf(" %d", n->num); }

View file

@ -0,0 +1,16 @@
import extensions.
singleton YCombinator
{
fix : func
= (:f)[(:x)[ x eval:x ] eval(:g)[ f eval(:x)[(g eval:g) eval:x] ]] eval:func.
}
program =
[
var fib := YCombinator fix(:f)((:i)( (i <= 1) ifTrue:[^i] ifFalse:[^f eval(i-1) + f eval(i-2) ] )).
var fact := YCombinator fix(:f)((:i)((i == 0) ifTrue:[^1] ifFalse:[^f eval(i-1) * i] )).
console printLine("fib(10)=",fib eval(10)).
console printLine("fact(10)=",fact eval(10)).
].

View file

@ -1,15 +1,27 @@
newtype Mu a = Roll { unroll :: Mu a -> a }
newtype Mu a = Roll
{ unroll :: Mu a -> a }
fix :: (a -> a) -> a
fix = \f -> (\x -> f (unroll x x)) $ Roll (\x -> f (unroll x x))
fix = g <*> (Roll . g)
where
g = (. (>>= id) unroll)
fac :: Integer -> Integer
fac = fix $ \f n -> if (n <= 0) then 1 else n * f (n-1)
fac =
fix $
\f n ->
(if n <= 0
then 1
else n * f (n - 1))
fibs :: [Integer]
fibs = fix $ \fbs -> 0 : 1 : fix zipP fbs (tail fbs)
where zipP f (x:xs) (y:ys) = x+y : f xs ys
fibs =
fix $ (0 :) . (1 :) . (fix (\f (x:xs) (y:ys) -> x + y : f xs ys) <*> tail)
main = do
print $ map fac [1 .. 20]
print $ take 20 fibs
main :: IO ()
main =
mapM_
print
[ map fac [1 .. 20]
, take 20 fibs
]

View file

@ -1,28 +1,36 @@
fix :: (a -> a) -> a
fix f = f (fix f) -- _not_ the {fix f = x where x = f x}
fix f = f (fix f) -- _not_ the {fix f = x where x = f x}
fac :: Integer -> Integer
fac_ f n | n <= 0 = 1
| otherwise = n * f (n-1)
fac = fix fac_ -- fac_ (fac_ . fac_ . fac_ . fac_ . ...)
fac_ f n
| n <= 0 = 1
| otherwise = n * f (n - 1)
fac = fix fac_ -- fac_ (fac_ . fac_ . fac_ . fac_ . ...)
-- a simple but wasteful exponential time definition:
fib :: Integer -> Integer
fib_ f 0 = 0
fib_ f 1 = 1
fib_ f n = f (n-1) + f (n-2)
fib_ f n = f (n - 1) + f (n - 2)
fib = fix fib_
-- Or for far more efficiency, compute a lazy infinite list. This is
-- a Y-combinator version of: fibs = 0:1:zipWith (+) fibs (tail fibs)
fibs :: [Integer]
fibs_ a = 0:1:(fix zipP a (tail a))
where
zipP f (x:xs) (y:ys) = x+y : f xs ys
fibs_ a = 0 : 1 : fix zipP a (tail a)
where
zipP f (x:xs) (y:ys) = x + y : f xs ys
fibs = fix fibs_
-- This code shows how the functions can be used:
main = do
print $ map fac [1 .. 20]
print $ map fib [0 .. 19]
print $ take 20 fibs
main : IO ()
main =
mapM_
print
[ map fac [1 .. 20]
, map fib [0 .. 19]
, take 20 fibs
]

View file

@ -1 +1 @@
Y=. ((((&>)/)(1 : '(5!:5)<''x'''))(&([ 128!:2 ,&<)))f.
Y=. ((((&>)/)((((^:_1)b.)(`(<'0';_1)))(`:6)))(&([ 128!:2 ,&<)))

View file

@ -1,11 +1,11 @@
u=. [ NB. Function (left)
n=. ] NB. Argument (right)
sr=. [ 128!:2 ,&< NB. Self referring
sr=. [ apply f. ,&< NB. Self referring
fac=. (1:`(n * u sr n - 1:)) @. (0: < n)
fac=. (1:`(n * u sr n - 1:)) @. (0 < n)
fac f. Y 10
3628800
Fib=. ((u sr n - 2:) + u sr n - 1:) ^: (1: < n)
Fib=. ((u sr n - 2:) + u sr n - 1:) ^: (1 < n)
Fib f. Y 10
55

View file

@ -1,9 +1,12 @@
fac f. Y NB. Showing the stateless recursive factorial function...
'1:`(] * [ ([ 128!:2 ,&<) ] - 1:)@.(0: < ])&>/'&([ 128!:2 ,&<)
'1:`(] * [ ([ 128!:2 ,&<) ] - 1:)@.(0 < ])&>/'&([ 128!:2 ,&<)
fac f. NB. Showing the stateless factorial step...
1:`(] * [ ([ 128!:2 ,&<) ] - 1:)@.(0: < ])
1:`(] * [ ([ 128!:2 ,&<) ] - 1:)@.(0 < ])
Fib f. Y NB. Showing the stateless recursive Fibonacci function...
'(([ ([ 128!:2 ,&<) ] - 2:) + [ ([ 128!:2 ,&<) ] - 1:)^:(1: < ])&>/'&([ 128!:2 ,&<)
'(([ ([ 128!:2 ,&<) ] - 2:) + [ ([ 128!:2 ,&<) ] - 1:)^:(1 < ])&>/'&([ 128!:2 ,&<)
Fib f. NB. Showing the stateless Fibonacci step...
(([ ([ 128!:2 ,&<) ] - 2:) + [ ([ 128!:2 ,&<) ] - 1:)^:(1: < ])
(([ ([ 128!:2 ,&<) ] - 2:) + [ ([ 128!:2 ,&<) ] - 1:)^:(1 < ])

View file

@ -1,4 +1,4 @@
sr=. [ 128!:2 ,&< NB. Self referring
lw=. '(5!:5)<''x''' (1 :) NB. Linear representation of a word
Y=. (&>)/lw(&sr) f.
Y=. 'Y'f. NB. Fixing it
sr=. [ apply f.,&< NB. Self referring
lv=. (((^:_1)b.)(`(<'0';_1)))(`:6) NB. Linear representation of a verb argument
Y=. (&>)/lv(&sr) f. NB. Y combinator
Y=. 'Y'f. NB. Fixing it

View file

@ -0,0 +1,22 @@
// version 1.1.2
typealias Func<T, R> = (T) -> R
class RecursiveFunc<T, R>(val p: (RecursiveFunc<T, R>) -> Func<T, R>)
fun <T, R> y(f: (Func<T, R>) -> Func<T, R>): Func<T, R> {
val rec = RecursiveFunc<T, R> { r -> f { r.p(r)(it) } }
return rec.p(rec)
}
fun fac(f: Func<Int, Int>) = { x: Int -> if (x <= 1) 1 else x * f(x - 1) }
fun fib(f: Func<Int, Int>) = { x: Int -> if (x <= 2) 1 else f(x - 1) + f(x - 2) }
fun main(args: Array<String>) {
print("Factorial(1..10) : ")
for (i in 1..10) print("${y(::fac)(i)} ")
print("\nFibonacci(1..10) : ")
for (i in 1..10) print("${y(::fib)(i)} ")
println()
}

View file

@ -0,0 +1,42 @@
1) defining the Ycombinator
{def Y
{lambda {:f :n}
{:f :f :n}}}
2) defining non recursive functions
2.1) factorial
{def almost-fac
{lambda {:f :n}
{if {= :n 1}
then 1
else {* :n {:f :f {- :n 1}}}}}}
2.2) fibonacci
{def almost-fibo
{lambda {:f :n}
{if {< :n 2}
then 1
else {+ {:f :f {- :n 1}} {:f :f {- :n 2}}}}}}
3) testing
{Y almost-fac 6}
-> 720
{Y almost-fibo 8}
-> 34
We could also forget the Ycombinator and names:
1) fac:
{{lambda {:f :n} {:f :f :n}}
{lambda {:f :n}
{if {= :n 1}
then 1
else {* :n {:f :f {- :n 1}}}}} 6}
-> 720
2) fibo:
{{lambda {:f :n} {:f :f :n}}
{{lambda {:f :n}
{if {< :n 2} then 1
else {+ {:f :f {- :n 1}} {:f :f {- :n 2}}}}}} 8}
-> 34

View file

@ -1,49 +1,71 @@
use std::sync::Arc;
//! A simple implementation of the Y Combinator
// λf.(λx.xx)(λx.f(xx))
// <=> λf.(λx.f(xx))(λx.f(xx))
//Arc<Box<Closure>>
macro_rules! abc {
($x:expr) => (Arc::new(Box::new($x)));
// CREDITS: A better version of the previous code that was posted here, with detailed explanation.
// See <y> and also <y_apply>.
// A function type that takes its own type as an input is an infinite recursive type.
// We introduce a trait that will allow us to have an input with the same type as self, and break the recursion.
// The input is going to be a trait object that implements the desired function in the interface.
// NOTE: We will be coercing a reference to a closure into this trait object.
trait Apply<T, R> {
fn apply( &self, &Apply<T, R >, T ) -> R;
}
#[derive(Clone)]
enum Mu<T> {
Roll(Arc<Box<Fn(Mu<T>)->T>>),
}
impl<T, R, F> Apply<T, R> for F where F: Fn( &Apply<T, R>, T ) -> R {
fn apply( &self, f: &Apply<T, R>, t: T ) -> R {
self( f, t )
fn unroll<T>(Mu::Roll(f): Mu<T>) -> Arc<Box<Fn(Mu<T>)->T>> {f.clone()}
pub type Func<A> = Arc<Box<Fn(A)->A>>;
pub type RecFunc<A> = Arc<Box<Fn(Func<A>) -> Func<A>>>;
pub fn y<A: 'static>(f: RecFunc<A>) -> Func<A> {
let g: Arc<Box<Fn(Mu<Func<A>>)->Func<A>>> = abc!(move |x : Mu<Func<A>>| -> Func<A> {
let f = f.clone();
abc!(move |a:A| -> A {
let f = f.clone();
f(unroll(x.clone())(x.clone()))(a)
})
});
g(Mu::Roll(g.clone()))
}
#[macro_export]
macro_rules! y {
(|$name:ident| $fun:tt) => {
y(abc!(|$name| abc!($fun)))
// If we were to pass in self as f, we get -
// NOTE: Each letter is an individual symbol.
// λf.λt.sft
// => λs.λt.sst [s/f]
// => λs.ss
}
}
fn fac(n: u32) -> u32 {
let fn_: Func<u32> = y!(|f| (move |x| if x == 0 { 1 } else { f(x-1) * x }));
fn_(n)
// Here you take a reference to the function you want to recurse, AND the input, and return the result.
// But, you are NOT <returning> a recursive version of the given function...
// You CAN, of course, wrap this in a closure.
fn y_apply<T, R, F>( f: &F, t: T ) -> R where F: Fn( &Fn( T ) -> R, T ) -> R {
( &|x: &Apply<T, R>, y| x.apply( x, y ) )
.apply( &|x: &Apply<T, R>, y| f( &|z| x.apply( x, z ), y ), t )
// NOTE: Each letter is an individual symbol.
// (λx.(λy.xxy))(λx.(λy.f(λz.xxz)y))t
// => (λx.xx)(λx.f(xx))t
// => (Yf)t
}
fn fib(n: u32) -> u32 {
let fn_: Func<u32> = y!(|f| (move |x| if x < 2 { x } else { f(x-1) + f(x-2) }));
fn_(n)
// The static lifetime bounds on the type parameters 'T' and 'R' guarantee that those types will not -
// - contain any references that will have a lifetime less than 'static.
// If the types are allowed to have references that have a lifetime shorter than 'static, those references -
// - may become invalid while you still you have the returned value.
// You need to have the lifetimes be 'static, because, unlike before, you RETURN a recursive version of the function...
fn y<T: 'static, R: 'static>( f: Box<Fn( &Fn( T ) -> R, T ) -> R> ) -> Box<Fn( T ) -> R> {
Box::new( move |t: T| ( &|x: &Apply<T, R>, y| x.apply( x, y ) )
.apply( &|x: &Apply<T, R>, y| f( &|z| x.apply( x, z ), y ), t ) )
// NOTE: Each letter is an individual symbol.
// (λt(λx.(λy.xxy))(λx.(λy.f(λz.xxz)y)))t
// => (λx.xx)(λx.f(xx))
// => Yf
}
fn fac( n: usize ) -> usize {
let almost_fac = Box::new( |f: &Fn( usize ) -> usize, x| if x == 0 { 1 } else { x * f( x - 1 ) } );
let fac = y( almost_fac );
fac( n )
}
fn fib( n: usize ) -> usize {
let almost_fib = Box::new( |f: &Fn( usize ) -> usize, x| if x < 2 { x } else { f( x - 2 ) + f( x - 1 ) } );
let fib = y( almost_fib );
fib( n )
}
fn main() {
println!("{}", fac(10));
println!("{}", fib(10))
println!( "{}", fac( 10 ) );
println!( "{}", fib( 10 ) );
}

View file

@ -0,0 +1,11 @@
(define y
F -> ((/. X (X X))
(/. X (F (/. Z ((X X) Z))))))
(let Fac (y (/. F N (if (= 0 N)
1
(* N (F (- N 1))))))
(output "~A~%~A~%~A~%"
(Fac 0)
(Fac 5)
(Fac 10)))

View file

@ -1,7 +1,7 @@
var y = ->(f) {->(g) {g(g)}(->(g) { f(->(*args) {g(g)(args...)})})};
var y = ->(f) {->(g) {g(g)}(->(g) { f(->(*args) {g(g)(args...)})})}
var fac = ->(f) { ->(n) { n < 2 ? 1 : (n * f(n-1)) } };
say 10.of { |i| y(fac)(i) };
var fac = ->(f) { ->(n) { n < 2 ? 1 : (n * f(n-1)) } }
say 10.of { |i| y(fac)(i) }
var fib = ->(f) { ->(n) { n < 2 ? n : (f(n-2) + f(n-1)) } };
say 10.of { |i| y(fib)(i) };
var fib = ->(f) { ->(n) { n < 2 ? n : (f(n-2) + f(n-1)) } }
say 10.of { |i| y(fib)(i) }

View file

@ -0,0 +1,39 @@
// z-combinator
(
z = { |f|
{ |x| x.(x) }.(
{ |y|
f.({ |args| y.(y).(args) })
}
)
};
)
// factorial
k = { |f| { |x| if(x < 2, 1, { x * f.(x - 1) }) } };
g = z.(k);
g.(5) // 120
(1..10).collect(g) // [ 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800 ]
// fibonacci
k = { |f| { |x| if(x <= 2, 1, { f.(x - 1) + f.(x - 2) }) } };
g = z.(k);
g.(3)
(1..10).collect(g) // [ 1, 1, 2, 3, 5, 8, 13, 21, 34, 55 ]
// a shorter form
(
r = { |x| x.(x) };
z = { |f| r.({ |y| f.(r.(y).(_)) }) };
)

View file

@ -0,0 +1,9 @@
if !has("lambda")
echoerr 'Lambda feature required'
finish
endif
let Y = {f -> {x -> x(x)}({y -> f({... -> call(y(y), a:000)})})}
let Fac = {f -> {n -> n<2 ? 1 : n * f(n-1)}}
echo Y(Fac)(5)
echo map(range(10), 'Y(Fac)(v:val)')

View file

@ -1,3 +1,4 @@
# Better names due to Jim Weirich: http://vimeo.com/45140590
def (Y improver)
((fn(gen) gen.gen)
(fn(gen)

View file

@ -0,0 +1 @@
fcn Y(f){ fcn(g){ g(g) }( 'wrap(h){ f( 'wrap(a){ h(h)(a) }) }) }

View file

@ -0,0 +1,3 @@
fcn almost_factorial(f){ fcn(n,f){ if(n<=1) 1 else n*f(n-1) }.fp1(f) }
Y(almost_factorial)(6).println();
[0..10].apply(Y(almost_factorial)).println();

View file

@ -0,0 +1,3 @@
fcn almost_fib(f){ fcn(n,f){ if(n<2) 1 else f(n-1)+f(n-2) }.fp1(f) }
Y(almost_fib)(9).println();
[0..10].apply(Y(almost_fib)).println();