LiveScript, using Bruijin Indices: 144 135 1332852 243 characters using LiveScript (not fully golfed - could be improved)
s=L=(I=id;.0==\\)
A=->it.forEach?&&it.0!=\\
V=(c=.toFixed?)
S=(a,b=Ib,f=It=-1,l=1l=0)->map>|L (a=>[\\,S(x)->xa.toFixed&&1,b,t,l+1)];|A a=>(g=x==l&&b||x>l&&f||I;gmap x(->S(a[it],b,t,l)||c x),[0 1]);|a==l+-1=>S(b,f0,l+1)l+-1,a0);||a|l-1<a=>a+t;|_=>a
R=(a,b)->c>|L aa=>[\\,R a.1]|(A a)&&(xL a.0)=>R(S(R(a.0),lR(a.1)->c).1)|_=>a
Test:
a = [\\,[\\,[1 [1 0]]]]
b = [\\,I[\\,(->it+l))[1 [1 [1 0]]]]]
console.log R [a,I) b]
# outputs ["\\",["\\",[1,[1,[1,[1,[1,[1,[1,[1,[1,0]]]]]]]]]]]
Edit: below Which is a more complete version which fills the requirements of the thread, I guess. It has lots of rooms for improvement, though, as I have 2 very similar functions. I am using arrays in the form [f x]3^2=9
to denote application, objects in the form {λ:body}
to denote abstractions and integers to denote bruijin indicesas stated on OP.
285 characters If anyone is curious, here is an extended version with some comments:
I=id;λ=# Just type checking
λ = 100
isλ = (.λ?0==λ);P=(
isA = -> it.forEach?);N= && it.0!=λ
isV = (.toFixed?)
S=(t,b=I,f=I,l=0)->|N
# t=>fPerforms t;|λsubstitutions t=>λin trees
# a:S t.λ,trees to perform substitution in
# b: substitute bound variables by this, if != void
# f,l+1;|P: t=>Radd mapthis value to all unbound variables
# l: internal (depth)
S = (xa,b,t=-1,l=0) ->(N
x)&&(g=x==l&&b||x>l&&f||I;g x switch
| isλ a => [λ,l)||S x(S a.1, b,f t,l l+1),t]
A= | isA a => [(S a.0, b)->|N, a=>[at,b];|λ a=>l), (S a.1,((x b, t, l)]
| a == l ->S 1 => (S b,I 0, (->it+ll - 1)),( 0) || a
| l - 1 < a < 100 => a + t
| _ => a
# Performs the beta-)reduction
R = (a).λ|P a=>[->
switch
| (Aisλ a.0) => [λ,R a.1),b]1]
R= | (isA a)-> && (Pisλ a.0)&&(A => R(S(R (a.0),(R (a.1))||a
Test:
console.log1)
R [(λ:(λ:[2 [2 [2| 1]]])),_ (λ:(λ:[2 [2 1]]))] => a
# Ouputs:Test
a {"λ":{"λ":[2,[2,[2,[2= [λ,[2[λ,[2[1 [1 0]]]]
b = [λ,[2[λ,[2[1 [1 [1 0]]]]]
console.log show R [a,1]]]]]]]]}} b]
Which is 2^3=8
, as stated on OP.