Author Topic: Combinator Calculator: The purest math you'll ever see  (Read 3894 times)

0 Members and 1 Guest are viewing this topic.

Offline STxAxTIC

  • Library Staff
  • Forum Resident
  • Posts: 1091
  • he lives
    • View Profile
Combinator Calculator: The purest math you'll ever see
« on: January 09, 2022, 11:55:17 pm »
Alright, this post will mostly appeal to the theory-heads out there, but maybe there's some unforseen value in making a general-audience post about this, so here we go.

Today the Science Department of QB64 brings your attention to the oldest, most powerful model of computing ever conceived. Before Turing machines, before lambda calculus - in December 1920, the world was alerted to the S and K combinators. These are abstract functions that you can implement very easily on a computer or another device to make that device become a computer. Here are the functions:

Code: [Select]
s[x][y][z] = x[z][y[z]]
k[x][y] = x

... and that's it. The entirety of computing is in those two functions. All data, all algorithms. Everything you've ever written or will write, whether it be code or it be mathematics, can be compiled to/from those S and K combinators as such. One paper I came across said something like "S and K combinators are the machine language of mathematics". I totally jive with this statement. I got so into this actually, that I had to implement this language in QB64. I'll 'splain you it all.

But first, quiz time. You fall into one of three categories right now:

1)
If you're lost or mostly uninterested, forget about whatever you just read and check out the calculator I made. It does plus, times, and exponents, but only on the integers. Code at the bottom!

2)
If you want to know what's going on so far, and want to hear it *from me*, then I wrote all about this (in Notepad with no spell check and in a hurry, and I still need to add images):
http://barnes.x10host.com/pages/Function-Officium/Function-Officium-One.php
http://barnes.x10host.com/pages/Function-Officium/Function-Officium-Two.php

3)
If you want it straight from the horse's mouth, I suggest you start with this:
https://people.cs.uchicago.edu/~odonnell/Teacher/Lectures/Formal_Organization_of_Knowledge/Examples/combinator_calculus/
https://writings.stephenwolfram.com/2020/12/combinators-a-centennial-view/

To play with this, have it crank out some math for you. You can thumb through the examples in the code I commented out - they will make more sense if read alongside my online notes.

