option casemap:none

ifndef __SOMECLASS_CLASS__
__SOMECLASS_CLASS__   equ 1

  ;; Once again, HeapAlloc/Free is REQUIRED by the class extention for windows.
  ;; Malloc/Free are used by Linux and OSX. So the function prototypes have to
  ;; be defined somewhere. If you have include files where they're defined, just
  ;; include them in the usual way and remove the option dllimports.
  if @Platform eq 1             ;; Windows 64
    ;; include windows.inc
    ;; includelib kernel32.lib
    option dllimport:<kernel32>
      HeapAlloc       proto :qword, :dword, :qword
      HeapFree        proto :qword, :dword, :qword
      ExitProcess     proto :dword
      GetProcessHeap  proto
    option dllimport:none
      exit            equ ExitProcess
  elseif @Platform eq 3         ;; Linux 64
    ;;include libc.inc
    malloc            proto SYSTEMV :qword
    free              proto SYSTEMV :qword
    exit              proto SYSTEMV :dword
  endif

  printf              proto :qword, :VARARG

  CLASS someClass
    CMETHOD someMethod
  ENDMETHODS
    var dd ?
  ENDCLASS

  ;; The OS' ABI has an effect on this class extention. That is, the class self pointetr
  ;; is usually refferenced in the first arg register. So for Windows it would be rcx and
  ;; Linux would be rdi. So to write code that will assemble on both we use a register
  ;; that ISN'T used to pass arguments in either ABI(Not sure about OSX's ABI however)
  METHOD someClass, Init, <VOIDARG>, <>, a:dword
    mov rbx, thisPtr
    assume rbx:ptr someClass
    mov [rbx].var, a
    mov rax, rbx
    assume rbx:nothing
    ret
  ENDMETHOD

  METHOD someClass, someMethod, <dword>, <>
    mov rbx, thisPtr
    assume rbx:ptr someClass
    mov eax, [rbx].var
    assume rbx:nothing
    ret
  ENDMETHOD

  METHOD someClass, Destroy, <VOIDARG>, <>
    ret
  ENDMETHOD
endif                         ;; __CLASS_CLASS_

.code
main proc
  local meh:ptr someClass
  ;; Create a new instance of someClass with an arg of 7
  mov meh, _NEW(someClass, 7)
  meh->someMethod()              ;;Get meh->var value and return it in RAX
  invoke printf, CSTR("class->someMethod = %i",10), rax
  _DELETE(meh)                   ;; DIIIIIIIE!
  invoke exit, 0                 ;; Crashy crashy without it.
  ret
main endp

end


class Person {
	construct=func(self,Name,Age,Gender){
		self:Name=Name;
		self:Age=Age;
		self:Gender=Gender;
	}{Name="John",Age=20,Gender="Male"};
	ToString=func(self){
		send self.Name+" ("+self.Gender+"): Age "+self.Age;
	}
}

set John = new Person with [];
log(John::ToString());
set Jane = new Person with ["Jane",20,"Female"]
log(Jane::ToString());


(DEFINE-CLASS PROGRAMMING-LANGUAGE
    (INSTANCE-VARIABLES NAME YEAR))

