Recs

From Esolang
Jump to navigation Jump to search

recsis a esolang created by User: Jan jelo.The whole program is a expression,interpreter evaluate it and print the result. It combines partial recursive function and Lambda calculus,and also some extensions.

Expression

A expression can be

<variable>

<natural number>

<function>

(list <expression> <expression>...)

(<function> <expression> <expression>...)

(let <name> <expression>...<name> <expression> <expression>)

Function

A function can be

(<function> <expression> <expression>...)

<variable>

Z S (P <natural number> <natural number>)

(C <function> <function>...)

(R <function> <function>)

(M <function>)

(lam <parameter> <expression>)

(fn <expression>)

+-*/

pairleftright

conscarcdr

=

(if <expression> <expression> <expression>...)

Reduce

Partial Recursive Function

Z

Z is zero function.

(Z x y z w...) will reduce to 0

S

S is successor function.

(S x y z w...) will reduce to x+1

P

(P m n) is projection function

((P m n)x1 x2...xn...xm) will reduce to xn

C

C is function compose.

((C f g1 g2...gm)x1 x2...xn) will reduce to (f (g1 x1...xn) (g2 x1...xn)...(gm x1..xn))

R

R is primitive recursion.

((R h g)x1...x_n-1 0) will reduce to (h x1...x_n-1)(base case)

((R h g)x1...x_n-1 xn) will reduce to (g x1...x_n-1 xn-1 ((R h g)x1...x_n-1 xn-1))(recursive case)

M

M is minimalization.

((M f)x1...xn) will reduce to the smallest A that makes (f x1...xn A) reduce to 0

Lambda

lam

((lam x exp)x1...) will reduce to the exp that replace free x in exp into x1.

Other

+ - * / √

(+ x1 x2...) will reduce to x1+x2

(- x1 x2...) will reduce to max(0,x1-x2)

(* x1 x2...) will reduce to x1*x2

(/ x1 x2...) will reduce to floor(x1/x2)

(√ x1...) will reduce to floor(sqrt(x1))

cons car cdr

(cons x (list a b c...)...) will reduce to (list x a b c...)

(car (list a b c...)...) will reduce to a

(cdr (list a b c...)...) will reduce to (list b c...)

pair left right

pair is a pairing function,it encodes two natural numbers into one natural number.

  0  1  2  3
  -----------
0|0  3  8  15
1|1  2  7  14
2|4  5  6  13
3|9  10 11 12

(pair l r...) will reduce to l^2+r if l>=r

(pair l r...) will reduce to 2*r+r^2-l if l<r

let K be floor(sqrt(p)),Q be K^2+K,then

(left p...) will reduce to K-p+Q if p>=Q

(left p...) will reduce to K if p<Q

(right p...) will reduce to p-K^2 if p>=Q

(right p...) will reduce to K if p<Q

= if

(= x1 x2...) will reduce to 1 if the value of x1 is equal to the value ofx2,otherwise it will reduce to 0

(if cond t f...) will reduce to f if the value of cond is equal to (list) or 0,otherwise it will reduce to t

let

(let x1 f1 x2 f2...xn fn e) will reduce to ((lam x1((lam x2(...((lam xn e)fn)...))f2))f1)

fn

((fn exp)x1...xn) will reduce to the exp that replace the free #<N> in exp into N-th argument in the arguments-list