Code: QB64: [Select]
  1.  
  2.  
  3.     _KEYCLEAR
  4.     INPUT "Enter first integer: ", a
  5.     INPUT "Enter second integer: ", b
  6.     c = -1
  7.     DO WHILE ((c < 1) OR (c > 3))
  8.         INPUT "Enter operation. 1 for add, 2 for multiply, 3 for exponent: ", c
  9.     LOOP
  10.     PRINT
  11.  
  12.     SELECT CASE c
  13.         CASE 1
  14.             d = "+"
  15.             e = "s[k[s]][s[k[s[k[s]]]][s[k[k]]]]"
  16.         CASE 2
  17.             d = "*"
  18.             e = "s[k[s]][k]"
  19.         CASE 3
  20.             d = "^"
  21.             e = "s[k[s[s[k][k]]]][k]"
  22.     END SELECT
  23.  
  24.     PRINT "You entered:"
  25.     PRINT a; d; b
  26.     PRINT
  27.     PRINT "Translation of problem: "
  28.     PRINT NumberPrefix$(a); e; NumberPrefix$(b)
  29.     PRINT
  30.     PRINT "Press any key to compute..."
  31.     SLEEP
  32.  
  33.     SELECT CASE c
  34.         CASE 1
  35.             PRINT InterpretInteger&(EvalLoop$(SumPrefix$(a, b) + "[s][k]"))
  36.             PRINT "Result:"; a; d; b; "="; a + b
  37.         CASE 2
  38.             PRINT InterpretInteger&(EvalLoop$(ProductPrefix$(a, b) + "[s][k]"))
  39.             PRINT "Result:"; a; d; b; "="; a * b
  40.         CASE 3
  41.             PRINT InterpretInteger&(EvalLoop$(ExponentPrefix$(a, b) + "[s][k]"))
  42.             PRINT "Result:"; a; d; b; "="; a ^ b
  43.     END SELECT
  44.     PRINT
  45.  
  46.  
  47. '' Identity
  48. 'PRINT EvalLoop$("s[k][k]" + "[a]")
  49.  
  50. '' Wolfram's example
  51. 'PRINT EvalLoop$("s[s[k[s]][s[k[k]][s[k[s]][k]]]][s[k[s[s[k][k]]]][k]]")
  52. 'PRINT EvalLoop$("s[s[k[s]][s[k[k]][s[k[s]][k]]]][s[k[s[s[k][k]]]][k]][a][b][c]")
  53.  
  54. '' Zero
  55. 'PRINT EvalLoop$("s[k]" + "[s][k]")
  56. 'PRINT EvalLoop$(NumberPrefix$(0) + "[s][k]")
  57.  
  58. '' One
  59. 'PRINT EvalLoop$("s[s[k[s]][k]][s[k]]" + "[s][k]")
  60. 'PRINT EvalLoop$("s[s[k[s]][k]]" + "[s[k]][s][k]")
  61. 'PRINT EvalLoop$(NumberPrefix$(1) + "[s][k]")
  62.  
  63. '' Two
  64. 'PRINT EvalLoop$("s[s[k[s]][k]][s[s[k[s]][k]][s[k]]]" + "[s][k]")
  65. 'PRINT EvalLoop$("s[s[k[s]][k]]" + "[" + "s[s[k[s]][k]]" + "[s[k]]][s][k]")
  66. 'PRINT EvalLoop$(NumberPrefix$(2) + "[s][k]")
  67.  
  68. '' Three
  69. 'PRINT EvalLoop$("s[s[k[s]][k]][s[s[k[s]][k]][s[s[k[s]][k]][s[k]]]]" + "[s][k]")
  70. 'PRINT EvalLoop$("s[s[k[s]][k]]" + "[" + "s[s[k[s]][k]]" + "[" + "s[s[k[s]][k]]" + "[s[k]]]][s][k]")
  71. 'PRINT EvalLoop$(NumberPrefix$(3) + "[s][k]")
  72.  
  73. '' Sum
  74. 'PRINT EvalLoop$("s[k[s]][s[k[s[k[s]]]][s[k[k]]]][s[s[k[s]][k]][s[k]]][s[s[k[s]][k]][s[s[k[s]][k]][s[k]]]][s][k]")
  75. 'PRINT EvalLoop$(SumPrefix$(1, 2) + "[s][k]")
  76. 'PRINT EvalLoop$(SumPrefix$(3, 4) + "[s][k]")
  77. 'PRINT EvalLoop$(SumPrefix$(30, 40) + "[s][k]")
  78.  
  79. '' Product
  80. 'PRINT EvalLoop$("s[k[s]][k][s[s[k[s]][k]][s[s[k[s]][k]][s[k]]]][s[s[k[s]][k]][s[s[k[s]][k]][s[k]]]][s][k]")
  81. 'PRINT EvalLoop$(ProductPrefix$(2, 2) + "[s][k]")
  82. 'PRINT EvalLoop$(ProductPrefix$(3, 2) + "[s][k]")
  83. 'PRINT EvalLoop$(ProductPrefix$(2, 3) + "[s][k]")
  84.  
  85. '' Exponent
  86. 'PRINT EvalLoop$(ExponentPrefix$(3, 2) + "[s][k]")
  87.  
  88. '' Self-apply: siix
  89. 'PRINT EvalLoop$("s[s[k][k]][s[k][k]][x]")
  90.  
  91. '' Infinite loop: sii(sii)
  92. 'PRINT EvalLoop$("s[s[k][k]][s[k][k]][s[s[k][k]][s[k][k]]]")
  93.  
  94. '' Swap: s(k(si))(s(kk)i)ab
  95. 'PRINT EvalLoop$("s[k[s[s[k][k]]]][s[k[k]][s[k][k]]][a][b]")
  96.  
  97. '' Self-reference 1:
  98. 'PRINT EvalLoop$("s[k[x]][s[s[k][k]][s[k][k]]][y]")
  99.  
  100. '' Self-reference 2: (infinite loop)
  101. 'PRINT EvalLoop$("s[k[x]][s[s[k][k]][s[k][k]]][s[k[x]][s[s[k][k]][s[k][k]]]]")
  102.  
  103.  
  104. ' Human helper fucntion(s)
  105.  
  106. FUNCTION InterpretInteger& (t AS STRING)
  107.     DIM TheReturn AS LONG
  108.     DIM j AS INTEGER
  109.     DIM w AS STRING
  110.     TheReturn = 0
  111.     w = t
  112.     j = INSTR(w, "s")
  113.     DO WHILE (j <> 0)
  114.         TheReturn = TheReturn + 1
  115.         w = RIGHT$(w, LEN(w) - j - 1)
  116.         j = INSTR(w, "s")
  117.     LOOP
  118.     InterpretInteger& = TheReturn
  119.  
  120. ' Math functions
  121.  
  122. FUNCTION ExponentPrefix$ (a AS INTEGER, b AS INTEGER)
  123.     ExponentPrefix$ = "s[k[s[s[k][k]]]][k]" + "[" + NumberPrefix$(a) + "]" + "[" + NumberPrefix$(b) + "]"
  124.  
  125. FUNCTION ProductPrefix$ (a AS INTEGER, b AS INTEGER)
  126.     ProductPrefix$ = "s[k[s]][k]" + "[" + NumberPrefix$(a) + "]" + "[" + NumberPrefix$(b) + "]"
  127.  
  128. FUNCTION SumPrefix$ (a AS INTEGER, b AS INTEGER)
  129.     SumPrefix$ = "s[k[s]][s[k[s[k[s]]]][s[k[k]]]]" + "[" + NumberPrefix$(a) + "]" + "[" + NumberPrefix$(b) + "]"
  130.  
  131. FUNCTION NumberPrefix$ (n AS LONG)
  132.     NumberPrefix$ = Nest$("s[s[k[s]][k]]", "s[k]", n)
  133.  
  134. ' Higher-order functions
  135.  
  136. FUNCTION Nest$ (f AS STRING, x AS STRING, n AS LONG)
  137.     DIM TheReturn AS STRING
  138.     DIM AS LONG j
  139.     TheReturn = x
  140.     IF (n > 0) THEN
  141.         FOR j = 1 TO n
  142.             TheReturn = f + "[" + TheReturn + "]"
  143.         NEXT
  144.     END IF
  145.     Nest$ = TheReturn
  146.  
  147. ' Eval functions
  148.  
  149. FUNCTION EvalLoop$ (TheStringIn AS STRING)
  150.     DIM TheReturn AS STRING
  151.     DIM Tmp AS STRING
  152.     DIM k AS INTEGER
  153.     Tmp = TheStringIn
  154.     TheReturn = TheStringIn
  155.     PRINT TheReturn
  156.     k = 0
  157.     DO
  158.         Tmp = EvalStep$(TheReturn)
  159.         IF (Tmp <> TheReturn) THEN
  160.             k = k + 1
  161.             TheReturn = Tmp
  162.             PRINT "Step "; _TRIM$(STR$(k)); ": "; TheReturn
  163.         ELSE
  164.             EXIT DO
  165.         END IF
  166.         '_DELAY .025
  167.     LOOP
  168.     EvalLoop$ = TheReturn
  169.  
  170. FUNCTION EvalStep$ (TheStringIn AS STRING)
  171.     DIM TheReturn AS STRING
  172.     DIM AS STRING ArgListS(3)
  173.     DIM AS STRING ArgListK(2)
  174.     DIM AS LONG s0, k0
  175.     DIM AS STRING t1, t2
  176.     TheReturn = TheStringIn
  177.     s0 = FindValidS(TheStringIn, ArgListS())
  178.     k0 = FindValidK(TheStringIn, ArgListK())
  179.     IF (s0 < k0) THEN
  180.         t1 = "s" + ArgListS(1) + ArgListS(2) + ArgListS(3)
  181.         t2 = Shave$(ArgListS(1)) + "[" + Shave$(ArgListS(3)) + "][" + Shave$(ArgListS(2)) + "[" + Shave$(ArgListS(3)) + "]]"
  182.         TheReturn = Replace$(TheStringIn, t1, t2)
  183.     END IF
  184.     IF (k0 < s0) THEN
  185.         t1 = "k" + ArgListK(1) + ArgListK(2)
  186.         t2 = Shave$(ArgListK(1))
  187.         TheReturn = Replace$(TheStringIn, t1, t2)
  188.     END IF
  189.     EvalStep$ = TheReturn
  190.  
  191. ' Parsing functions
  192.  
  193. FUNCTION Shave$ (TheStringIn AS STRING)
  194.     DIM TheReturn AS STRING
  195.     TheReturn = TheStringIn
  196.     TheReturn = LEFT$(TheReturn, LEN(TheReturn) - 1)
  197.     TheReturn = RIGHT$(TheReturn, LEN(TheReturn) - 1)
  198.     Shave$ = TheReturn
  199.  
  200. FUNCTION Replace$ (TheStringIn AS STRING, TargetSegment AS STRING, NewSegment AS STRING)
  201.     DIM TheReturn AS STRING
  202.     DIM k AS INTEGER
  203.     k = INSTR(TheStringIn, TargetSegment)
  204.     IF (k <> 0) THEN
  205.         TheReturn = LEFT$(TheStringIn, k - 1) + NewSegment + RIGHT$(TheStringIn, LEN(TheStringIn) - k - LEN(TargetSegment) + 1)
  206.     ELSE
  207.         TheReturn = TheStringIn
  208.     END IF
  209.     Replace$ = TheReturn
  210.  
  211. SUB FindArgs (TheStringIn AS STRING, StartPos AS LONG, NumArgs AS LONG, arr() AS STRING)
  212.     DIM TheString AS STRING
  213.     DIM AS LONG i, j0, j1, j2, bal
  214.     TheString = TheStringIn
  215.     j0 = 0
  216.     j1 = 0
  217.     j2 = 0
  218.     bal = 0
  219.     i = StartPos
  220.     DO WHILE (i <= LEN(TheString))
  221.         i = i + 1
  222.         IF (MID$(TheString, i, 1) = "[") THEN
  223.             bal = bal + 1
  224.             IF (bal = 1) THEN j1 = i
  225.         END IF
  226.         IF (MID$(TheString, i, 1) = "]") THEN
  227.             bal = bal - 1
  228.             IF (bal = 0) THEN j2 = i
  229.         END IF
  230.         IF ((j1 <> 0) AND (j2 <> 0) AND (bal = 0)) THEN
  231.             j0 = j0 + 1
  232.             arr(j0) = MID$(TheString, j1, j2 - j1 + 1)
  233.             j1 = 0
  234.             j2 = 0
  235.             bal = 0
  236.             IF (j0 = NumArgs) THEN EXIT DO
  237.         END IF
  238.     LOOP
  239.  
  240. FUNCTION FindValidS& (TheStringIn AS STRING, arr() AS STRING)
  241.     DIM TheReturn AS LONG
  242.     DIM Tmp AS STRING
  243.     DIM AS LONG j, n
  244.     TheReturn = 2147483647
  245.     Tmp = TheStringIn
  246.     FOR j = 1 TO UBOUND(arr)
  247.         arr(j) = ""
  248.     NEXT
  249.     n = 0
  250.     DO
  251.         j = INSTR(Tmp, "s")
  252.         IF (j > 0) THEN
  253.             CALL FindArgs(Tmp, j, 3, arr())
  254.             IF ((arr(1) <> "") AND (arr(2) <> "") AND (arr(3) <> "")) THEN
  255.                 TheReturn = j + n
  256.                 EXIT DO
  257.             ELSE
  258.                 Tmp = RIGHT$(Tmp, LEN(Tmp) - j)
  259.                 n = LEN(TheStringIn) - LEN(Tmp)
  260.             END IF
  261.         ELSE
  262.             EXIT DO
  263.         END IF
  264.     LOOP
  265.     FindValidS& = TheReturn
  266.  
  267. FUNCTION FindValidK& (TheStringIn AS STRING, arr() AS STRING)
  268.     DIM TheReturn AS LONG
  269.     DIM Tmp AS STRING
  270.     DIM AS LONG j, n
  271.     TheReturn = 2147483647
  272.     Tmp = TheStringIn
  273.     FOR j = 1 TO UBOUND(arr)
  274.         arr(j) = ""
  275.     NEXT
  276.     n = 0
  277.     DO
  278.         j = INSTR(Tmp, "k")
  279.         IF (j > 0) THEN
  280.             CALL FindArgs(Tmp, j, 2, arr())
  281.             IF ((arr(1) <> "") AND (arr(2) <> "")) THEN
  282.                 TheReturn = j + n
  283.                 EXIT DO
  284.             ELSE
  285.                 Tmp = RIGHT$(Tmp, LEN(Tmp) - j)
  286.                 n = LEN(TheStringIn) - LEN(Tmp)
  287.             END IF
  288.         ELSE
  289.             EXIT DO
  290.         END IF
  291.     LOOP
  292.     FindValidK& = TheReturn

EDIT:

Here is a screenshot of calculating 4^4. It took almost 3000 steps!
 
sssss.png
« Last Edit: January 10, 2022, 08:04:19 am by STxAxTIC »
You're not done when it works, you're done when it's right.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Combinator Calculator: The purest math you'll ever see
« Reply #1 on: January 11, 2022, 01:29:20 pm »
I am book marking this for when I have time to dig into, look really interesting.

Offline QB64Curious

  • Newbie
  • Posts: 22
    • View Profile
Re: Combinator Calculator: The purest math you'll ever see
« Reply #2 on: January 23, 2022, 10:43:17 pm »
Pure Functional programming, in QB. Who wouldda seen this coming, in the 90s?