(DEFINE-METHOD (PROGRAMMING-LANGUAGE 'INITIALIZE X)
    (SETQ NAME X)
    SELF)

(DEFINE-METHOD (PROGRAMMING-LANGUAGE 'WAS-CREATED-IN X)
    (SETQ YEAR X))

(DEFINE-METHOD (PROGRAMMING-LANGUAGE 'DESCRIBE)
    `(THE PROGRAMMING LANGUAGE ,NAME WAS CREATED IN ,YEAR))

(DEFINE LISP (PROGRAMMING-LANGUAGE 'NEW 'LISP))

(LISP 'WAS-CREATED-IN 1958)

(DISPLAY (LISP 'DESCRIBE))
(NEWLINE)


class C{ // define class named "C", no parents or attributes
   println("starting construction"); // all code outside functions is wrapped into the constructor
   var v;    // instance data for this class
   fcn init(x) // initializer for this class, calls constructor
      { v = x }
   println("ending construction of ",self);
}
c1:=C(5);  // create a new instance of C
c2:=c1("hoho"); // create another instance of C
println(C.v," ",c1.v," ",c2.v);


module Graphics;
type
	{ref,public} (* class *)
	Point = object(ord,abs: integer)
	var
		(* instance variables *)
		{public,immutable} x,y: integer;

	(* method *)
	procedure {public} Ord():integer;
	begin
		return y
	end Ord;

	(* method *)
	procedure {public} Abs():integer;
	begin
		return x
	end Abs;

	(* constructor *)
	begin
		self.x := ord;
		self.y := abs;
	end Point;
end Graphics.

module Main;
import Graphics;
var
	p: Graphics.Point;

procedure Write(p: Graphics.Point);
begin
	writeln('[':1,p.x:3,',':1,p.y:3,']':1)
end Write;

begin
	p := new Graphics.Point(12,12);
	Write(p);
	writeln("Abs: ":4,p.Abs():3," Ord: ":5,p.Ord():3);
end Main.


	dc.l TrapString_Bus
	dc.l TrapString_Addr
	dc.l TrapString_Illegal
	dc.l TrapString_Div0
	dc.l TrapString_chk
	dc.l TrapString_v
	dc.l TrapString_priv
	dc.l TrapString_trace

TrapString_Bus:
	dc.b "Bus error",255
	even
TrapString_Addr:
	dc.b "Address error",255
	even
TrapString_Illegal:
	dc.b "Illegal Instruction",255
	even
TrapString_Div0:
	dc.b "Divide By Zero",255
	even
TrapString_chk:
	dc.b "CHK Failure",255
	even
TrapString_v:
	dc.b "Signed Overflow",255
	even
TrapString_priv:
	dc.b "Privilege Violation",255
	even
TrapString_trace:
	dc.b "Tracing",255
	even


REPORT z_test_rosetta_collection.

CLASS lcl_collection DEFINITION CREATE PUBLIC.

  PUBLIC SECTION.
    METHODS: start.
ENDCLASS.

CLASS lcl_collection IMPLEMENTATION.
  METHOD start.
    DATA(itab) = VALUE int4_table( ( 1 ) ( 2 ) ( 3 ) ).

    cl_demo_output=>display( itab ).
  ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.
  NEW lcl_collection( )->start( ).


procedure Array_Collection is

   A : array (-3 .. -1) of Integer := (1, 2, 3);

begin

   A (-3) := 3;
   A (-2) := 2;
   A (-1) := 1;

end Array_Collection;


# create a constant array of integers and set its values #
[]INT constant array = ( 1, 2, 3, 4 );
# create an array of integers that can be changed, note the size mst be specified #
# this array has the default lower bound of 1 #
[ 5 ]INT mutable array := ( 9, 8, 7, 6, 5 );
# modify the second element of the mutable array #
mutable array[ 2 ] := -1;
# array sizes are normally fixed when the array is created, however arrays can be #
# declared to be FLEXible, allowing their sizes to change by assigning a new array to them #
# The standard built-in STRING is notionally defined as FLEX[ 1 : 0 ]CHAR in the standard prelude #
# Create a string variable: #
STRING str := "abc";
# assign a longer value to it #
str := "bbc/itv";
# add a few characters to str, +=: adds the text to the beginning, +:= adds it to the end #
"[" +=: str; str +:= "]"; # str now contains "[bbc/itv]" #
# Arrays of any type can be FLEXible: #
# create an array of two integers #
FLEX[ 1 : 2 ]INT fa := ( 0, 0 );
# replace it with a new array of 5 elements #
fa := LOC[ -2 : 2 ]INT;


// Create an empty list of String
List<String> my_list = new List<String>();
// Create a nested list
List<List<Set<Integer>>> my_list_2 = new List<List<Set<Integer>>>();


; initialize array
arr: ["one" 2 "three" "four"]

; add an element to the array
arr: arr ++ 5

; print it
print arr


myCol := Object()
mycol.mykey := "my value!"
mycol["mykey"] := "new val!"
MsgBox % mycol.mykey ; new val


1→{L₁}
2→{L₁+1}
3→{L₁+2}
4→{L₁+3}
Disp {L₁}►Dec,i
Disp {L₁+1}►Dec,i
Disp {L₁+2}►Dec,i
Disp {L₁+3}►Dec,i


      DIM text$(1)
      text$(0) = "Hello "
      text$(1) = "world!"


#define cSize( a )  ( sizeof(a)/sizeof(a[0]) ) /* a.size() */
int ar[10];               /* Collection<Integer> ar = new ArrayList<Integer>(10); */
ar[0] = 1;                /* ar.set(0, 1); */
ar[1] = 2;

int* p;                   /* Iterator<Integer> p; Integer pValue; */
for (p=ar;                /* for( p = ar.itereator(), pValue=p.next(); */
       p<(ar+cSize(ar));  /*        p.hasNext(); */
       p++) {             /*        pValue=p.next() ) { */
  printf("%d\n",*p);      /*   System.out.println(pValue); */
}                         /* } */


// Creates and initializes a new integer Array
int[] intArray = new int[5] { 1, 2, 3, 4, 5 };
//same as
int[] intArray = new int[]{ 1, 2, 3, 4, 5 };
//same as
int[] intArray = { 1, 2, 3, 4, 5 };

//Arrays are zero-based
string[] stringArr = new string[5];
stringArr[0] = "string";


int a[5]; // array of 5 ints (since int is POD, the members are not initialized)
a[0] = 1; // indexes start at 0

int primes[10] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29 }; // arrays can be initialized on creation

#include <string>
std::string strings[4]; // std::string is no POD, therefore all array members are default-initialized
                        // (for std::string this means initialized with empty strings)


{1 "a", "Q" 10} ; commas are treated as whitespace
(hash-map 1 "a" "Q" 10) ; equivalent to the above
(let [my-map {1 "a"}]
  (assoc my-map "Q" 10)) ; "adding" an element


       identification division.
       program-id. collections.

       data division.
       working-storage section.
       01 sample-table.
          05 sample-record occurs 1 to 3 times depending on the-index.
             10 sample-alpha   pic x(4).
             10 filler         pic x value ":".
             10 sample-number  pic 9(4).
             10 filler         pic x value space.
       77 the-index            usage index.

       procedure division.
       collections-main.

       set the-index to 3
       move 1234 to sample-number(1)
       move "abcd" to sample-alpha(1)

       move "test" to sample-alpha(2)

       move 6789 to sample-number(3)
       move "wxyz" to sample-alpha(3)

       display "sample-table    : " sample-table
       display "sample-number(1): " sample-number(1)
       display "sample-record(2): " sample-record(2)
       display "sample-number(3): " sample-number(3)

      *> abend: out of bounds subscript, -debug turns on bounds check
       set the-index down by 1
       display "sample-table    : " sample-table
       display "sample-number(3): " sample-number(3)

       goback.
       end program collections.


CL-USER> (let ((list '())
               (hash-table (make-hash-table)))
           (push 1 list)
           (push 2 list)
           (push 3 list)
           (format t "~S~%" (reverse list))
           (setf (gethash 'foo hash-table) 42)
           (setf (gethash 'bar hash-table) 69)
           (maphash (lambda (key value)
                      (format t "~S => ~S~%" key value))
                    hash-table)
           ;; or print the hash-table in readable form
           ;; (inplementation-dependent)
           (write hash-table :readably t)
           ;; or describe it
           (describe hash-table)
           ;; describe the list as well
           (describe list))
;; FORMAT on a list
(1 2 3)
;; FORMAT on a hash-table
FOO => 42
BAR => 69
;; WRITE :readably t on a hash-table
#.(SB-IMPL::%STUFF-HASH-TABLE
   (MAKE-HASH-TABLE :TEST 'EQL :SIZE '16 :REHASH-SIZE '1.5
                    :REHASH-THRESHOLD '1.0 :WEAKNESS 'NIL)
   '((BAR . 69) (FOO . 42)))
;; DESCRIBE on a hash-table
#<HASH-TABLE :TEST EQL :COUNT 2 {1002B6F391}>
  [hash-table]

Occupancy: 0.1
Rehash-threshold: 1.0
Rehash-size: 1.5
Size: 16
Synchronized: no
;; DESCRIBE on a list
(3 2 1)
  [list]
; No value


int[3] array;
array[0] = 5;
// array.length = 4; // compile-time error


// Creates and initializes a new integer Array
var
    // Dynamics arrays can be initialized, if it's global variable in declaration scope
    intArray: TArray<Integer> = [1, 2, 3, 4, 5];
    intArray2: array of Integer = [1, 2, 3, 4, 5];

    //Cann't initialize statics arrays in declaration scope
    intArray3: array [0..4]of Integer;
    intArray4: array [10..14]of Integer;

procedure
var
    // Any arrays can't be initialized, if it's local variable in declaration scope
    intArray5: TArray<Integer>;
begin
  // Dynamics arrays can be full assigned in routine scope
  intArray := [1,2,3];
  intArray2 := [1,2,3];

  // Dynamics arrays zero-based
  intArray[0] := 1;

  // Dynamics arrays must set size, if it not was initialized before
  SetLength(intArray,5);

  // Inline dynamics arrays can be created and initialized routine scope
  // only for version after 10.3 Tokyo
  var intArray6 := [1, 2, 3];
  var intArray7: TArray<Integer> := [1, 2, 3];
end;


? def constList := [1,2,3,4,5]
# value: [1, 2, 3, 4, 5]

? constList.with(6)
# value: [1, 2, 3, 4, 5, 6]

? def flexList := constList.diverge()
# value: [1, 2, 3, 4, 5].diverge()

? flexList.push(6)
? flexList
# value: [1, 2, 3, 4, 5, 6].diverge()

? constList
# value: [1, 2, 3, 4, 5]

? def constMap := [1 => 2, 3 => 4]
# value: [1 => 2, 3 => 4]

? constMap[1]
# value: 2

? def constSet := [1, 2, 3, 2].asSet()
# value: [1, 2, 3].asSet()

? constSet.contains(3)
# value: true


(define my-collection ' ( 🌱 ☀ ☔ ))
(set! my-collection (cons '🎥 my-collection))
(set! my-collection (cons '🐧 my-collection))
my-collection
  → (🐧 🎥 🌱 ☀ ☔)

;; save it
(local-put 'my-collection)
  → my-collection


// Weak array
var stringArr := Array.allocate(5);
stringArr[0] := "string";

// initialized array
var intArray := new int[]{1, 2, 3, 4, 5};


USING: assocs deques dlists lists lists.lazy sequences sets ;

! ===fixed-size sequences===
{ 1 2 "foo" 3 } ! array
[ 1 2 3 + * ]   ! quotation
"Hello, world!" ! string
B{ 1 2 3 }      ! byte array
?{ f t t }      ! bit array

! Add an element to a fixed-size sequence
{ 1 2 3 } 4 suffix ! { 1 2 3 4 }

! Append a sequence to a fixed-size sequence
{ 1 2 3 } { 4 5 6 } append ! { 1 2 3 4 5 6 }

! Sequences are sets
{ 1 1 2 3 } { 2 5 7 8 } intersect ! { 2 }

! Strings are just arrays of code points
"Hello" { } like ! { 72 101 108 108 111 }
{ 72 101 108 108 111 } "" like ! "Hello"

! ===resizable sequences===
V{ 1 2 "foo" 3 }     ! vector
BV{ 1 2 255 }        ! byte vector
SBUF" Hello, world!" ! string buffer

! Add an element to a resizable sequence by mutation
V{ 1 2 3 } 4 suffix! ! V{ 1 2 3 4 }

! Append a sequence to a resizable sequence by mutation
V{ 1 2 3 } { 4 5 6 } append! ! V{ 1 2 3 4 5 6 }

! Sequences are stacks
V{ 1 2 3 } pop ! 3

! ===associative mappings===
{ { "hamburger" 150 } { "soda" 99 } { "fries" 99 } } ! alist
H{ { 1 "a" } { 2 "b" } } ! hash table

! Add a key-value pair to an assoc
3 "c" H{ { 1 "a" } { 2 "b" } } [ set-at ] keep
! H{ { 1 "a" } { 2 "b" } { "c" 3 } }

! ===linked lists===
T{ cons-state f 1 +nil+ }               ! literal list syntax
T{ cons-state { car 1 } { cdr +nil+ } } ! literal list syntax
                                        ! with car 1 and cdr nil

! One method of manually constructing a list
1 2 3 4 +nil+ cons cons cons cons

1 2 2list ! convenience word for list construction
          ! T{ cons-state
          !     { car 1 }
          !     { cdr T{ cons-state { car 2 } { cdr +nil+ } } }
          !  }

{ 1 2 3 4 } sequence>list ! make a list from a sequence

0 lfrom ! a lazy list from 0 to infinity
0 [ 2 + ] lfrom-by ! a lazy list of all even numbers >= 0.

DL{ 1 2 3 } ! double linked list / deque
3 DL{ 1 2 } [ push-front ] keep ! DL{ 3 1 2 }
3 DL{ 1 2 } [ push-back  ] keep ! DL{ 1 2 3 }

! Factor also comes with disjoint sets, interval maps, heaps,
! boxes, directed graphs, locked I/O buffers, trees, and more!


# creating an empty array and adding values

a = []      # => []
a[0]: 1    # => [1]
a[3]: 2    # => [1, nil, nil, 2]

# creating an array with the constructor
a = Array new     # => []


include ffl/car.fs

10 car-create ar           \ create a dynamic array with initial size 10

2 0 ar car-set             \ ar[0] = 2
3 1 ar car-set             \ ar[1] = 3
1 0 ar car-insert          \ ar[0] = 1 ar[1] = 2 ar[2] = 3


 REAL A(36)   !Declares a one-dimensional array A(1), A(2), ... A(36)
  A(1) = 1           !Assigns a value to the first element.
  A(2) = 3*A(1) + 5  !The second element gets 8.


' FB 1.05.0 Win64

'create fixed size array of integers
Dim a(1 To 5) As Integer = {1, 2, 3, 4, 5}
Print a(2), a(4)

'create empty dynamic array of doubles
Dim b() As Double
' add two elements by first redimensioning the array to hold this number of elements
Redim b(0 To 1)
b(0) = 3.5 : b(1) = 7.1
Print b(0), b(1)

'create 2 dimensional fixed size array of bytes
Dim c(1 To 2, 1 To 2) As Byte = {{1, 2}, {3, 4}}
Print c(1, 1), c(2,2)
Sleep


Public Sub Main()
Dim siCount As Short
Dim cCollection As Collection = ["0": "zero", "1": "one", "2": "two", "3": "three", "4": "four",
                                 "5": "five", "6": "six", "7": "seven", "8": "eight", "9": "nine"]

For siCount = 0 To 9
  Print cCollection[Str(siCount)]
Next

End


package main

import "fmt"

func main() {
    var a []interface{}
    a = append(a, 3)
    a = append(a, "apples", "oranges")
    fmt.Println(a)
}


def emptyList = []
assert emptyList.isEmpty() : "These are not the items you're looking for"
assert emptyList.size() == 0 : "Empty list has size 0"
assert ! emptyList : "Empty list evaluates as boolean 'false'"

def initializedList = [ 1, "b", java.awt.Color.BLUE ]
assert initializedList.size() == 3
assert initializedList : "Non-empty list evaluates as boolean 'true'"
assert initializedList[2] == java.awt.Color.BLUE : "referencing a single element (zero-based indexing)"
assert initializedList[-1] == java.awt.Color.BLUE : "referencing a single element (reverse indexing of last element)"

def combinedList = initializedList + [ "more stuff", "even more stuff" ]
assert combinedList.size() == 5
assert combinedList[1..3] == ["b", java.awt.Color.BLUE, "more stuff"] : "referencing a range of elements"

combinedList << "even more stuff"
assert combinedList.size() == 6
assert combinedList[-1..-3] == \
        ["even more stuff", "even more stuff", "more stuff"] \
                : "reverse referencing last 3 elements"
println ([combinedList: combinedList])


#  Creation of collections:
 s := "abccd"                                   # string, an ordered collection of characters, immutable
 c := 'abcd'                                    # cset, an unordered collection of characters, immutable
 S := set()                                     # set, an unordered collection of unique values, mutable, contents may be of any type
 T := table()                                   # table, an associative array of values accessed via unordered keys, mutable, contents may be of any type
 L := []                                        # list, an ordered collection of values indexed by position 1..n or as stack/queue, mutable, contents may be of any type
 record constructorname(field1,field2,fieldetc) # record, a collection of values stored in named fields, mutable, contents may be of any type (declare outside procedures)
 R := constructorname()                         # record (creation)


   c =: 0 10 20 30 40 NB.  A collection

   c, 50              NB.  Append 50 to the collection
0 10 20 30 40 50
   _20 _10 , c        NB.  Prepend _20 _10 to the collection
_20 _10 0 10 20 30 40

   ,~  c               NB.  Self-append
0 10 20 30 40 0 10 20 30 40
   ,:~  c              NB.  Duplicate
0 10 20 30 40
0 10 20 30 40

   30 e. c             NB.  Is 30 in the collection?
1
   30 i.~c             NB.  Where?
3
   30 80 e. c          NB.  Don't change anything to test multiple values -- collections are native.
1 0

   2 1 4 2 { c         NB.  From the collection, give me items two, one, four, and two again.
20 10 40 20

   |.c                 NB.  Reverse the collection
40 30 20 10 0
   1+c                 NB.  Increment the collection
1 11 21 31 41
   c%10                NB.  Decimate the collection (divide by 10)
0 1 2 3 4

   {. c                NB.  Give me the first item
0
   {: c                NB.  And the last
40
   3{.c                NB.  Give me the first 3 items
0 10 20
   3}.c                NB.  Throw away the first 3 items
30 40
   _3{.c               NB.  Give me the last 3 items
20 30 40
   _3}.c               NB.  (Guess)
0 10

     keys_map_  =:  'one';'two';'three'
     vals_map_  =:  'alpha';'beta';'gamma'
   lookup_map_  =:  a:& $: : (dyad def ' (keys i. y) { vals,x')&boxopen
   exists_map_  =:  verb def 'y e. keys'&boxopen

   exists_map_ 'bad key'
0
   exists_map_ 'two';'bad key'
1 0

   lookup_map_ 'one'
+-----+
|alpha|
+-----+
   lookup_map_ 'three';'one';'two';'one'
+-----+-----+----+-----+
|gamma|alpha|beta|alpha|
+-----+-----+----+-----+
   lookup_map_ 'bad key'
++
||
++
   'some other default' lookup_map_ 'bad key'
+------------------+
|some other default|
+------------------+
   'some other default' lookup_map_ 'two';'bad key'
+----+------------------+
|beta|some other default|
+----+------------------+

   +/ c                NB. Sum of collection
100
   */ c                NB.  Product of collection
0

   i.5                 NB.  Generate the first 5 nonnegative integers
0 1 2 3 4
   10*i.5              NB.  Looks familiar
0 10 20 30 40
   c = 10*i.5          NB.  Test each for equality
1 1 1 1 1
   c -: 10 i.5         NB.  Test for identicality
1


List arrayList = new ArrayList();
arrayList.add(new Integer(0));
// alternative with primitive autoboxed to an Integer object automatically
arrayList.add(0);

//other features of ArrayList
//define the type in the arraylist, you can substitute a proprietary class in the "<>"
List<Integer> myarrlist = new ArrayList<Integer>();

//add several values to the arraylist to be summed later
int sum;
for(int i = 0; i < 10; i++) {
    myarrlist.add(i);
}


var array = [];
array.push('abc');
array.push(123);
array.push(new MyClass);
console.log( array[2] );


julia> collection = []
0-element Array{Any,1}

julia> push!(collection, 1,2,4,7)
4-element Array{Any,1}:
 1
 2
 4
 7


import java.util.PriorityQueue

fun main(args: Array<String>) {
    // generic array
    val ga = arrayOf(1, 2, 3)
    println(ga.joinToString(prefix = "[", postfix = "]"))

    // specialized array (one for each primitive type)
    val da = doubleArrayOf(4.0, 5.0, 6.0)
    println(da.joinToString(prefix = "[", postfix = "]"))

    // immutable list
    val li = listOf<Byte>(7, 8, 9)
    println(li)

    // mutable list
    val ml = mutableListOf<Short>()
    ml.add(10); ml.add(11); ml.add(12)
    println(ml)

    // immutable map
    val hm = mapOf('a' to 97, 'b' to 98, 'c' to 99)
    println(hm)

    // mutable map
    val mm = mutableMapOf<Char, Int>()
    mm.put('d', 100); mm.put('e', 101); mm.put('f', 102)
    println(mm)

    // immutable set (duplicates not allowed)
    val se = setOf(1, 2, 3)
    println(se)

    // mutable set (duplicates not allowed)
    val ms = mutableSetOf<Long>()
    ms.add(4L); ms.add(5L); ms.add(6L)
    println(ms)

    // priority queue (imported from Java)
    val pq = PriorityQueue<String>()
    pq.add("First"); pq.add("Second"); pq.add("Third")
    println(pq)
}


-- list stuff
l = [1, 2]
l.add(3)
l.add(4)
put l
-- [1, 2, 3, 4]

-- property list stuff
pl = [#foo: 1, #bar: 2]
pl[#foobar] = 3
pl["barfoo"] = 4
put pl
-- [#foo: 1, #bar: 2, #foobar: 3, "barfoo": 4]


+ vector : ARRAY[INTEGER];
vector := ARRAY[INTEGER].create_with_capacity 32 lower 0;
vector.add_last 1;
vector.add_last 2;


collection = {0, '1'}
print(collection[1]) -- prints 0

collection = {["foo"] = 0, ["bar"] = '1'} -- a collection of key/value pairs
print(collection["foo"]) -- prints 0
print(collection.foo) -- syntactic sugar, also prints 0

collection = {0, '1', ["foo"] = 0, ["bar"] = '1'}


Module Arr {
      \\ array as tuple
      A=(1,2,3,4,5)
      Print Array(A,0)=1
      Print A
      \\ add two arrays
      A=Cons(A, (6,))
      Print Len(A)=6
      Print A
      \\ arrays may have arrays, inventories, stacks as items
      A=((1,2,3),(4,5,6))
      Print Array(Array(A, 0),2)=3
}
Arr


>> A = {2,'TPS Report'} %Declare cell-array and initialize

A =

    [2]    'TPS Report'

>> A{2} = struct('make','honda','year',2003)

A =

    [2]    [1x1 struct]

>> A{3} = {3,'HOVA'} %Create and assign A{3}

A =

    [2]    [1x1 struct]    {1x2 cell}

>> A{2} %Get A{2}

ans =

    make: 'honda'
    year: 2003


seq = [0, "foo", pi]
seq.push 42
seq = seq + [1, 2, 3]
print seq


ll=LDList.CreateFromValues("")
LDList.Add(ll "Cars")
LDList.Add(ll "Toys")
LDList.Print(ll)


/* NetRexx */
options replace format comments java crossref symbols nobinary

myVals = [ 'zero', 'one', 'two', 'three', 'four', 'five' ]
mySet = Set
mySet = HashSet()

loop val over myVals
  mySet.add(val)
  end val

loop val over mySet
  say val
  end val

return


values := IntVector->New();
values->AddBack(7);
values->AddBack(3);
values->AddBack(10);


#import <Foundation/Foundation.h>

void show_collection(id coll)
{
  for ( id el in coll )
  {
    if ( [coll isKindOfClass: [NSCountedSet class]] ) {
      NSLog(@"%@ appears %lu times", el, [coll countForObject: el]);
    } else if ( [coll isKindOfClass: [NSDictionary class]] ) {
      NSLog(@"%@ -> %@", el, coll[el]);
    } else {
      NSLog(@"%@", el);
    }
  }
  printf("\n");
}

int main()
{
  @autoreleasepool {

    // create an empty set
    NSMutableSet *set = [[NSMutableSet alloc] init];
    // populate it
    [set addObject: @"one"];
    [set addObject: @10];
    [set addObjectsFromArray: @[@"one", @20, @10, @"two"] ];
    // let's show it
    show_collection(set);

    // create an empty counted set (a bag)
    NSCountedSet *cset = [[NSCountedSet alloc] init];
    // populate it
    [cset addObject: @"one"];
    [cset addObject: @"one"];
    [cset addObject: @"two"];
    // show it
    show_collection(cset);

    // create a dictionary
    NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
    // populate it
    dict[@"four"] = @4;
    dict[@"eight"] = @8;
    // show it
    show_collection(dict);

  }
  return EXIT_SUCCESS;
}


  Buffer		A collection of bytes
     Mem		A mutable collection of bytes
  Interval             A first value, a last value and a step.
  Pair                 A collection of 2 elements (with key/value features).
  List			A collection of n elements
     ListBuffer        A mutable collection of n elements that can grow when necessary
  String               A collection of n characters
     Symbol            A collection of n characters that are identity (if they are equal, they are the same object).
     StringBuffer      A mutable collection of n charaters that can grow when necessary


a = .array~new(4)   -- creates an array of 4 items, with all slots empty
say a~size a~items  -- size is 4, but there are 0 items
a[1] = "Fred"       -- assigns a value to the first item
a[5] = "Mike"       -- assigns a value to the fifth slot, expanding the size
say a~size a~items  -- size is now 5, with 2 items


declare
  %% Lists (immutable, recursive)
  Xs = [1 2 3 4]
  %% Add element at the front (cons)
  Xs0 = 0|Xs
  {Show {Length Xs}} %% output: 4

  %% Records (immutable maps with a label)
  Rec = label(1:2 symbol:3)
  {Show Rec}   %% output: label(2 symbol:3)
  {Show Rec.1} %% output: 2
  %% create a new record with an added field
  Rec2 = {AdjoinAt Rec 2 value}
  {Show Rec2}  %% output: label(2 value symbol:3)

  %% Dictionaries (mutable maps)
  Dict = {Dictionary.new}
  Dict.1 := 1
  Dict.symbol := 3
  {Show Dict.1} %% output: 1

  %% Arrays (mutable with integer keys)
  Arr = {Array.new 1 10 initValue}
  Arr.1 := 3
  {Show Arr.1} %% output: 3


v = vector(0);
v = [];
cv = vectorv(0);
cv = []~;
m = matrix(1,1);
s = Set(v);
l = List(v);
vs = vectorsmall(0);
M = Map()


var
  MyArray: array[1..5] of real;
begin
  MyArray[1] := 4.35;
end;


use strict;
my @c = (); # create an empty "array" collection

# fill it
push @c, 10, 11, 12;
push @c, 65;
# print it
print join(" ",@c) . "\n";

# create an empty hash
my %h = ();
# add some pair
$h{'one'} = 1;
$h{'two'} = 2;
# print it
foreach my $i ( keys %h ) {
    print $i . " -> " . $h{$i} . "\n";
}


with javascript_semantics
sequence collection = {}
collection = append(collection,"one")
collection = prepend(collection,2)
? collection -- {2,"one"}


<?php
$a = array();
# add elements "at the end"
array_push($a, 55, 10, 20);
print_r($a);
# using an explicit key
$a['one'] = 1;
$a['two'] = 2;
print_r($a);
?>


go =>
  L = [1,2,3,4],
  L2 = L ++ [[5,6,7]], % adding a list
  L3 = ["a string"] ++ L2, % adding a string

  % Prolog way
  append([0],L,[5],L4).


   declare countries character (20) varying controlled;
   allocate countries initial ('Britain');
   allocate countries initial ('America');
   allocate countries initial ('Argentina');


# Create an Array by separating the elements with commas:
$array = "one", 2, "three", 4

# Using explicit syntax:
$array = @("one", 2, "three", 4)

# Send the values back into individual variables:
$var1, $var2, $var3, $var4 = $array

# An array of several integer ([int]) values:
$array = 0, 1, 2, 3, 4, 5, 6, 7

# Using the range operator (..):
$array = 0..7

# Strongly typed:
[int[]] $stronglyTypedArray = 1, 2, 4, 8, 16, 32, 64, 128

# An empty array:
$array = @()

# An array with a single element:
$array = @("one")

# I suppose this would be a jagged array:
$jaggedArray = @((11, 12, 13),
                 (21, 22, 23),
                 (31, 32, 33))

$jaggedArray | Format-Wide {$_} -Column 3 -Force

$jaggedArray[1][1] # returns 22

# A Multi-dimensional array:
$multiArray = New-Object -TypeName "System.Object[,]" -ArgumentList 6,6

for ($i = 0; $i -lt 6; $i++)
{
    for ($j = 0; $j -lt 6; $j++)
    {
        $multiArray[$i,$j] = ($i + 1) * 10 + ($j + 1)
    }
}

$multiArray | Format-Wide {$_} -Column 6 -Force

$multiArray[2,2] # returns 33


% create a list
L = [a,b,c,d],

% prepend to the list
L2 = [before_a|L],

% append to the list
append(L2, ['Hello'], L3),

% delete from list
exclude(=(b), L3, L4).


Dim Text.s(9)

Text(3)="Hello"
Text(7)="World!"


collection = [0, '1']                 # Lists are mutable (editable) and can be sorted in place
x = collection[0]                     # accessing an item (which happens to be a numeric 0 (zero)
collection.append(2)                  # adding something to the end of the list
collection.insert(0, '-1')            # inserting a value into the beginning
y = collection[0]                     # now returns a string of "-1"
collection.extend([2,'3'])            # same as [collection.append(i) for i in [2,'3']] ... but faster
collection += [2,'3']                 # same as previous line
collection[2:6]                       # a "slice" (collection of the list elements from the third up to but not including the sixth)
len(collection)                       # get the length of (number of elements in) the collection
collection = (0, 1)                   # Tuples are immutable (not editable)
collection[:]                         # ... slices work on these too; and this is equivalent to collection[0:len(collection)]
collection[-4:-1]                     # negative slices count from the end of the string
collection[::2]                       # slices can also specify a stride --- this returns all even elements of the collection
collection="some string"              # strings are treated as sequences of characters
x = collection[::-1]                  # slice with negative step returns reversed sequence (string in this case).
collection[::2] == "some string"[::2] # True, literal objects don't need to be bound to name/variable to access slices or object methods
collection.__getitem__(slice(0,len(collection),2))  # same as previous expressions.
collection = {0: "zero", 1: "one"}    # Dictionaries (Hash)
collection['zero'] = 2                # Dictionary members accessed using same syntax as list/array indexes.
collection = set([0, '1'])            # sets (Hash)


#lang racket

;; create a list
(list 1 2 3 4)
;; create a list of size N
(make-list 100 0)
;; add an element to the front of a list (non-destructively)
(cons 1 (list 2 3 4))


# Array
my @array = 1,2,3;
@array.push: 4,5,6;

# Hash
my %hash = 'a' => 1, 'b' => 2;
%hash<c d> = 3,4;
%hash.push: 'e' => 5, 'f' => 6;

# SetHash
my $s = SetHash.new: <a b c>;
$s ∪= <d e f>;

# BagHash
my $b = BagHash.new: <b a k l a v a>;
$b ⊎= <a b c>;


[ 1 2 3 'abc' ] as a_list
a_list print

list (4 items)
 0 => 1
 1 => 2
 2 => 3
 3 => "abc"


pr. =                             /*define a default for all elements for the array*/

pr.1  = 2                         /*note that this array starts at   1   (one).    */
pr.2  = 3
pr.3  = 5
pr.4  = 7
pr.5  = 11
pr.6  = 13
pr.7  = 17
pr.8  = 19
pr.9  = 23
pr.10 = 29
pr.11 = 31
pr.12 = 37
pr.13 = 41
pr.14 = 43
pr.15 = 47

y.     =     0                    /*define a default for all years  (Y)  to be zero*/
y.1985 =  6020
y.1986 =  7791
y.1987 =  8244
y.1988 = 10075

x = y.2012                        /*the variable  X  will have a value of zero (0).*/

fib.0 =  0                        /*this stemmed arrays will start with  zero (0). */
fib.1 =  1
fib.2 =  1
fib.3 =  2
fib.4 =  3
fib.5 =  5
fib.6 =  8
fib.7 = 17

   do n=-5  to 5                  /*define a stemmed array from   -5    to    5    */
   sawtooth.n = n                 /*the  sawtooth  array is, well, a sawtooth curve*/
   end   /*n*/                    /*note that  eleven  elements will be defined.   */


text = list(2)
text[1] = "Hello "
text[2] = "world!"
see text[1] + text[2] + nl


# creating an empty array and adding values
a = []              #=> []
a[0] = 1            #=> [1]
a[3] = "abc"        #=> [1, nil, nil, "abc"]
a << 3.14           #=> [1, nil, nil, "abc", 3.14]

# creating an array with the constructor
a = Array.new               #=> []
a = Array.new(3)            #=> [nil, nil, nil]
a = Array.new(3, 0)         #=> [0, 0, 0]
a = Array.new(3){|i| i*2}   #=> [0, 2, 4]


Windows PowerShell
Copyright (C) 2012 Microsoft Corporation. All rights reserved.

PS C:\Users\FransAdm> scala
Welcome to Scala version 2.10.1 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_25).
Type in expressions to have them evaluated.
Type :help for more information.

scala> // Immutable collections do not and cannot change the instantiated object

scala> // Lets start with Lists

scala> val list = Nil // Empty List
list: scala.collection.immutable.Nil.type = List()

scala> val list2 = List("one", "two") // List with two elements (Strings)
list2: List[String] = List(one, two)

scala> val list3 = 3 :: list2 // prepend 3 to list2, using a special operator
list3: List[Any] = List(3, one, two)

scala> // The result was a mixture with a Int and Strings, so the common superclass Any is used.

scala> // Let test the Set collection

scala> val set = Set.empty[Char] // Empty Set of Char type
set: scala.collection.immutable.Set[Char] = Set()

scala> val set1 = set + 'c' // add an element
set1: scala.collection.immutable.Set[Char] = Set(c)

scala> val set2 = set + 'a' + 'c' + 'c' // try to add another and  the same element twice
set2: scala.collection.immutable.Set[Char] = Set(a, c)

scala> // Let's look at the most universal map: TrieMap (Cache-aware lock-free concurrent hash trie)

scala> val capital = collection.concurrent.TrieMap("US" -> "Washington", "France" -> "Paris") // This map is mutable
capital: scala.collection.concurrent.TrieMap[String,String] = TrieMap(US -> Washington, France -> Paris)

scala> capital - "France" // This is only an expression, does not modify the map itself
res0: scala.collection.concurrent.TrieMap[String,String] = TrieMap(US -> Washington)

scala> capital += ("Tokio" -> "Japan") // Adding an element, object is changed - not the val capital
res1: capital.type = TrieMap(US -> Washington, Tokio -> Japan, France -> Paris)

scala> capital // Check what we have sofar
res2: scala.collection.concurrent.TrieMap[String,String] = TrieMap(US -> Washington, Tokio -> Japan, France -> Paris)

scala>  val queue = new scala.collection.mutable.Queue[String]
queue: scala.collection.mutable.Queue[String] = Queue()

scala> queue += "first"
res17: queue.type = Queue("first")

scala> queue += "second"
res19: queue.type = Queue("first", "second")

scala>


$ include "seed7_05.s7i";

enable_output(set of string);

const proc: main is func
  local
    var set of string: aSet is {"iron", "copper"};
  begin
    writeln(aSet);
    incl(aSet, "silver");
    writeln(aSet);
  end func;


set = new('set 5 10 15 20 25 25')
add(set,30)
show(set)

show.eval('member(set,5)')
show.eval('member(set,6)')

show.eval("exists(set,'eq(this,10)')")
show.eval("forall(set,'eq(this,40)')")


# creating an empty array and adding values
var a = []          #=> []
a[0] = 1            #=> [1]
a[3] = "abc"        #=> [1, nil, nil, "abc"]
a << 3.14           #=> [1, nil, nil, "abc", 3.14]


|anOrdered aBag aSet aSorted aSorted2 aDictionary|

anOrdered := OrderedCollection new.
anOrdered add: 1; add: 5; add: 3.
anOrdered printNl.

aBag := Bag new.
aBag add: 5; add: 5; add: 5; add: 6.
aBag printNl.

aSet := Set new.
aSet add: 10; add: 5; add: 5; add: 6; add: 10.
aSet printNl.

aSorted := SortedCollection new.
aSorted add: 10; add: 9; add: 8; add: 5.
aSorted printNl.

"another sorted with custom comparator: let's sort
 the other collections according to their size (number of
 elements)"
aSorted2 := SortedCollection sortBlock: [ :a :b |
    (a size) < (b size) ].
aSorted2 add: anOrdered; add: aBag; add: aSet; add: aSorted.
aSorted2 printNl.

aDictionary := Dictionary new.
aDictionary at: 'OrderedCollection' put: anOrdered;
            at: 'Bag' put: aBag;
            at: 'Set' put: aSet;
            at: 'SortedCollection' put: { aSorted. aSorted2 }.
aDictionary printNl.


set c [list] ;# create an empty list
# fill it
lappend c 10 11 13
set c [linsert $c 2 "twelve goes here"]
# iterate over it
foreach elem $c {puts $elem}

# pass to a proc
proc show_size {l} {
    puts [llength $l]
}
show_size $c


$$ MODE TUSCRIPT

collection=*
DATA apple
DATA banana
DATA orange

morestuff=*
DATA peaches
DATA apple

collection=APPEND(collection,morestuff)
TRACE *collection


a_index=(one two three)           # create an array with a few elements
a_index+=(four five)              # append some elements
a_index[9]=ten                   # add a specific index
for elem in "${a_index[@]}"; do   # interate over the elements
    echo "$elem"
done
for idx in "${!a_index[@]}"; do   # interate over the array indices
    printf "%d\t%s\n" $idx "${a_index[idx]}"
done


Dim coll As New Collection
coll.Add "apple"
coll.Add "banana"


Dim toys As New List(Of String)
toys.Add("Car")
toys.Add("Boat")
toys.Add("Train")


LOCAL loColl As Collection, o, a1, a2, a3
a1 = CREATEOBJECT("animal", "dog", 4)
a2 = CREATEOBJECT("animal", "chicken", 2)
a3 = CREATEOBJECT("animal", "snake", 0)
loColl = NEWOBJECT("Collection")
loColl.Add(a1)
loColl.Add(a2)
loColl.Add(a3)

FOR EACH o IN loColl FOXOBJECT
    ? o.Name, o.Legs
ENDFOR

DEFINE CLASS animal As Custom
Legs = 0

PROCEDURE Init(tcName, tnLegs)
THIS.Name = tcName
THIS.Legs = tnLegs
ENDPROC

ENDDEFINE


var list = [] // Empty Array
list = [1, 2, 3, 4]
list.add(5)
list.clear()
list = [0] * 10
list.count // 10

var map = {}
map["key"] = "value"
map[3] = 31
map.count // 2
map.clear()

for (e in map.keys) {
    // Do stuff
}


Lists: L(1,2,3).append(4); //-->L(1,2,3,4), mutable list
Read only list: ROList(1,2,3).append(4);  // creates two lists

Bit bucket: Data(0,Int,1,2,3) // three bytes
   The "Int" means treat contents as a byte stream
Data(0,Int,"foo ","bar") //-->7 bytes
   Data(0,Int,"foo ").append("bar") //ditto
   Data(0,Int,"foo\n","bar").readln() //-->"foo\n"
Data(0,String,"foo ","bar") //-->9 bytes (2 \0s)
   Data(0,String,"foo ").append("bar").readln() //-->"foo "


--------------------- CHURCH NUMERALS --------------------

-- churchZero :: (a -> a) -> a -> a
on churchZero(f, x)
    x
end churchZero

-- churchSucc :: ((a -> a) -> a -> a) -> (a -> a) -> a -> a
on churchSucc(n)
    script
        on |λ|(f)
            script
                property mf : mReturn(f)
                on |λ|(x)
                    mf's |λ|(mReturn(n)'s |λ|(mf)'s |λ|(x))
                end |λ|
            end script
        end |λ|
    end script
end churchSucc

-- churchFromInt(n) :: Int -> (b -> b) -> b -> b
on churchFromInt(n)
    script
        on |λ|(f)
            foldr(my compose, my |id|, replicate(n, f))
        end |λ|
    end script
end churchFromInt

-- intFromChurch :: ((Int -> Int) -> Int -> Int) -> Int
on intFromChurch(cn)
    mReturn(cn)'s |λ|(my succ)'s |λ|(0)
end intFromChurch

on churchAdd(m, n)
    script
        on |λ|(f)
            script
                property mf : mReturn(m)
                property nf : mReturn(n)
                on |λ|(x)
                    nf's |λ|(f)'s |λ|(mf's |λ|(f)'s |λ|(x))
                end |λ|
            end script
        end |λ|
    end script
end churchAdd

on churchMult(m, n)
    script
        on |λ|(f)
            script
                property mf : mReturn(m)
                property nf : mReturn(n)
                on |λ|(x)
                    mf's |λ|(nf's |λ|(f))'s |λ|(x)
                end |λ|
            end script
        end |λ|
    end script
end churchMult

on churchExp(m, n)
    n's |λ|(m)
end churchExp

--------------------------- TEST -------------------------
on run
    set cThree to churchFromInt(3)
    set cFour to churchFromInt(4)

    map(intFromChurch, ¬
        {churchAdd(cThree, cFour), churchMult(cThree, cFour), ¬
            churchExp(cFour, cThree), churchExp(cThree, cFour)})
end run

------------------------- GENERIC ------------------------

-- compose (<<<) :: (b -> c) -> (a -> b) -> a -> c
on compose(f, g)
    script
        property mf : mReturn(f)
        property mg : mReturn(g)
        on |λ|(x)
            mf's |λ|(mg's |λ|(x))
        end |λ|
    end script
end compose

-- id :: a -> a
on |id|(x)
    x
end |id|

-- foldr :: (a -> b -> b) -> b -> [a] -> b
on foldr(f, startValue, xs)
    tell mReturn(f)
        set v to startValue
        set lng to length of xs
        repeat with i from lng to 1 by -1
            set v to |λ|(item i of xs, v, i, xs)
        end repeat
        return v
    end tell
end foldr

-- map :: (a -> b) -> [a] -> [b]
on map(f, xs)
    tell mReturn(f)
        set lng to length of xs
        set lst to {}
        repeat with i from 1 to lng
            set end of lst to |λ|(item i of xs, i, xs)
        end repeat
        return lst
    end tell
end map

-- Lift 2nd class handler function into 1st class script wrapper
-- mReturn :: First-class m => (a -> b) -> m (a -> b)
on mReturn(f)
    if class of f is script then
        f
    else
        script
            property |λ| : f
        end script
    end if
end mReturn

-- Egyptian multiplication - progressively doubling a list, appending
-- stages of doubling to an accumulator where needed for binary
-- assembly of a target length
-- replicate :: Int -> a -> [a]
on replicate(n, a)
    set out to {}
    if n < 1 then return out
    set dbl to {a}

    repeat while (n > 1)
        if (n mod 2) > 0 then set out to out & dbl
        set n to (n div 2)
        set dbl to (dbl & dbl)
    end repeat
    return out & dbl
end replicate

-- succ :: Int -> Int
on succ(x)
    1 + x
end succ


using System;

public delegate Church Church(Church f);

public static class ChurchNumeral
{
    public static readonly Church ChurchZero = _ => x => x;
    public static readonly Church ChurchOne = f => f;

    public static Church Successor(this Church n) => f => x => f(n(f)(x));
    public static Church Add(this Church m, Church n) => f => x => m(f)(n(f)(x));
    public static Church Multiply(this Church m, Church n) => f => m(n(f));
    public static Church Exponent(this Church m, Church n) => n(m);
    public static Church IsZero(this Church n) => n(_ => ChurchZero)(ChurchOne);
    public static Church Predecessor(this Church n) =>
      f => x => n(g => h => h(g(f)))(_ => x)(a => a);
    public static Church Subtract(this Church m, Church n) => n(Predecessor)(m);
    static Church looper(this Church v, Church d) =>
        v(_ => v.divr(d).Successor())(ChurchZero);
    static Church divr(this Church n, Church d) =>
        n.Subtract(d).looper(d);
    public static Church Divide(this Church dvdnd, Church dvsr) =>
        (dvdnd.Successor()).divr(dvsr);

    public static Church FromInt(int i) =>
      i <= 0 ? ChurchZero : Successor(FromInt(i - 1));

    public static int ToInt(this Church ch) {
        int count = 0;
        ch(x => { count++; return x; })(null);
        return count;
    }

    public static void Main() {
        Church c3 = FromInt(3);
        Church c4 = c3.Successor();
        Church c11 = FromInt(11);
        Church c12 = c11.Successor();
        int sum = c3.Add(c4).ToInt();
        int product = c3.Multiply(c4).ToInt();
        int exp43 = c4.Exponent(c3).ToInt();
        int exp34 = c3.Exponent(c4).ToInt();
        int tst0 = ChurchZero.IsZero().ToInt();
        int pred4 = c4.Predecessor().ToInt();
        int sub43 = c4.Subtract(c3).ToInt();
        int div11by3 = c11.Divide(c3).ToInt();
        int div12by3 = c12.Divide(c3).ToInt();
        Console.Write($"{sum} {product} {exp43} {exp34} {tst0} ");
        Console.WriteLine($"{pred4} {sub43} {div11by3} {div12by3}");
    }
}


class Church { // identity Church function by default
    proc this(f: shared Church): shared Church { return f; }
}

// utility Church functions...
class ComposeChurch : Church {
    const l, r: shared Church;
    override proc this(f: shared Church): shared Church {
        return l(r(f)); }
}

proc composeChurch(chl: shared Church, chr: shared Church) : shared Church {
    return new shared ComposeChurch(chl, chr): shared Church;
}

class ConstChurch : Church {
    const ch: shared Church;
    override proc this(f: shared Church): shared Church { return ch; }
}

proc constChurch(ch: shared Church): shared Church {
    return new shared ConstChurch(ch): shared Church;
}

// Church constants...
const cIdentityChurch: shared Church = new shared Church();
const cChurchZero = constChurch(cIdentityChurch);
const cChurchOne = cIdentityChurch; // default is identity!

// Church functions...
class SuccChurch: Church {
    const curr: shared Church;
    override proc this(f: shared Church): shared Church {
        return composeChurch(f, curr(f)); }
}

proc succChurch(ch: shared Church): shared Church {
    return new shared SuccChurch(ch) : shared Church;
}

class AddChurch: Church {
    const chf, chs: shared Church;
    override proc this(f: shared Church): shared Church {
        return composeChurch(chf(f), chs(f)); }
}

proc addChurch(cha: shared Church, chb: shared Church): shared Church {
    return new shared AddChurch(cha, chb) : shared Church;
}

class MultChurch: Church {
    const chf, chs: shared Church;
    override proc this(f: shared Church): shared Church {
        return composeChurch(chf, chs)(f); }
}

proc multChurch(cha: shared Church, chb: shared Church): shared Church {
    return new shared MultChurch(cha, chb) : shared Church;
}

class ExpChurch : Church {
    const b, e : shared Church;
    override proc this(f : shared Church): shared Church { return e(b)(f); }
}

proc expChurch(chbs: shared Church, chexp: shared Church): shared Church {
    return new shared ExpChurch(chbs, chexp) : shared Church;
}

class IsZeroChurch : Church {
    const c : shared Church;
    override proc this(f : shared Church): shared Church {
        return c(constChurch(cChurchZero))(cChurchOne)(f); }
}

proc isZeroChurch(ch: shared Church): shared Church {
    return new shared IsZeroChurch(ch) : shared Church;
}

class PredChurch : Church {
    const c : shared Church;
    class XFunc : Church {
        const cf, fnc: shared Church;
        class GFunc : Church {
            const fnc: shared Church;
            class HFunc : Church {
                const fnc, g: shared Church;
                override proc this(f : shared Church): shared Church {
                    return f(g(fnc)); }
            }
            override proc this(f : shared Church): shared Church {
                return new shared HFunc(fnc, f): shared Church; }
        }
        override proc this(f : shared Church): shared Church {
            const prd = new shared GFunc(fnc): shared Church;
            return cf(prd)(constChurch(f))(cIdentityChurch); }
    }
    override proc this(f : shared Church): shared Church {
        return new shared XFunc(c, f) : shared Church; }
}

proc predChurch(ch: shared Church): shared Church {
    return new shared PredChurch(ch) : shared Church;
}

class SubChurch : Church {
    const a, b : shared Church;
    class PredFunc : Church {
        override proc this(f : shared Church): shared Church {
            return new shared PredChurch(f): shared Church;
        }
    }
    override proc this(f : shared Church): shared Church {
        const prdf = new shared PredFunc(): shared Church;
        return b(prdf)(a)(f); }
}

proc subChurch(cha: shared Church, chb: shared Church): shared Church {
    return new shared SubChurch(cha, chb) : shared Church;
}

class DivrChurch : Church {
    const v, d : shared Church;
    override proc this(f : shared Church): shared Church {
        const loopr = constChurch(succChurch(divr(v, d)));
        return v(loopr)(cChurchZero)(f); }
}

proc divr(n: shared Church, d : shared Church): shared Church {
    return new shared DivrChurch(subChurch(n, d), d): shared Church;
}

proc divChurch(chdvdnd: shared Church, chdvsr: shared Church): shared Church {
    return divr(succChurch(chdvdnd), chdvsr);
}

// conversion functions...
proc loopChurch(i: int, ch: shared Church) : shared Church { // tail call...
    return if (i <= 0) then ch else loopChurch(i - 1, succChurch(ch));
}

proc churchFromInt(n: int): shared Church {
    return loopChurch(n, cChurchZero); // can't embed "worker" proc!
}

class IntChurch : Church {
    const value: int;
}

class IncChurch : Church {
    override proc this(f: shared Church): shared Church {
        const tst = f: IntChurch;
        if tst != nil {
          return new shared IntChurch(tst.value + 1): shared Church; }
        else return f; } // shouldn't happen!
}

proc intFromChurch(ch: shared Church): int {
    const zero = new shared IntChurch(0): shared Church;
    const tst = ch(new shared IncChurch(): shared Church)(zero): IntChurch;
    if tst != nil { return tst.value; }
    else return -1; // should never happen!
}

// testing...
const ch3 = churchFromInt(3); const ch4 = succChurch(ch3);
const ch11 = churchFromInt(11); const ch12 = succChurch(ch11);
write(intFromChurch(addChurch(ch3, ch4)), ", ");
write(intFromChurch(multChurch(ch3, ch4)), ", ");
write(intFromChurch(expChurch(ch3, ch4)), ", ");
write(intFromChurch(expChurch(ch4, ch3)), ", ");
write(intFromChurch(isZeroChurch(cChurchZero)), ", ");
write(intFromChurch(isZeroChurch(ch3)), ", ");
write(intFromChurch(predChurch(ch4)), ", ");
write(intFromChurch(predChurch(cChurchZero)), ", ");
write(intFromChurch(subChurch(ch11, ch3)), ", ");
write(intFromChurch(divChurch(ch11, ch3)), ", ");
writeln(intFromChurch(divChurch(ch12, ch3)));


(defn zero [f] identity)
(defn succ  [n]   (fn [f] (fn [x] (f ((n f) x)))))
(defn add   [n,m] (fn [f] (fn [x] ((m f)((n f) x)))))
(defn mult  [n,m] (fn [f] (fn [x] ((m (n f)) x))))
(defn power [b,e] (e b))

(defn to-int [c] ((c inc) 0))

(defn from-int [n]
  (letfn [(countdown [i] (if (zero? i) zero (succ (countdown (- i 1)))))]
  (countdown n)))

(def three (succ (succ (succ zero))))
(def four (from-int 4))

(doseq [n [(add three four)   (mult three four)
           (power three four) (power four three)]]
    (println (to-int n)))


struct Church # can't be generic!
  getter church : (Church -> Church) | Int32
  def initialize(@church) end
  def apply(ch)
    chf = @church
    chf.responds_to?(:call) ? chf.call(ch) : self
  end
  def compose(chr)
    chlf = @church
    chrf = chr.church
    if chlf.responds_to?(:call) && chrf.responds_to?(:call)
      Church.new(-> (f : Church) { chlf.call(chrf.call(f)) })
    else
      self
    end
  end
end

# Church Numeral constants...
CHURCH_ZERO = begin
  Church.new(-> (f : Church) {
    Church.new(-> (x : Church) { x }) })
end

CHURCH_ONE = begin
  Church.new(-> (f : Church) { f })
end

# Church Numeral functions...
def succChurch
  -> (ch : Church) {
        Church.new(-> (f : Church) { f.compose(ch.apply(f)) }) }
end

def addChurch
  -> (cha : Church, chb : Church) {
        Church.new(-> (f : Church) { cha.apply(f).compose(chb.apply(f)) }) }
end

def multChurch
  -> (cha : Church, chb : Church) { cha.compose(chb) }
end

def expChurch
  -> (chbs : Church, chexp : Church) { chexp.apply(chbs) }
end

def isZeroChurch
  liftZero = Church.new(-> (f : Church) { CHURCH_ZERO })
  -> (ch : Church) { ch.apply(liftZero).apply(CHURCH_ONE) }
end

def predChurch
  -> (ch : Church) {
    Church.new(-> (f : Church) { Church.new(-> (x : Church) {
          prd = Church.new(-> (g : Church) { Church.new(-> (h : Church) {
                  h.apply(g.apply(f)) }) })
          frst = Church.new(-> (d : Church) { x })
          id = Church.new(-> (a : Church) { a })
          ch.apply(prd).apply(frst).apply(id)
      }) }) }
end

def subChurch
  -> (cha : Church, chb : Church) {
    chb.apply(Church.new(predChurch)).apply(cha) }
end

def divr # can't be nested in another def...
  -> (n : Church, d: Church) {
    tstr = -> (v : Church) {
      loopr = Church.new(-> (a : Church) {
        succChurch.call(divr.call(v, d)) }) # recurse until zero
      v.apply(loopr).apply(CHURCH_ZERO) }
    tstr.call(subChurch.call(n, d)) }
end

def divChurch
  -> (chdvdnd : Church, chdvsr : Church) {
        divr.call(succChurch.call(chdvdnd), chdvsr) }
end

# conversion functions...
def intToChurch(i) : Church
  rslt = CHURCH_ZERO
  cntr = 0
  while cntr < i
    rslt = succChurch.call(rslt)
    cntr += 1
  end
  rslt
end

def churchToInt(ch) : Int32
  succInt32 = Church.new(-> (v : Church) {
    vi = v.church
    vi.is_a?(Int32) ? Church.new(vi + 1) : v })
  rslt = ch.apply(succInt32).apply(Church.new(0)).church
  rslt.is_a?(Int32) ? rslt : -1
end

# testing...
ch3 = intToChurch(3)
ch4 = succChurch.call(ch3)
ch11 = intToChurch(11)
ch12 = succChurch.call(ch11)
add = churchToInt(addChurch.call(ch3, ch4))
mult = churchToInt(multChurch.call(ch3, ch4))
exp1 = churchToInt(expChurch.call(ch3, ch4))
exp2 = churchToInt(expChurch.call(ch4, ch3))
iszero1 = churchToInt(isZeroChurch.call(CHURCH_ZERO))
iszero2 = churchToInt(isZeroChurch.call(ch3))
pred1 = churchToInt(predChurch.call(ch4))
pred2 = churchToInt(predChurch.call(CHURCH_ZERO))
sub = churchToInt(subChurch.call(ch11, ch3))
div1 = churchToInt(divChurch.call(ch11, ch3))
div2 = churchToInt(divChurch.call(ch12, ch3))
print("#{add} #{mult} #{exp1} #{exp2} #{iszero1} #{iszero2} ")
print("#{pred1} #{pred2} #{sub} #{div1} #{div2}\r\n")


module Main exposing ( main )

import Html exposing ( Html, text )

type alias Church a = (a -> a) -> a -> a

churchZero : Church a -- a Church constant
churchZero = always identity

succChurch : Church a -> Church a
succChurch ch = \ f -> f << ch f -- add one recursion

addChurch : Church a -> Church a -> Church a
addChurch chaf chbf = \ f -> chaf f << chbf f

multChurch : Church a -> Church a -> Church a
multChurch = (<<)

expChurch : Church a -> (Church a -> Church a) -> Church a
expChurch = (\ f x y -> f y x) identity -- `flip` inlined

churchFromInt : Int -> Church a
churchFromInt n = if n <= 0 then churchZero
                  else succChurch <| churchFromInt (n - 1)

intFromChurch : Church Int -> Int
intFromChurch cn = cn ((+) 1) 0 -- `succ` inlined

--------------------------- TEST -------------------------
main : Html Never
main =
  let cThree = churchFromInt 3
      cFour = succChurch cThree
  in [ addChurch cThree cFour
     , multChurch cThree cFour
     , expChurch cThree cFour
     , expChurch cFour cThree
     ] |> List.map intFromChurch
       |> Debug.toString |> text


-module(church).
-export([main/1, zero/1]).
zero(_)    -> fun(F) -> F end.
succ(N)    -> fun(F) -> fun(X) -> F((N(F))(X)) end end.
add(N,M)   -> fun(F) -> fun(X) -> (M(F))((N(F))(X)) end end.
mult(N,M)  -> fun(F) -> fun(X) -> (M(N(F)))(X) end end.
power(B,E) -> E(B).

to_int(C) -> CountUp = fun(I) -> I + 1 end, (C(CountUp))(0).

from_int(0) -> fun church:zero/1;
from_int(I) -> succ(from_int(I-1)).

main(_) ->
    Zero  = fun church:zero/1,
    Three = succ(succ(succ(Zero))),
    Four  = from_int(4),
    lists:map(fun(C) -> io:fwrite("~w~n",[to_int(C)]) end,
	      [add(Three,Four),   mult(Three,Four),
	       power(Three,Four), power(Four,Three)]).


type IChurch =
  abstract Apply : ('a -> 'a) -> ('a -> 'a)

let zeroChurch = { new IChurch with override __.Apply _ = id }
let oneChurch = { new IChurch with override __.Apply f = f }
let succChurch (n: IChurch) =
  { new IChurch with override __.Apply f = fun x -> f (n.Apply f x) }
let addChurch (m: IChurch) (n: IChurch) =
  { new IChurch with override __.Apply f = fun x -> m.Apply f (n.Apply f x) }
let multChurch (m: IChurch) (n: IChurch) =
  { new IChurch with override __.Apply f = m.Apply (n.Apply f) }
let expChurch (m: IChurch) (n: IChurch) =
  { new IChurch with override __.Apply f = n.Apply m.Apply f }
let iszeroChurch (n: IChurch) =
  { new IChurch with
      override __.Apply f = n.Apply (fun _ -> zeroChurch.Apply) oneChurch.Apply f }
let predChurch (n: IChurch) =
  { new IChurch with
      override __.Apply f = fun x -> n.Apply (fun g h -> h (g f))
                                             (fun _ -> x) id }
let subChurch (m: IChurch) (n: IChurch) =
  { new IChurch with override __.Apply f = (n.Apply predChurch m).Apply f }
let divChurch (dvdnd: IChurch) (dvsr: IChurch) =
  let rec divr (n: IChurch) (d: IChurch) =
    { new IChurch with
        override __.Apply f =
          ((fun (v: IChurch) -> // test v for Church zeroChurch...
              v.Apply (fun _ -> (succChurch (divr v d)).Apply) // if not zeroChurch
                                zeroChurch.Apply)(subChurch n d)) f }
  divr (succChurch dvdnd) dvsr

let chtoi (ch: IChurch) = ch.Apply ((+) 1) 0
let itoch i = List.fold (>>) id (List.replicate i succChurch) zeroChurch

#nowarn "25" // skip incomplete pattern warning
[<EntryPoint>]
let main _ =
    let [c3; c4; c11; c12] = List.map itoch [3; 4; 11; 12]

    [ addChurch c3 c4
    ; multChurch c3 c4
    ; expChurch c3 c4
    ; expChurch c4 c3
    ; iszeroChurch zeroChurch
    ; iszeroChurch oneChurch
    ; predChurch c3
    ; subChurch c11 c3
    ; divChurch c11 c3
    ; divChurch c12 c3
    ] |> List.map chtoi |> printfn "%A"
    0 // return an integer exit code


package main

import "fmt"

type any = interface{}

type fn func(any) any

type church func(fn) fn

func zero(f fn) fn {
    return func(x any) any {
        return x
    }
}

func (c church) succ() church {
    return func(f fn) fn {
        return func(x any) any {
            return f(c(f)(x))
        }
    }
}

func (c church) add(d church) church {
    return func(f fn) fn {
        return func(x any) any {
            return c(f)(d(f)(x))
        }
    }
}

func (c church) mul(d church) church {
    return func(f fn) fn {
        return func(x any) any {
            return c(d(f))(x)
        }
    }
}

func (c church) pow(d church) church {
    di := d.toInt()
    prod := c
    for i := 1; i < di; i++ {
        prod = prod.mul(c)
    }
    return prod
}

func (c church) toInt() int {
    return c(incr)(0).(int)
}

func intToChurch(i int) church {
    if i == 0 {
        return zero
    } else {
        return intToChurch(i - 1).succ()
    }
}

func incr(i any) any {
    return i.(int) + 1
}

func main() {
    z := church(zero)
    three := z.succ().succ().succ()
    four := three.succ()

    fmt.Println("three        ->", three.toInt())
    fmt.Println("four         ->", four.toInt())
    fmt.Println("three + four ->", three.add(four).toInt())
    fmt.Println("three * four ->", three.mul(four).toInt())
    fmt.Println("three ^ four ->", three.pow(four).toInt())
    fmt.Println("four ^ three ->", four.pow(three).toInt())
    fmt.Println("5 -> five    ->", intToChurch(5).toInt())
}


class ChurchNumerals {
    static void main(args) {

        def zero = { f -> { a -> a } }
        def succ = { n -> { f -> { a -> f(n(f)(a)) } } }
        def add = { n -> { k -> { n(succ)(k) } } }
        def mult = { f -> { g -> { a -> f(g(a)) } } }
        def pow = { f -> { g -> g(f) } }

        def toChurchNum
        toChurchNum = { n ->
            n == 0 ? zero : succ(toChurchNum(n - 1))
        }

        def toInt = { n ->
            n(x -> x + 1)(0)
        }

        def three = succ(succ(succ(zero)))
        println toInt(three) // prints 3

        def four = succ(three)
        println toInt(four) // prints 4

        println "3 + 4 = ${toInt(add(three)(four))}" // prints 3 + 4 = 7
        println "4 + 3 = ${toInt(add(four)(three))}" // prints 4 + 3 = 7

        println "3 * 4 = ${toInt(mult(three)(four))}" // prints 3 * 4 = 12
        println "4 * 3 = ${toInt(mult(four)(three))}" // prints 4 * 3 = 12

        println "3 ^ 4 = ${toInt(pow(three)(four))}" // prints 3 ^ 4 = 81
        println "4 ^ 3 = ${toInt(pow(four)(three))}" // prints 4 ^ 3 = 64
    }
}


import Unsafe.Coerce ( unsafeCoerce )

type Church a = (a -> a) -> a -> a

churchZero :: Church  a
churchZero = const id

churchOne :: Church a
churchOne = id

succChurch :: Church a -> Church a
succChurch = (<*>) (.) -- add one recursion, or \ ch f -> f . ch f

addChurch :: Church a -> Church a -> Church a
addChurch = (<*>). fmap (.) -- or \ ach bch f -> ach f . bch f

multChurch :: Church a -> Church a -> Church a
multChurch = (.) -- or \ ach bch -> ach . bch

expChurch :: Church a -> Church a -> Church a
expChurch basech expch = unsafeCoerce expch basech

isChurchZero :: Church a -> Church a
isChurchZero ch = unsafeCoerce ch (const churchZero) churchOne

predChurch :: Church a -> Church a
predChurch ch f x = unsafeCoerce ch (\ g h -> h (g f)) (const x) id

minusChurch :: Church a -> Church a -> Church a
minusChurch ach bch = unsafeCoerce bch predChurch ach

-- counts the times divisor can be subtracted from dividend to zero...
divChurch :: Church a -> Church a -> Church a
divChurch dvdnd dvsr =
  let divr n d =
        (\ v -> v (const $ succChurch $ divr v d) -- if branch
                  churchZero -- else branch
        ) (minusChurch n d)
  in divr (unsafeCoerce succChurch dvdnd) $ unsafeCoerce dvsr

churchFromInt :: Int -> Church a
churchFromInt 0 = churchZero
churchFromInt n = succChurch $ churchFromInt (n - 1)

-- Or as a fold:
-- churchFromInt n = foldr (.) id . replicate n

-- Or as an iterated application:
-- churchFromInt n = iterate succChurch churchZero !! n

intFromChurch :: Church Int -> Int
intFromChurch ch = ch succ 0

------------------------------------- TEST -------------------------------------
main :: IO ()
main = do
  let [cThree, cFour, cEleven, cTwelve] = churchFromInt <$> [3, 4, 11, 12]
  print $ fmap intFromChurch  [ addChurch cThree cFour
                              , multChurch cThree cFour
                              , expChurch cFour cThree
                              , expChurch cThree cFour
                              , isChurchZero churchZero
                              , predChurch cFour
                              , minusChurch cEleven cThree
                              , divChurch cEleven cThree
                              , divChurch cTwelve cThree
                              ]


chget=: {{(0;1;1;1) {:: y}}

chset=: {{
  'A B'=.;y
  'C D'=.B
  'E F'=.D
  <A;<C;<E;<<.x
}}

ch0=: {{
  if.0=#y do.y=.;:'>:' end. NB. replace empty gerund with increment
  0 chset y`:6^:2`''
}}

apply=: `:6

chNext=: {{(1+chget y) chset y}}

chAdd=: {{(x +&chget y) chset y}}
chSub=: {{(x -&chget y) chset y}}
chMul=: {{(x *&chget y) chset y}}
chExp=: {{(x ^&chget y) chset y}}
int2ch=: {{y chset ch0 ''}}
ch2int=: chget


package lvijay;

import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;

public class Church {
    public static interface ChurchNum extends Function<ChurchNum, ChurchNum> {
    }

    public static ChurchNum zero() {
        return f -> x -> x;
    }

    public static ChurchNum next(ChurchNum n) {
        return f -> x -> f.apply(n.apply(f).apply(x));
    }

    public static ChurchNum plus(ChurchNum a) {
        return b -> f -> x -> b.apply(f).apply(a.apply(f).apply(x));
    }

    public static ChurchNum pow(ChurchNum m) {
        return n -> m.apply(n);
    }

    public static ChurchNum mult(ChurchNum a) {
        return b -> f -> x -> b.apply(a.apply(f)).apply(x);
    }

    public static ChurchNum toChurchNum(int n) {
        if (n <= 0) {
            return zero();
        }
        return next(toChurchNum(n - 1));
    }

    public static int toInt(ChurchNum c) {
        AtomicInteger counter = new AtomicInteger(0);
        ChurchNum funCounter = f -> {
            counter.incrementAndGet();
            return f;
        };

        plus(zero()).apply(c).apply(funCounter).apply(x -> x);

        return counter.get();
    }

    public static void main(String[] args) {
        ChurchNum zero  = zero();
        ChurchNum three = next(next(next(zero)));
        ChurchNum four  = next(next(next(next(zero))));

        System.out.println("3+4=" + toInt(plus(three).apply(four))); // prints 7
        System.out.println("4+3=" + toInt(plus(four).apply(three))); // prints 7

        System.out.println("3*4=" + toInt(mult(three).apply(four))); // prints 12
        System.out.println("4*3=" + toInt(mult(four).apply(three))); // prints 12

        // exponentiation.  note the reversed order!
        System.out.println("3^4=" + toInt(pow(four).apply(three))); // prints 81
        System.out.println("4^3=" + toInt(pow(three).apply(four))); // prints 64

        System.out.println("  8=" + toInt(toChurchNum(8))); // prints 8
    }
}


(() => {
    'use strict';

    // ----------------- CHURCH NUMERALS -----------------

    const churchZero = f =>
        identity;

    const churchSucc = n =>
        f => compose(f)(n(f));

    const churchAdd = m =>
        n => f => compose(n(f))(m(f));

    const churchMult = m =>
        n => f => n(m(f));

    const churchExp = m =>
        n => n(m);

    const intFromChurch = n =>
        n(succ)(0);

    const churchFromInt = n =>
        compose(
            foldl(compose)(identity)
        )(
            replicate(n)
        );

    // Or, by explicit recursion:
    const churchFromInt_ = x => {
        const go = i =>
            0 === i ? (
                churchZero
            ) : churchSucc(go(pred(i)));
        return go(x);
    };

    // ---------------------- TEST -----------------------
    // main :: IO ()
    const main = () => {
        const [cThree, cFour] = map(churchFromInt)([3, 4]);

        return map(intFromChurch)([
            churchAdd(cThree)(cFour),
            churchMult(cThree)(cFour),
            churchExp(cFour)(cThree),
            churchExp(cThree)(cFour),
        ]);
    };

    // --------------------- GENERIC ---------------------

    // compose (>>>) :: (a -> b) -> (b -> c) -> a -> c
    const compose = f =>
        g => x => f(g(x));

    // foldl :: (a -> b -> a) -> a -> [b] -> a
    const foldl = f =>
        a => xs => [...xs].reduce(
            (x, y) => f(x)(y),
            a
        );

    // identity :: a -> a
    const identity = x => x;

    // map :: (a -> b) -> [a] -> [b]
    const map = f =>
        // The list obtained by applying f
        // to each element of xs.
        // (The image of xs under f).
        xs => [...xs].map(f);

    // pred :: Enum a => a -> a
    const pred = x =>
        x - 1;

    // replicate :: Int -> a -> [a]
    const replicate = n =>
        // n instances of x.
        x => Array.from({
            length: n
        }, () => x);

    // succ :: Enum a => a -> a
    const succ = x =>
        1 + x;

    // MAIN ---
    console.log(JSON.stringify(main()));
})();


def church(f; $x; $m):
  if $m == 0 then .
  elif $m == 1 then $x|f
  else church(f; $x; $m - 1)
  end;


id(x) = x -> x
zero() = x -> id(x)
add(m) = n -> (f -> (x -> n(f)(m(f)(x))))
mult(m) = n -> (f -> (x -> n(m(f))(x)))
exp(m) = n -> n(m)
succ(i::Int) = i + 1
succ(cn) = f -> (x -> f(cn(f)(x)))
church2int(cn) = cn(succ)(0)
int2church(n) = n < 0 ? throw("negative Church numeral") : (n == 0 ? zero() : succ(int2church(n - 1)))

function runtests()
    church3 = int2church(3)
    church4 = int2church(4)
    println("Church 3 + Church 4 = ", church2int(add(church3)(church4)))
    println("Church 3 * Church 4 = ", church2int(mult(church3)(church4)))
    println("Church 4 ^ Church 3 = ", church2int(exp(church4)(church3)))
    println("Church 3 ^ Church 4 = ", church2int(exp(church3)(church4)))
end

runtests()


{def succ {lambda {:n :f :x} {:f {:n :f :x}}}}
{def add {lambda {:n :m :f :x} {{:n :f} {:m :f :x}}}}
{def mul {lambda {:n :m :f} {:m {:n :f}}}}
{def power {lambda {:n :m} {:m :n}}}

{def church {lambda {:n} {{:n {+ {lambda {:x} {+ :x 1}}}} 0}}}

{def zero  {lambda {:f :x} :x}}
{def three {succ {succ {succ zero}}}}
{def four {succ {succ {succ {succ zero}}}}}

3+4 = {church {add   {three} {four}}} -> 7
3*4 = {church {mul   {three} {four}}} -> 12
3^4 = {church {power {three} {four}}} -> 81
4^3 = {church {power {four} {three}}} -> 64


function churchZero()
  return function(x) return x end
end

function churchSucc(c)
  return function(f)
    return function(x)
      return f(c(f)(x))
    end
  end
end

function churchAdd(c, d)
  return function(f)
    return function(x)
      return c(f)(d(f)(x))
    end
  end
end

function churchMul(c, d)
  return function(f)
      return c(d(f))
  end
end

function churchExp(c, e)
  return e(c)
end

function numToChurch(n)
  local ret = churchZero
  for i = 1, n do
    ret = succ(ret)
  end
  return ret
end

function churchToNum(c)
  return c(function(x) return x + 1 end)(0)
end

three =  churchSucc(churchSucc(churchSucc(churchZero)))
four = churchSucc(churchSucc(churchSucc(churchSucc(churchZero))))

print("'three'\t=", churchToNum(three))
print("'four' \t=", churchToNum(four))
print("'three' * 'four' =", churchToNum(churchMul(three, four)))
print("'three' + 'four' =", churchToNum(churchAdd(three, four)))
print("'three' ^ 'four' =", churchToNum(churchExp(three, four)))
print("'four' ^ 'three' =", churchToNum(churchExp(four, three)))


import macros, sugar
type
  Fn = proc(p: pointer): pointer{.noSideEffect.}
  Church = proc(f: Fn): Fn{.noSideEffect.}
  MetaChurch = proc(c: Church): Church{.noSideEffect.}

#helpers:
template λfλx(exp): untyped = (f: Fn){.closure.}=>((x: pointer){.closure.}=>exp)
template λcλf(exp): untyped = (c: Church){.closure.}=>((f: Fn){.closure.}=>exp)
macro type_erase(body: untyped): untyped =
  let
    name = if body[0].kind == nnkPostFix: body[0][1] else: body[0]
    typ = body[3][0]
  quote do:
    `body`
    proc `name`(p: pointer): pointer =
      template erased: untyped = cast[ptr `typ`](p)[]
      erased = erased.`name`
      p
macro type_erased(body: untyped): untyped =
  let (id1, id2, id3) = (body[0][0][0], body[0][0][1], body[0][1])
  quote do:
    result = `id3`
    result = cast[ptr typeof(`id3`)](
      `id1`(`id2`)(result.addr)
      )[]

#simple math
func zero*(): Church = λfλx: x
func succ*(c: Church): Church = λfλx: f (c f)x
func `+`*(c, d: Church): Church = λfλx: (c f) (d f)x
func `*`*(c, d: Church): Church = λfλx: c(d f)x

#exponentiation
func metazero(): MetaChurch = λcλf: f
func succ(m: MetaChurch): MetaChurch{.type_erase.} = λcλf: c (m c)f
converter toMeta*(c: Church): MetaChurch = type_erased: c(succ)(metazero())
func `^`*(c: Church, d: MetaChurch): Church = d c

#conversions to/from actual numbers
func incr(x: int): int{.type_erase.} = x+1
func toInt(c: Church): int = type_erased: c(incr)(0)
func toChurch*(x: int): Church = return if x <= 0: zero() else: toChurch(x-1).succ
func `$`*(c: Church): string = $c.toInt

when isMainModule:
  let three = zero().succ.succ.succ
  let four = 4.toChurch
  echo [three+four, three*four, three^four, four^three]


(*  Using type as suggested in https://stackoverflow.com/questions/43426709/does-ocamls-type-system-prevent-it-from-modeling-church-numerals
    This is an explicitly polymorphic type : it says that f must be of type ('a -> 'a) -> 'a -> 'a for any possible a "at same time".
*)
type church_num = { f : 'a. ('a -> 'a) -> 'a -> 'a }

(* Zero means apply f 0 times to x, aka return x *)
let ch_zero : church_num = { f = fun _ -> fun x -> x }

(* One simplifies to just returning the function *)
let ch_one : church_num = { f = fun fn -> fn }

(* The next numeral of a church numeral would apply f one more time *)
let ch_succ (c : church_num) : church_num = { f = fun fn x -> fn (c.f fn x) }

(* Adding m and n is applying f m times and then also n times *)
let ch_add  (m : church_num) (n : church_num) : church_num =
    { f = fun fn x -> n.f fn (m.f fn x) }

(* Multiplying is repeated addition : add n, m times *)
let ch_mul  (m : church_num) (n : church_num) : church_num =
    { f = fun fn x -> m.f (n.f fn) x }

(*  Exp is repeated multiplication : multiply by base, exp times.
    However, Church numeral n is in some sense the n'th power of a function f applied to x
    So exp base = apply function base to the exp'th power = base^exp.
*)
let ch_exp (base : church_num) (exp : church_num) : church_num =
    { f = fun fn x -> (exp.f base.f) fn x }

(* extended Church functions: *)

(* test function for church zero *)
let ch_is_zero (c : church_num) : church_num =
    { f = fun fn x -> c.f (fun _ -> fun _ -> fun xi -> xi) (* when argument is not ch_zero *)
                          (fun fi -> fi) (* when argument is ch_zero *) fn x }

(* church predecessor function; reduces function calls by one unless already church zero *)
let ch_pred (c : church_num) : church_num =
    { f = fun fn x -> c.f (fun g h -> h (g fn)) (fun _ -> x) (fun xi -> xi) }

(* church subtraction function; calls predecessor function second argument times on first *)
let ch_sub (m : church_num) (n : church_num) : church_num = n.f ch_pred m

(* church division function; counts number of times divisor can be recursively
   subtracted from dividend *)
let ch_div (dvdnd : church_num) (dvsr : church_num) : church_num =
  let rec divr n = (fun v -> v.f (fun _ -> (ch_succ (divr v)))
                                  ch_zero) (ch_sub n dvsr)
  in divr (ch_succ dvdnd)

(* conversion functions: *)

(* Convert a number to a church_num via recursion *)
let church_of_int (n : int) : church_num =
    if n < 0
    then raise (Invalid_argument (string_of_int n ^ " is not a natural number"))
    else
    (* Tail-recursed helper *)
    let rec helper n acc =
        if n = 0
        then acc
        else helper (n-1) (ch_succ acc)
    in helper n ch_zero

(*  Convert a church_num to an int is rather easy! Just +1 n times. *)
let int_of_church (n : church_num) : int = n.f succ 0

(* Now the tasks at hand: *)

(* Derive Church numerals three, four, eleven, and twelve,
   in terms of Church zero and a Church successor function *)

let ch_three = church_of_int 3
let ch_four = ch_three |> ch_succ
let ch_eleven = church_of_int 11
let ch_twelve = ch_eleven |> ch_succ

(* Use Church numeral arithmetic to obtain the the sum and the product of Church 3 and Church 4 *)
let ch_7 = ch_add ch_three ch_four
let ch_12 = ch_mul ch_three ch_four

(* Similarly obtain 4^3 and 3^4 in terms of Church numerals, using a Church numeral exponentiation function *)
let ch_64 = ch_exp ch_four ch_three
let ch_81 = ch_exp ch_three ch_four

(* check that ch_is_zero works *)
let ch_1 = ch_is_zero ch_zero
let ch_0 = ch_is_zero ch_three

(* check church predecessor, subtraction, and division, functions work *)
let ch_2 = ch_pred ch_three
let ch_8 = ch_sub ch_eleven ch_three
let ch_3 = ch_div ch_eleven ch_three
let ch_4 = ch_div ch_twelve ch_three

(* Convert each result back to an integer, and return it as a string *)
let result = List.map (fun c -> string_of_int(int_of_church c))
                      [ ch_three; ch_four; ch_7; ch_12; ch_64; ch_81;
                        ch_eleven; ch_twelve; ch_1; ch_0; ch_2; ch_8; ch_3; ch_4 ]
             |> String.concat "; " |> Printf.sprintf "[ %s ]"

;;

print_endline result


zero = @(f) @(x) x;
succ = @(n) @(f) @(x) f(n(f)(x));
add = @(m, n) @(f) @(x) m(f)(n(f)(x));
mul = @(m, n) @(f) @(x) m(n(f))(x);
pow = @(b, e) e(b);

% Need a short-circuiting ternary
iif = @(varargin) varargin{3 - varargin{1}}();

% Helper for anonymous recursion
% The branches are thunked to prevent infinite recursion
to_church_ = @(f, i) iif(i == 0, @() zero, @() succ(f(f, i - 1)));
to_church = @(i) to_church_(to_church_, i);

to_int = @(c) c(@(n) n + 1)(0);

three = succ(succ(succ(zero)));
four = succ(succ(succ(succ(zero))));

cellfun(to_int, {
    add(three, four),
    mul(three, four),
    pow(three, four),
    pow(four, three)})


use 5.020;
use feature qw<signatures>;
no warnings qw<experimental::signatures>;

use constant zero  => sub ($f) {
                      sub ($x) { $x }};

use constant succ  => sub ($n) {
                      sub ($f) {
                      sub ($x) { $f->($n->($f)($x)) }}};

use constant add   => sub ($n) {
                      sub ($m) {
                      sub ($f) {
                      sub ($x) { $m->($f)($n->($f)($x)) }}}};

use constant mult  => sub ($n) {
                      sub ($m) {
                      sub ($f) {
                      sub ($x) { $m->($n->($f))($x) }}}};

use constant power => sub ($b) {
                      sub ($e) { $e->($b) }};

use constant countup   => sub ($i) { $i + 1 };
use constant countdown => sub ($i) { $i == 0 ? zero : succ->( __SUB__->($i - 1) ) };
use constant to_int    => sub ($f) { $f->(countup)->(0) };
use constant from_int  => sub ($x) { countdown->($x) };

use constant three => succ->(succ->(succ->(zero)));
use constant four  => from_int->(4);

say join ' ', map { to_int->($_) } (
    add  ->( three )->( four  ),
    mult ->( three )->( four  ),
    power->( four  )->( three ),
    power->( three )->( four  ),
);


with javascript_semantics

type church(object c)
-- eg {r_add,1,{a,b}}
    return sequence(c) and length(c)=3
       and integer(c[1]) and integer(c[2])
       and sequence(c[3]) and length(c[3])=2
end type

function succ(church c)
-- eg {r_add,1,{a,b}} => {r_add,2,{a,b}}  aka  a+b -> a+b+b
    c = deep_copy(c)
    c[2] += 1
    return c
end function

-- three normal integer-handling routines...
function add(integer n, a, b)
    for i=1 to n do
        a += b
    end for
    return a
end function
constant r_add = routine_id("add")

function mul(integer n, a, b)
    for i=1 to n do
        a *= b
    end for
    return a
end function
constant r_mul = routine_id("mul")

function pow(integer n, a, b)
    for i=1 to n do
        a = power(a,b)
    end for
    return a
end function
constant r_pow = routine_id("pow")

-- ...and three church constructors to match
--    (no maths here, just pure static data)
function addch(church c, d)
    church res = {r_add,1,{c,d}}
    return res
end function

function mulch(church c, d)
    church res = {r_mul,1,{c,d}}
    return res
end function

function powch(church c, d)
    church res = {r_pow,1,{c,d}}
    return res
end function

function tointch(church c)
-- note this is where the bulk of any processing happens
    {integer rid, integer n, object x} = c
    x = deep_copy(x)
    for i=1 to length(x) do
        if church(x[i]) then x[i] = tointch(x[i]) end if
    end for
--  return call_func(rid,n&x)
    x = deep_copy({n})&deep_copy(x)
    return call_func(rid,x)
end function

constant church zero = {r_add,0,{0,1}}

function inttoch(integer i)
    if i=0 then
        return zero
    else
        return succ(inttoch(i-1))
    end if
end function

church three = succ(succ(succ(zero))),
       four = succ(three)
printf(1,"three        -> %d\n",tointch(three))
printf(1,"four         -> %d\n",tointch(four))
printf(1,"three + four -> %d\n",tointch(addch(three,four)))
printf(1,"three * four -> %d\n",tointch(mulch(three,four)))
printf(1,"three ^ four -> %d\n",tointch(powch(three,four)))
printf(1,"four ^ three -> %d\n",tointch(powch(four,three)))
printf(1,"5 -> five    -> %d\n",tointch(inttoch(5)))


<?php
$zero = function($f) { return function ($x) { return $x; }; };

$succ = function($n) {
  return function($f) use (&$n) {
    return function($x) use (&$n, &$f) {
      return $f( ($n($f))($x) );
    };
  };
};

$add = function($n, $m) {
  return function($f) use (&$n, &$m) {
    return function($x) use (&$f, &$n, &$m) {
      return ($m($f))(($n($f))($x));
    };
  };
};

$mult = function($n, $m) {
  return function($f) use (&$n, &$m) {
    return function($x) use (&$f, &$n, &$m) {
      return ($m($n($f)))($x);
    };
  };
};

$power = function($b,$e) {
  return $e($b);
};

$to_int = function($f) {
  $count_up = function($i) { return $i+1; };
  return ($f($count_up))(0);
};

$from_int = function($x) {
  $countdown = function($i) use (&$countdown) {
    global $zero, $succ;
    if ( $i == 0 ) {
      return $zero;
    } else {
      return $succ($countdown($i-1));
    };
  };
  return $countdown($x);
};

$three = $succ($succ($succ($zero)));
$four = $from_int(4);
foreach (array($add($three,$four), $mult($three,$four),
	       $power($three,$four), $power($four,$three)) as $ch) {
  print($to_int($ch));
  print("\n");
}
?>


church_zero(z).

church_successor(Z, c(Z)).

church_add(z, Z, Z).
church_add(c(X), Y, c(Z)) :-
    church_add(X, Y, Z).

church_multiply(z, _, z).
church_multiply(c(X), Y, R) :-
    church_add(Y, S, R),
    church_multiply(X, Y, S).

% N ^ M
church_power(z, z, z).
church_power(N, c(z), N).
church_power(N, c(c(Z)), R) :-
    church_multiply(N, R1, R),
    church_power(N, c(Z), R1).

int_church(0, z).
int_church(I, c(Z)) :-
    int_church(Is, Z),
    succ(Is, I).

run :-
    int_church(3, Three),
    church_successor(Three, Four),
    church_add(Three, Four, Sum),
    church_multiply(Three, Four, Product),
    church_power(Four, Three, Power43),
    church_power(Three, Four, Power34),

    int_church(ISum, Sum),
    int_church(IProduct, Product),
    int_church(IPower43, Power43),
    int_church(IPower34, Power34),

    !,
    maplist(format('~w '), [ISum, IProduct, IPower43, IPower34]),
    nl.


'''Church numerals'''

from itertools import repeat
from functools import reduce

# ----- CHURCH ENCODINGS OF NUMERALS AND OPERATIONS ------

def churchZero():
    '''The identity function.
       No applications of any supplied f
       to its argument.
    '''
    return lambda f: identity

def churchSucc(cn):
    '''The successor of a given
       Church numeral. One additional
       application of f. Equivalent to
       the arithmetic addition of one.
    '''
    return lambda f: compose(f)(cn(f))

def churchAdd(m):
    '''The arithmetic sum of two Church numerals.'''
    return lambda n: lambda f: compose(m(f))(n(f))

def churchMult(m):
    '''The arithmetic product of two Church numerals.'''
    return lambda n: compose(m)(n)

def churchExp(m):
    '''Exponentiation of Church numerals. m^n'''
    return lambda n: n(m)

def churchFromInt(n):
    '''The Church numeral equivalent of
       a given integer.
    '''
    return lambda f: (
        foldl
        (compose)
        (identity)
        (replicate(n)(f))
    )

# OR, alternatively:
def churchFromInt_(n):
    '''The Church numeral equivalent of a given
       integer, by explicit recursion.
    '''
    if 0 == n:
        return churchZero()
    else:
        return churchSucc(churchFromInt(n - 1))

def intFromChurch(cn):
    '''The integer equivalent of a
       given Church numeral.
    '''
    return cn(succ)(0)

# ------------------------- TEST -------------------------
# main :: IO ()
def main():
    'Tests'

    cThree = churchFromInt(3)
    cFour = churchFromInt(4)

    print(list(map(intFromChurch, [
        churchAdd(cThree)(cFour),
        churchMult(cThree)(cFour),
        churchExp(cFour)(cThree),
        churchExp(cThree)(cFour),
    ])))

# ------------------ GENERIC FUNCTIONS -------------------

# compose (flip (.)) :: (a -> b) -> (b -> c) -> a -> c
def compose(f):
    '''A left to right composition of two
       functions f and g'''
    return lambda g: lambda x: g(f(x))

# foldl :: (a -> b -> a) -> a -> [b] -> a
def foldl(f):
    '''Left to right reduction of a list,
       using the binary operator f, and
       starting with an initial value a.
    '''
    def go(acc, xs):
        return reduce(lambda a, x: f(a)(x), xs, acc)
    return lambda acc: lambda xs: go(acc, xs)

# identity :: a -> a
def identity(x):
    '''The identity function.'''
    return x

# replicate :: Int -> a -> [a]
def replicate(n):
    '''A list of length n in which every
       element has the value x.
    '''
    return lambda x: repeat(x, n)

# succ :: Enum a => a -> a
def succ(x):
    '''The successor of a value.
       For numeric types, (1 +).
    '''
    return 1 + x if isinstance(x, int) else (
        chr(1 + ord(x))
    )

if __name__ == '__main__':
    main()


  [ this nested ]           is zero  (       --> cn )

  [ this nested join ]      is succ  (    cn --> cn )

  [ zero
    [ 2dup = if done
      succ
      rot succ unrot
      recurse ]
    2drop ]                 is add   ( cn cn --> cn )

  [ zero unrot zero
    [ 2dup = if done
      succ
      2swap
      tuck add swap
      2swap recurse ]
    2drop drop ]            is mul   ( cn cn --> cn )

  [ zero succ unrot zero
    [ 2dup = if done
      succ
      2swap
      tuck mul swap
      2swap recurse ]
    2drop drop ]            is exp   ( cn cn --> cn )

  [ zero swap times succ ]  is n->cn (     n --> cn )

  [ size 1 - ]              is cn->n (    cn -->  n )

  ( - - - - - - - - - - - - - - - - - - - - - - - - )

  [ zero succ succ succ ]   is three (       --> cn )

  [ three succ ]            is four  (       --> cn )

  four three add cn->n echo sp
  four three mul cn->n echo sp
  four three exp cn->n echo sp
  three four exp cn->n echo


zero <- function(f) {function(x) x}
succ <- function(n) {function(f) {function(x) f(n(f)(x))}}
add <- function(n) {function(m) {function(f) {function(x) m(f)(n(f)(x))}}}
mult <- function(n) {function(m) {function(f) m(n(f))}}
expt <- function(n) {function(m) m(n)}
natToChurch <- function(n) {if(n == 0) zero else succ(natToChurch(n - 1))}
churchToNat <- function(n) {(n(function(x) x + 1))(0)}

three <- natToChurch(3)
four <- natToChurch(4)

churchToNat(add(three)(four))
churchToNat(mult(three)(four))
churchToNat(expt(three)(four))
churchToNat(expt(four)(three))


#lang racket

(define zero (λ (f) (λ (x) x)))
(define zero* (const identity)) ; zero renamed

(define one (λ (f) f))
(define one* identity) ; one renamed

(define succ (λ (n) (λ (f) (λ (x) (f ((n f) x))))))
(define succ* (λ (n) (λ (f) (λ (x) ((n f) (f x)))))) ; different impl

(define add (λ (n) (λ (m) (λ (f) (λ (x) ((m f) ((n f) x)))))))
(define add* (λ (n) (n succ)))

(define succ** (add one))

(define mult (λ (n) (λ (m) (λ (f) (m (n f))))))
(define mult* (λ (n) (λ (m) ((m (add n)) zero))))

(define expt  (λ (n) (λ (m) (m n))))
(define expt* (λ (n) (λ (m) ((m (mult n)) one))))

(define (nat->church n)
  (cond
    [(zero? n) zero]
    [else (succ (nat->church (sub1 n)))]))

(define (church->nat n) ((n add1) 0))

(define three (nat->church 3))
(define four (nat->church 4))

(church->nat ((add three) four))
(church->nat ((mult three) four))
(church->nat ((expt three) four))
(church->nat ((expt four) three))


constant $zero  = sub (Code $f) {
                  sub (     $x) { $x }}

constant $succ  = sub (Code $n) {
                  sub (Code $f) {
                  sub (     $x) { $f($n($f)($x)) }}}

constant $add   = sub (Code $n) {
                  sub (Code $m) {
                  sub (Code $f) {
                  sub (     $x) { $m($f)($n($f)($x)) }}}}

constant $mult  = sub (Code $n) {
                  sub (Code $m) {
                  sub (Code $f) {
                  sub (     $x) { $m($n($f))($x) }}}}

constant $power = sub (Code $b) {
                  sub (Code $e) { $e($b) }}

sub to_int (Code $f) {
    sub countup (Int $i) { $i + 1 }
    return $f(&countup).(0)
}

sub from_int (Int $x) {
    multi sub countdown (     0) { $zero }
    multi sub countdown (Int $i) { $succ( countdown($i - 1) ) }
    return countdown($x);
}

constant $three = $succ($succ($succ($zero)));
constant $four  = from_int(4);

say map &to_int,
    $add(   $three )( $four  ),
    $mult(  $three )( $four  ),
    $power( $four  )( $three ),
    $power( $three )( $four  ),
;


def zero(f)
  return lambda {|x| x}
end
Zero = lambda { |f| zero(f) }

def succ(n)
  return lambda { |f| lambda { |x| f.(n.(f).(x)) } }
end

Three = succ(succ(succ(Zero)))

def add(n, m)
  return lambda { |f| lambda { |x| m.(f).(n.(f).(x)) } }
end

def mult(n, m)
  return lambda { |f| lambda { |x| m.(n.(f)).(x) } }
end

def power(b, e)
  return e.(b)
end

def int_from_couch(f)
  countup = lambda { |i| i+1 }
  f.(countup).(0)
end

def couch_from_int(x)
  countdown = lambda { |i|
    case i
      when 0 then Zero
      else succ(countdown.(i-1))
    end
  }
  countdown.(x)
end

Four  = couch_from_int(4)

puts [ add(Three, Four),
       mult(Three, Four),
       power(Three, Four),
       power(Four, Three) ].map {|f| int_from_couch(f) }


use std::rc::Rc;
use std::ops::{Add, Mul};

#[derive(Clone)]
struct Church<'a, T: 'a> {
    runner: Rc<dyn Fn(Rc<dyn Fn(T) -> T + 'a>) -> Rc<dyn Fn(T) -> T + 'a> + 'a>,
}

impl<'a, T> Church<'a, T> {
    fn zero() -> Self {
        Church {
            runner: Rc::new(|_f| {
                Rc::new(|x| x)
            })
        }
    }

    fn succ(self) -> Self {
        Church {
            runner: Rc::new(move |f| {
                let g = self.runner.clone();
                Rc::new(move |x| f(g(f.clone())(x)))
            })
        }
    }

    fn run(&self, f: impl Fn(T) -> T + 'a) -> Rc<dyn Fn(T) -> T + 'a> {
        (self.runner)(Rc::new(f))
    }

    fn exp(self, rhs: Church<'a, Rc<dyn Fn(T) -> T + 'a>>) -> Self
    {
        Church {
            runner: (rhs.runner)(self.runner)
        }
    }
}

impl<'a, T> Add for Church<'a, T> {
    type Output = Church<'a, T>;

    fn add(self, rhs: Church<'a, T>) -> Church<T> {
        Church {
            runner: Rc::new(move |f| {
                let self_runner = self.runner.clone();
                let rhs_runner = rhs.runner.clone();
                Rc::new(move |x| (self_runner)(f.clone())((rhs_runner)(f.clone())(x)))
            })
        }
    }
}

impl<'a, T> Mul for Church<'a, T> {
    type Output = Church<'a, T>;

    fn mul(self, rhs: Church<'a, T>) -> Church<T> {
        Church {
            runner: Rc::new(move |f| {
                (self.runner)((rhs.runner)(f))
            })
        }
    }
}

impl<'a, T> From<i32> for Church<'a, T> {
    fn from(n: i32) -> Church<'a, T> {
        let mut ret = Church::zero();
        for _ in 0..n {
            ret = ret.succ();
        }
        ret
    }
}

impl<'a> From<&Church<'a, i32>> for i32  {
    fn from(c: &Church<'a, i32>) -> i32 {
        c.run(|x| x + 1)(0)
    }
}

fn three<'a, T>() -> Church<'a, T> {
    Church::zero().succ().succ().succ()
}

fn four<'a, T>() -> Church<'a, T> {
    Church::zero().succ().succ().succ().succ()
}

fn main() {
    println!("three =\t{}", i32::from(&three()));
    println!("four =\t{}", i32::from(&four()));

    println!("three + four =\t{}", i32::from(&(three() + four())));
    println!("three * four =\t{}", i32::from(&(three() * four())));

    println!("three ^ four =\t{}", i32::from(&(three().exp(four()))));
    println!("four ^ three =\t{}", i32::from(&(four().exp(three()))));
}


val demo = fn () =>
let
 open IntInf

 val zero        =  fn f       =>  fn x => x ;
 fun succ  n     =  fn f       =>  f o (n f)  ;                                                   (* successor *)
 val rec church  =  fn 0       =>  zero
                       | n     =>  succ ( church (n-1) ) ;                                        (* natural to church numeral *)
 val natural     =  fn churchn =>  churchn  (fn x => x+1) (fromInt 0) ;                           (* church numeral to natural *)

 val mult        =  fn cn    =>  fn cm   =>  cn o cm  ;
 val add         =  fn cn    =>  fn cm   =>  fn f => (cn f) o (cm  f) ;
 val exp         =  fn cn    =>  fn em   =>  em cn;

 in

   List.app    (fn i=>print( (toString i)^"\n" ))     ( List.map natural
       [ add (church 3) (church 4)  , mult (church 3) (church 4) , exp (church 4) (church 3) , exp (church 3) (church 4) ]  )

end;


func succ<A, B, C>(_ n: @escaping (@escaping (A) -> B) -> (C) -> A) -> (@escaping (A) -> B) -> (C) -> B {
  return {f in
    return {x in
      return f(n(f)(x))
    }
  }
}

func zero<A, B>(_ a: A) -> (B) -> B {
  return {b in
    return b
  }
}

func three<A>(_ f: @escaping (A) -> A) -> (A) -> A {
  return {x in
    return succ(succ(succ(zero)))(f)(x)
  }
}

func four<A>(_ f: @escaping (A) -> A) -> (A) -> A {
  return {x in
    return succ(succ(succ(succ(zero))))(f)(x)
  }
}

func add<A, B, C>(_ m: @escaping (B) -> (A) -> C) -> (@escaping (B) -> (C) -> A) -> (B) -> (C) -> C {
  return {n in
    return {f in
      return {x in
        return m(f)(n(f)(x))
      }
    }
  }
}

func mult<A, B, C>(_ m: @escaping (A) -> B) -> (@escaping (C) -> A) -> (C) -> B {
  return {n in
    return {f in
      return m(n(f))
    }
  }
}

func exp<A, B, C>(_ m: A) -> (@escaping (A) -> (B) -> (C) -> C) -> (B) -> (C) -> C {
  return {n in
    return {f in
      return {x in
        return n(m)(f)(x)
      }
    }
  }
}

func church<A>(_ x: Int) -> (@escaping (A) -> A) -> (A) -> A {
  guard x != 0 else { return zero }

  return {f in
    return {a in
      return f(church(x - 1)(f)(a))
    }
  }
}

func unchurch<A>(_ f: (@escaping (Int) -> Int) -> (Int) -> A) -> A {
  return f({i in
    return i + 1
  })(0)
}

let a = unchurch(add(three)(four))
let b = unchurch(mult(three)(four))
// We can even compose operations
let c = unchurch(exp(mult(four)(church(1)))(three))
let d = unchurch(exp(mult(three)(church(1)))(four))

print(a, b, c, d)


processor ChurchZero
  templates apply&{f:}
    $ !
  end apply
end ChurchZero

def zero: $ChurchZero;

processor Successor
  def predecessor: $;
  templates apply&{f:}
    $ -> predecessor::apply&{f: f} -> f !
  end apply
end Successor

templates churchFromInt
  @: $zero;
  $ -> #
  when <=0> do [email protected]!
  when <1..> do @: [email protected] -> Successor; $-1 -> #
end churchFromInt

templates intFromChurch
  templates add1
    $ + 1 !
  end add1
  def church: $;
  0 -> church::apply&{f: add1} !
end intFromChurch

def three: $zero -> Successor -> Successor -> Successor;
def four: 4 -> churchFromInt;

processor Add&{to:}
  def add: $;
  templates apply&{f:}
    $ -> add::apply&{f: f} -> to::apply&{f: f} !
  end apply
end Add

$three -> Add&{to: $four} -> intFromChurch -> '$;
' -> !OUT::write

processor Multiply&{by:}
  def multiply: $;
  templates apply&{f:}
    $ -> multiply::apply&{f: by::apply&{f: f}} !
  end apply
end Multiply

$three -> Multiply&{by: $four} -> intFromChurch -> '$;
' -> !OUT::write

processor Power&{exp:}
  def base: $;
  templates apply&{f:}
    processor Wrap&{f:}
      templates function
        $ -> f !
      end function
    end Wrap
    templates compose
      def p:$;
      $Wrap&{f: base::apply&{f: p::function}} !
    end compose
    def pow: $Wrap&{f: f} -> exp::apply&{f: compose};
    $ -> pow::function !
  end apply
end Power

$three -> Power&{exp: $four} -> intFromChurch -> '$;
' -> !OUT::write

$four -> Power&{exp: $three} -> intFromChurch -> '$;
' -> !OUT::write


class Church {
    static zero { Fn.new { Fn.new { |x| x } } }

    static succ(c) { Fn.new { |f| Fn.new { |x| f.call(c.call(f).call(x)) } } }

    static add(c, d) { Fn.new { |f| Fn.new { |x| c.call(f).call(d.call(f).call(x)) } } }

    static mul(c, d) { Fn.new { |f| c.call(d.call(f)) } }

    static pow(c, e) { e.call(c) }

    static fromInt(n) {
        var ret = zero
        if (n > 0) for (i in 1..n) ret = succ(ret)
        return ret
    }

    static toInt(c) { c.call(Fn.new { |x| x + 1 }).call(0) }
}

var three = Church.succ(Church.succ(Church.succ(Church.zero)))
var four = Church.succ(three)

System.print("three         -> %(Church.toInt(three))")
System.print("four          -> %(Church.toInt(four))")
System.print("three + four  -> %(Church.toInt(Church.add(three, four)))")
System.print("three * four  -> %(Church.toInt(Church.mul(three, four)))")
System.print("three ^ four  -> %(Church.toInt(Church.pow(three, four)))")
System.print("four  ^ three -> %(Church.toInt(Church.pow(four, three)))")


class Church{  // kinda heavy, just an int + fcn churchAdd(ca,cb) would also work
   fcn init(N){ var n=N; }	// Church Zero is Church(0)
   fcn toInt(f,x){ do(n){ x=f(x) } x } // c(3)(f,x) --> f(f(f(x)))
   fcn succ{ self(n+1) }
   fcn __opAdd(c){ self(n+c.n)      }
   fcn __opMul(c){ self(n*c.n)      }
   fcn pow(c)    { self(n.pow(c.n)) }
   fcn toString{ String("Church(",n,")") }
}


F chowla(n)
   V sum = 0
   V i = 2
   L i * i <= n
      I n % i == 0
         sum += i
         V j = n I/ i
         I i != j
            sum += j
      i++
   R sum

L(n) 1..37
   print(‘chowla(’n‘) = ’chowla(n))

V count = 0
V power = 100
L(n) 2..10'000'000
   I chowla(n) == 0
      count++
   I n % power == 0
      print(‘There are ’count‘ primes < ’power)
      power *= 10

count = 0
V limit = 350'000'000
V k = 2
V kk = 3
L
   V p = k * kk
   I p > limit
      L.break
   I chowla(p) == p - 1
      print(p‘ is a perfect number’)
      count++
   k = kk + 1
   kk += k
print(‘There are ’count‘ perfect numbers < ’limit)


with Ada.Text_IO;

procedure Chowla_Numbers is

   function Chowla (N : Positive) return Natural is
      Sum : Natural  := 0;
      I   : Positive := 2;
      J   : Positive;
   begin
      while I * I <= N loop
         if N mod I = 0 then
            J   := N / I;
            Sum := Sum + I + (if I = J then 0 else J);
            end if;
            I := I + 1;
      end loop;
      return Sum;
   end Chowla;

   procedure Put_37_First is
      use Ada.Text_IO;
   begin
      for A in Positive range 1 .. 37 loop
         Put_Line ("chowla(" & A'Image & ") = " & Chowla (A)'Image);
      end loop;
   end Put_37_First;

   procedure Put_Prime is
      use Ada.Text_IO;
      Count : Natural  := 0;
      Power : Positive := 100;
   begin
      for N in Positive range 2 .. 10_000_000 loop
         if Chowla (N) = 0 then
            Count := Count + 1;
         end if;
         if N mod Power = 0 then
            Put_Line ("There is " & Count'Image & " primes < " & Power'Image);
            Power := Power * 10;
         end if;
      end loop;
   end Put_Prime;

   procedure Put_Perfect is
      use Ada.Text_IO;
      Count : Natural  := 0;
      Limit : constant := 350_000_000;
      K     : Natural := 2;
      Kk    : Natural := 3;
      P     : Natural;
   begin
      loop
         P := K * Kk;
         exit when P > Limit;

         if Chowla (P) = P - 1 then
            Put_Line (P'Image & " is a perfect number");
            Count := Count + 1;
         end if;
         K  := Kk + 1;
         Kk := Kk + K;
      end loop;
      Put_Line ("There are " & Count'Image & " perfect numbers < " & Limit'Image);
   end Put_Perfect;

begin
   Put_37_First;
   Put_Prime;
   Put_Perfect;
end Chowla_Numbers;