(((fn((fn #2)3 4))1 2) will reduce to 4,not 2)

Turing Completeness

Because Lambda calculus and partial recursive function are Turing complete,recs is turing complete.

Example

(let
 omega
 (lam x(x x))
 fix
 (omega
  (lam f
   (lam x
    (x((f f)x)))))
 fact
 (fix
  (lam fact
   (lam x
    (if x
     (* x(fact(- x 1)))
     1))))
 map
 (fix
  (lam map
   (fn
    (if #2
       (cons(#1(car #2))(map #1(cdr #2)))
       (list)))))
 lst
 (list 0 1 2 3 4 5 6 7 8 9)
 (map (C fact S) lst)

will output (list 1 2 6 24 120 720 5040 40320 362880 3628800)

Interpreter

A interpreter written by Python3(I'm not sure if there are any bugs)

functions = [
 'S', 'Z', 'if', '+', '-', '*', '/',
 '=', '√', 'left', 'right', 'cons',
 'car', 'cdr', 'pair'
]
def sqrt(x):
 res=0;digit=1
 while digit<x:
  digit*=10
 while digit>0:
  while res**2<=x:
   res+=digit
  res-=digit
  digit=digit//10
 return res
def pair(x,y):
 if x>=y:return x**2+y
 return y**2+2*y-x
def left(p):
 k=sqrt(p)
 q=k**2+k
 if p>=q:return k-(p-q)
 return k
def right(p):
 k=sqrt(p)
 q=k**2+k
 if p>=q:return k
 return p-k**2

def pop(l):
 e=l+[]
 t=e.pop()
 if t!='(':return e
 i=1
 while i:
  t=e.pop()
  if t=='(':i+=1
  if t==')':i-=1
 return e
def top(l):
 e=l+[]
 t=e.pop()
 if t!='(':return [t]
 i=1;res=[t]
 while i:
  t=e.pop()
  if t=='(':i+=1
  if t==')':i-=1
  res.append(t)
 return res[::-1]
def token(string):
 a=(string
     .replace('(',' ( ')
     .replace(')',' ) ')
     .replace('\\\n','')
     .replace('\n',' ')
  )
 return list(filter(
          lambda x:x!='',
          a.split(' ')
        ))[::-1]
def isNum(x):
 nums='0123456789'
 return all(map(lambda x:x in nums,x))

def parse(string):
 def rec(tokens):
  last=tokens[-1]
  if last!='(':
   if isNum(last):return 'num',int(last)
   if last in functions:return(last,)
   return 'symbol',last
  l=tokens[1:-1]
  o=top(l);l=pop(l)
  if o==['lam']:
   para=top(l)[0];l=pop(l)
   body=top(l)
   return 'lam',para,rec(body)
  if o==['fn']:
   body=top(l)
   return 'fn',rec(body)
  if o==['P']:
   m=top(l);l=pop(l)
   n=top(l)
   return 'P',int(m[0]),int(n[0])
  if o==['C']:
   tmp=[]
   while l:tmp.append(rec(top(l)));l=pop(l)
   return 'C',tmp
  if o==['R']:
   h=top(l);l=pop(l)
   g=top(l)
   return 'R',rec(h),rec(g)
  if o==['M']:
   f=top(l)
   return 'M',rec(f)
  if o==['Z']:
   tmp=[]
   while l:tmp.append(rec(top(l)));l=pop(l)
   return 'app',('Z',),tmp
  if o==['let']:
   tmp=[]
   while l:tmp.append(rec(top(l)));l=pop(l)
   [*xs,res]=tmp
   while xs:
    arg,para=xs.pop(),xs.pop()[1]
    res=('app',('lam',para,res),[arg])
   return res
  if o==['list']:
   tmp=[]
   while l:tmp.append(rec(top(l)));l=pop(l)
   return 'list',tmp
  if o==['if']:
   cond=top(l);l=pop(l)
   t=top(l);l=pop(l)
   f=top(l)
   return 'app',('if',),[rec(cond), rec(t), rec(f)]
  if o[0]in{'=','+','-','*','/','cons','pair'}:
   a=top(l);l=pop(l)
   b=top(l)
   return 'app',(o[0],),[rec(a), rec(b)]
  if o[0]in{'√','car','cdr','left','right'}:
   a=top(l)
   return 'app',(o[0],),[rec(a)]
  tmp=[]
  while l:tmp.append(rec(top(l)));l=pop(l)
  return 'app',rec(o),tmp
 return rec(token(string))
def lam_rewrite(body,para,arg):
 t=body[0]
 if t=='symbol':
  if body[1][0]=='#'and isNum(body[1][1:]):return  body
  if body[1]==para:return arg
  return body
 if t=='num':return body
 if t=='list':return (
  'list',list(map(
   lambda x:lam_rewrite(x,para,arg),
   body[1]
  ))
 )
 if t=='lam':
  if body[1]==para:return body
  return (
   'lam',body[1],
   lam_rewrite(body[2],para,arg)
  )
 if t=='P':return  body
 if t=='C':
  return (
   'C',
   list(map(
    lambda x:lam_rewrite(x,para,arg),
    body[1]
   ))
  )
 if t=='app':
  return (
   'app',lam_rewrite(body[1], para, arg),
   list(map(
    lambda x:lam_rewrite(x,para,arg),
    body[2]
   )))
 return (
  body[0],
  *tuple(map(
   lambda x:lam_rewrite(x,para,arg),
   body[1:]))
 )
def fn_rewrite(body,args):
 t=body[0]
 if t=='num':return body
 if t=='list':return (
  'list',list(map(
   lambda x:fn_rewrite(x,args),
   body[1]
  ))
 )
 if t=='symbol':
  if body[1][0]=='#'and isNum(body[1][1:]):
   return val(args[int(body[1][1:])-1])
  return body
 if t in['fn','P']:return body
 if t=='app':
  return (
   'app',fn_rewrite(body[1],args),
   list(map(
    lambda x:fn_rewrite(x,args),
    body[2]
   )))
 if t=='lam':return (
  'lam',body[1],
  fn_rewrite(body[2],args)
 )
 return (
  body[0],
  *tuple(map(
   lambda x: fn_rewrite(x,args),
   body[1:]))
 )

def app(f,x):
 t=f[0]
 if t=='S':return 'num',val(x[0])[1]+1
 if t=='Z':return 'num',0
 if t=='if':
  if val(x[0])[1]:
   return val(x[1])
  return val(x[2])
 if t=='=':return (
  'num',
  int(val(x[0])[1]==val(x[1])[1])
 )
 if t=='+':return (
  'num',
  val(x[0])[1]+val(x[1])[1]
 )
 if t=='-':return (
  'num',
  max(0,val(x[0])[1]-val(x[1])[1])
 )
 if t=='*':return (
  'num',
  val(x[0])[1]*val(x[1])[1]
 )
 if t=='/':return (
  'num',
  val(x[0])[1]//val(x[1])[1]
 )
 if t=='cons':return (
  'list',
  [val(x[0])]+val(x[1])[1]
 )
 if t=='pair':return (
  'num',
  pair(val(x[0])[1],val(x[1])[1])
 )
 if t=='√':return (
  'num',
  sqrt(val(x[0])[1])
 )
 if t=='left':return (
  'num',
  left(val(x[0])[1])
 )
 if t=='right':return (
  'num',
  right(val(x[0])[1])
 )
 if t=='car':return val(x[0])[1][0]
 if t=='cdr':
  l=val(x[0])[1]
  if l:return 'list',l[1:]
  return 'list',l
 if t=='lam':
  return val(lam_rewrite(f[2],f[1],x[0]))
 if t=='fn':
  return val(fn_rewrite(f[1],x))
 if t=='P':
  return x[:f[1]][f[2]-1]
 if t=='C':
  fn=f[1][0]
  gs=f[1][1:]
  return app(
   fn,
   [app(g,x)for g in gs]
  )
 if t=='R':
  h=f[1];g=f[2]
  res=app(h,x[:-1])
  for i in range(x[-1][1]):
   res=app(g,x[:-1]+[('num',i)]+[res])
  return res
 if t=='M':
  fn=f[1];cnt=0
  while True:
   value=app(fn,x+[('num',cnt)])
   if value[1]==0:return 'num',cnt
   cnt+=1
 if t=='app':
  return app(val(f),x)
 return 'app',f,x

def val(exp):
 t=exp[0]
 if t=='app':
  return app(exp[1],(exp[2]))
 if t=='list':
  return 'list',list(map(val,exp[1]))
 return exp
def show(exp):
 t=exp[0]
 if t in functions:return t
 if t=='symbol':return exp[1]
 if t=='num':return str(exp[1])
 if t=='list':return f'(list {" ".join(map(show,exp[1]))})'
 if t=='app':return f'({show(exp[1])} {" ".join(map(show,exp[2]))})'
 if t=='P':return f'(P {exp[1]} {exp[2]})'
 if t=='C':return (
  '(C '+(' '.join(map(show,exp[1])))+')'
 )
 if t=='lam':
   return f'(lam {exp[1]} {show(exp[2])})'
 return f'({t} {" ".join(map(show,exp[1:]))})'

exp='''
(let
 omega
 (lam x(x x))
 fix
 (omega
  (lam f
   (lam x
    (x((f f)x)))))
 fact
 (fix
  (lam fact
   (lam x
    (if x
     (* x(fact(- x 1)))
     1))))
 map
 (fix
  (lam map
   (fn
    (if #2
       (cons(#1(car #2))(map #1(cdr #2)))
       (list)))))
 lst
 (list 0 1 2 3 4 5 6 7 8 9)
 (map (C fact S) lst)
)
'''
print(show(val(parse(exp))))