Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

2026 Participants: Martin Bartelmus * David M. Berry * Alan Blackwell * Gregory Bringman * David Cao * Claire Carroll * Sean Cho Ayres * Hunmin Choi * Jongchan Choi * Lyr Colin * Dan Cox * Christina Cuneo * Orla Delaney * Adrian Demleitner * Pierre Depaz * Mehulkumar Desai * Ranjodh Singh Dhaliwal * Koundinya Dhulipalla * Kevin Driscoll * Iain Emsley * Michael Falk * Leonardo Flores * Jordan Freitas * Aide Violeta Fuentes Barron * Erika Fülöp * Tiffany Fung * Sarah Groff Hennigh-Palermo * Gregor Große-Bölting * Dennis Jerz * Joey Jones * Titaÿna Kauffmann * Haley Kinsler * Todd Millstein * Charu Maithani * Judy Malloy * Eon Meridian * Luis Navarro * Collier Nogues * Stefano Penge * Marta Perez-Campos * Arpita Rathod * Abby Rinaldi * Ari Schlesinger * Carly Schnitzler * Arthur Schwarz * Haerin Shin * Jongbeen Song * Harlin/Hayley Steele * Daniel Temkin * Zach Whalen * Zijian Xia * Waliya Yohanna * Zachary Mann
CCSWG 2026 is coordinated by Lyr Colin-Pacheco (USC), Jeremy Douglass (UCSB), and Mark C. Marino (USC). Sponsored by the Humanities and Critical Code Studies Lab (USC), the Transcriptions Lab (UCSB), and the Digital Arts and Humanities Commons (UCSB).

The First AIs: IPL-V and Simon&Newell's 1950s (!!) Cognitive Models

For almost exactly a year now, since Team ELIZA got the original ELIZA working, and the book became the team's primary focus, I've been working on reanimating the very first AIs, specifically those written in IPL-V (Information Processing Language Five*) in the 1950s at RAND and Carnegie Tech (now CMU). Mark (Marino) suggested that I open a discussion about some of these earliest IPL-V AIs in this CCS session, and I'm looking for either encouragement or discouragement.

The problem is that, although IPL-V is an incredibly important language, being the language in which Simon and Newell implemented the world's first AIs**, it's also a very difficult language, being essentially the assembly language for a Lisp machine (although Lisp itself wasn't invented until a decade later than the earliest IPL work!) I've made a little video introduction to IPL-V:

If you aren't bored by it, or scared by (or scarred by) all this, let me know, either herebelow, or in DM, and I'll consider making the promised next video introducing LT (The Logic Theory machine, aka. The Logic Theorist) and maybe GPS (The General Problem Solver).

Cheers,
'Jeff

ps. Here's a video that I made about 6 months ago that summarizes my progress at that time on reanimating LT:

Since then my efforts have regressed! :-) Why that has happened is a long, perhaps semi-interesting story.)

(* The fifth IPL is the only one that was fully implemented and commonly available. Most of the previous ones were internal to RAND/CIT. There were plans for an IPL-VI, but it was rolled by Lisp, which implements all the same concepts in a much more elegant language.)

(** What Simon and Newell were working on at RAND in IPL-V wasn't primarily AI, but rather cognitive models; their goal was to build computer programs that thought in the same way that humans thought. To the extent that they succeeded at this, they would have incidentally built an AI by definition, but Simon and Newell preferred terms like "complex information processing" or "cognitive simulation" over "artificial intelligence," which was coined by McCarthy for the 1956 Dartmouth conference. This reflected a genuine philosophical difference: McCarthy pursued intelligence by any effective means, while Simon and Newell insisted their programs should mirror actual human cognitive processes.)

Comments

  • Hi, so under the assumption that anyone is willing to actually read IPL-V code, the primary sources are a 1960 paper introducing IPL-V, the Logic Theorist paper, and (for more detail) the IPL-V manual. Here they are, and then I'll provide some commentary:

    http://bitsavers.informatik.uni-stuttgart.de/pdf/rand/ipl/P-1929_An_Introduction_To_Information_Processing_Language_V_Mar60.pdf

    https://www.rand.org/content/dam/rand/pubs/research_memoranda/2009/RM3731.pdf

    https://bitsavers.org/pdf/rand/ipl/Information_Processing_Language-V_Second_Edition_1964.pdf

    So, start by watching my videos above. Then skim the 1960 show IPL-V intro and esp. p2 where simple lists are described, and then p22 where there is a complete IPL-V routine. (In order to understand the routine on p22 you'll need to back up to the couple of previous pages. A lot of this is described in my IPL-V video, so it will really be helpful to watch that first.)

    Then we get to the Logic Theory Machine (usually called the Logic Theorist, or LT). That's the other video. How LT works is described pretty well in the wikipedia page on it:https://en.wikipedia.org/wiki/Logic_Theorist

    What we want to look at is the actual code. That's pp. 123-184 of the Stefferud paper, which you should skim, just for shock value. :-) And you can pick any part of this that you feel like, but I recommend going to p12, which has a flowchart of M1, the executive routine, and then you can see the actual routine on p130. It's only about 26 lines long! (Search for "M001" to find the code easily).

    And...well...we'll see where we go from there!

    Cheers,
    'Jeff

  • edited January 20

    This is fascinating -- and thank you for generously sharing such an in-depth guided tour of this project! Thinking about 1950s cognitive models in IPL-V seems more important today and is perfect for thinking about AI (both contemporary and historical) in Critical Code Studies.

    I understand that you are presenting a historical sequence and stack of materials, but want to make sure I'm correctly oriented to everything as I come fully up to speed. In particular, as a "code critique," we are centering all of this documentation and context around routine M1 of the Logic Theory Machine, am I right?

    • The full code is the Logic Theory Machine, as it appears on pp123-184 of:

      • Stefferud, Einar. "The Logic Theory Machine: a model heuristic program." RAND Corporation, Santa Monica, CA, June 1963. RM-3731-CC. pp123-184. rand.org PDF DTIC AD0453449
    • The recommended starting point or entry point code snippet is the executive routine M1 on p130 -- which is also flowcharted on p12 of the memorandum.

    I really struggled with reading the code for M1 on page 130, in large part because was visually chaotic when I wasn't familiar with the format and don't know where the columns begin-end or what columns were named (the code pages lacks column headers or labels). On top of this, it is in the nature of the encoding of Name, Po, Symb, and Link to all appear intermittently, while Po and Symb are formatted to run together. All this creates an illusion that the data is haphazard or misaligned when it is in fact tightly regimented by character position. Further, if you aren't familiar with the name and symbol system, the capital O and numeral 0 are extremely close unless carefully inspected, making it inclear whether 1W0=PROB M001R020 is 1WO, PR0B, MOO1R020 et cetera. In fact, the embedded OCR in the (password-locked) RAND and DTIC official copies is full of OCR transcription errors throughout, especially on 0s and Os.

    What do to? As an exercise to work through my own understanding I took the "IPL-V Coding Sheet" on page 187, which shows 80-column data where each band of characters corresponds to Comments (6-40), Type (41), Name (43-47), Sign (48), PO (49-50), Symb (51-55), Link (57-61), Comments (63-72), and ID (73-80). Columns 42, 56, and 62 are blank; columns 0-5 appear to be blank, but 0-4 aren't shown in the reproduction. While the original coding sheet is not a pure typescript, I adapted it to an 80-column fixed-width text format and added as a header to a text file transcript of the PDF page 130 code. Here is the result:

                                        IPL-V CODING SHEET
    
    Problem no. ____________ Programmer ____________ Date ________ Page ____ of ____
    --------------------------------------------------------------------------------
                                            T      S                                
                                            y      i                              
                                            p      g                              
    _____Comments...........................e_Name.nPoSymb._Link._Comments..ID......
    --------------------------------------------------------------------------------
    00000000011111111112222222222333333333344444444445555555555666666666677777777778
    12345678901234567890123456789012345678901234567890123456789012345678901234567890
    --------------------------------------------------------------------------------
          PROGRAM HEADER                    5                                   R  -
         M1 SINGLE PRCBLEM EXECUTIVE FOR      M1      M3                    M001R000
            PROBLEM (0). H5 + IF SUCCEEDS.          40W0                    M001R010
                                                    60W0          1W0=PROB  M001R020
         TEST UTILITY.                               M43                    M001R030
              IF NO GOOD, QUIT.                     709-4                   M001R040
                                                    11W0                    M001R050
         PRINT 'TO PROVE' PROBLEM 1W0.                M78                   M001R060
                                                    11W0                    M001R070
         TRY SUBSTITUTION.                            M12                   M001R080
             IF WORKED, PRINT PROOF.                70      9-2             M001R090
                                              9-1   11W0                    M001R100
         CREATE LIST OF METHODS FOR PROB.             M8                    M001R110
                                                    11W0                    M001R120
         APPLY METHODS.                               M7                    M001R130
               IF PROOF FOUND, PRINT IT.            70      9-2             M001R140
         TEST IF ANY LIMITS EXCEEDED.                 M90                   M001R150
         IF YES, QUIT.                              70      9-3             M001R160
         FIND NEXT SUBPROBLEM.                        M90                   M001R170
         IF NONE QUIT.                              70      9-3             M001R180
         IF ONE,                                    60W0                    Mo01R190
         PRINT SUBPROBLEM, TRY METHODS.               M70   9-1             M001R200
         PRINT PROOF FROM (0)•                9-2     M71                   M001R210
         AND QUIT +.                                3OW0    J4              M001R220
         PRINT FAILURE, QUIT -.               9-3     M72   9-5             M001R230
                                              9-4   11W0                    M001R240
         PRINT REJECTED PROBLEM                       M81                   M001R250
         AND QUIT -.                          9-5   3OW0    J3              M001R260
                                            1                                   R
    

    Here is the same data with "|" interjected to make it more legible. This also formats it as a Markdown table:

    |Comments                          |T|Name |S|Po|Symb |Link |Comments  |ID      |
    |----------------------------------|-|-----|-|--|-----|-----|----------|--------|
    | PROGRAM HEADER                   |5|     | |  |     |     |          |    R  -|
    |M1 SINGLE PRCBLEM EXECUTIVE FOR   | |M1   | |  |M3   |     |          |M001R000|
    |   PROBLEM (0). H5 + IF SUCCEEDS. | |     | |40|W0   |     |          |M001R010|
    |                                  | |     | |60|W0   |     |1W0=PROB  |M001R020|
    |TEST UTILITY.                     | |     | | M|43   |     |          |M001R030|
    |     IF NO GOOD, QUIT.            | |     | |70|9-4  |     |          |M001R040|
    |                                  | |     | |11|W0   |     |          |M001R050|
    |PRINT 'TO PROVE' PROBLEM 1W0.     | |     | |  |M78  |     |          |M001R060|
    |                                  | |     | |11|W0   |     |          |M001R070|
    |TRY SUBSTITUTION.                 | |     | |  |M12  |     |          |M001R080|
    |    IF WORKED, PRINT PROOF.       | |     | |70|     |9-2  |          |M001R090|
    |                                  | |9-1  | |11|W0   |     |          |M001R100|
    |CREATE LIST OF METHODS FOR PROB.  | |     | |  |M8   |     |          |M001R110|
    |                                  | |     | |11|W0   |     |          |M001R120|
    |APPLY METHODS.                    | |     | |  |M7   |     |          |M001R130|
    |      IF PROOF FOUND, PRINT IT.   | |     | |70|     |9-2  |          |M001R140|
    |TEST IF ANY LIMITS EXCEEDED.      | |     | |  |M90  |     |          |M001R150|
    |IF YES, QUIT.                     | |     | |70|     |9-3  |          |M001R160|
    |FIND NEXT SUBPROBLEM.             | |     | |  |M90  |     |          |M001R170|
    |IF NONE QUIT.                     | |     | |70|     |9-3  |          |M001R180|
    |IF ONE,                           | |     | |60|W0   |     |          |Mo01R190|
    |PRINT SUBPROBLEM, TRY METHODS.    | |     | |  |M70  |9-1  |          |M001R200|
    |PRINT PROOF FROM (0)•             | |9-2  | |  |M71  |     |          |M001R210|
    |AND QUIT +.                       | |     | |3O|W0   |J4   |          |M001R220|
    |PRINT FAILURE, QUIT -.            | |9-3  | |  |M72  |9-5  |          |M001R230|
    |                                  | |9-4  | |11|W0   |     |          |M001R240|
    |PRINT REJECTED PROBLEM            | |     | |  |M81  |     |          |M001R250|
    |AND QUIT -.                       | |9-5  | |3O|W0   |J3   |          |M001R260|
    |                                  |1|     | |  |     |     |          |    R   |
    

    ...and here is that version is rendered live in Markdown:

    Comments T Name S Po Symb Link Comments ID
    PROGRAM HEADER 5 R -
    M1 SINGLE PRCBLEM EXECUTIVE FOR M1 M3 M001R000
    PROBLEM (0). H5 + IF SUCCEEDS. 40 W0 M001R010
    60 W0 1W0=PROB M001R020
    TEST UTILITY. M 43 M001R030
    IF NO GOOD, QUIT. 70 9-4 M001R040
    11 W0 M001R050
    PRINT 'TO PROVE' PROBLEM 1W0. M78 M001R060
    11 W0 M001R070
    TRY SUBSTITUTION. M12 M001R080
    IF WORKED, PRINT PROOF. 70 9-2 M001R090
    9-1 11 W0 M001R100
    CREATE LIST OF METHODS FOR PROB. M8 M001R110
    11 W0 M001R120
    APPLY METHODS. M7 M001R130
    IF PROOF FOUND, PRINT IT. 70 9-2 M001R140
    TEST IF ANY LIMITS EXCEEDED. M90 M001R150
    IF YES, QUIT. 70 9-3 M001R160
    FIND NEXT SUBPROBLEM. M90 M001R170
    IF NONE QUIT. 70 9-3 M001R180
    IF ONE, 60 W0 Mo01R190
    PRINT SUBPROBLEM, TRY METHODS. M70 9-1 M001R200
    PRINT PROOF FROM (0)• 9-2 M71 M001R210
    AND QUIT +. 3O W0 J4 M001R220
    PRINT FAILURE, QUIT -. 9-3 M72 9-5 M001R230
    9-4 11 W0 M001R240
    PRINT REJECTED PROBLEM M81 M001R250
    AND QUIT -. 9-5 3O W0 J3 M001R260
    1 R
  • edited January 21

    @jeremydouglass Amazing work; Thank you for that! Yes, card column coding is certainly something that we "moderns" aren't used to reading, and esp. assembly language!

    Until you did your work, it hadn't occurred to me that folks might prefer to read a transcription of the code in the paper. We have done that here:

    https://docs.google.com/spreadsheets/d/1ibvbyoIT20R4gDqo2iSkk5mJBWsRrtQ6sr8Fj1nz910

    M1 starts at about line 37. (Note that the two automatically-computed columns off the right of the code explain what the PQ and symbol mean!)

    We did this in part for our reading convenience, but also because we needed to feed the code into the emulator, and, as you point out, OCR'ing it doesn't work. (Rupert Lane, who did the ELIZA reanimation in the 7094->CTSS emulator has a somewhat complex procedure that gets the correct code out of old documents like these, he called "gridlock":

    https://github.com/rupertl/gridlock

    This should probably be widely advertised, at least in this community!

    To your original question about focusing on M1, that's just what I felt was a reasonably important yet at the same time reasonably small and reasonably understandable piece of LT. I'm not fixated on it, and other's might be more interested in reading other parts of the code base. (For which, of course, I recomment using our spreadsheet eventually, but struggling with the same reading problems that led both you and we to make transcriptions has some value, I think, in getting one's head inside what it was like to work with LT in the original.)

    Cheers,
    'Jeff

  • I've been deep inside M62 for several days:



    Which matches logic expressions that are being proved to expressions that could be used to prove them. This is one of the core and most complex routines in LT. It is particular complex because M62 is RECURSIVE (!!)_ You can see on cards R220 and R370 the function CALLS ITSELF! Unlike Lisp, where recursion was built in underneath the language, IPL programs must manage the recursion stack themselves, pushing things on and popping them off correctly. Having to manage the stack oneself is a good bit of what makes IPL such a painful language to code in. However, one get's used to the tropes, as one does with any language.

    The problem I'm having actually seems to be a bug in LT itself, but having worked with the program for a year, now, I'm loathe to jump to the conclusion that LT is wrong -- usually, to date, bugs end up being tracked to a bug in my IPL emulator, or a transcription error, but this appears to be an actual bug in the LT code.

    The culprit is actually the very last (or near very last) return: R660. Note that the PQ|Symbol here is: 31H0. What this means is: Pop the stack of the cell whose symbol name is contained in H0. Recall that H0 is the master communication cell -- it's sort of the working memory for the whole system. (There's actually nothing special about H0 as regards the IPL machine -- it's just that H0 is conventionally used in this way.) Very often H0 is pushed and popped, but an indirect cell pop off of H0 is NOT very common. Moreover, I think it's wrong! At the time this executes, H0 contains the name of the expression we've been working on, in this case, "*12" (which, if you care, is:

    *1.2   ((AVA)IA) 
    

    where "V" mean "OR" and "I" (which unfortunately looks like a vbar) is implication.

    The internal representation of that theorem is this:

    (0) {*12|14|0|9-2354}             <<<<< AAAAA                                                                                                              
    (0) {9-2354||9-2231|9-2250}                                                                                                            
       (1) {9-2231||0|9-2233}                                                                                                              
       (1) {9-2233||Q7|9-2232}                                                                                                             
          (2) {Q007R000::Q7|10|Q7|J10 [ATTRIBUTE--EXTERNAL NAME;]}                                                                         
          (2) "J10"                                                                                                                        
       (1) {9-2232||9-2230|9-2252}                                                                                                         
          (2) {9-2230|22|1.2  |}                                                                                                           
       (1) {9-2252||Q15|9-2251}                                                                                                            
          (2) {Q015R000::Q15|10|Q15|J10 [Q15 ATTRIBUTE INTERNAL FORM.;]}                                                                   
          (2) "J10"                                                                                                                        
       (1) {9-2251||Q15|0}                                                                                                                 
          (2) {Q015R000::Q15|10|Q15|J10 [Q15 ATTRIBUTE INTERNAL FORM.;]}                                                                   
          (2) "J10"                                                                                                                        
    (0) {9-2250||9-2243|0}                                                                                                                 
       (1) {9-2243|02|I0|9-2247}      <<<<< BBBBB (I -- implication)                                                                                                     
          (2) {I000D000::I0||I0-1839|0 [IMPLIES;]}                                                                                         
             (3) {I000D010::I0-1839||0|I0-1840}                                                                                            
             [@4...]                                                                                                                       
             (3) {I000D020::I0-1840||Q14|I0-1841}                                                                                          
             [@4...]                                                                                                                       
             (3) {I000D030::I0-1841||J4|I0-1842}                                                                                           
             [@4...]                                                                                                                       
             (3) {I000D040::I0-1842||Q7|I0-1843}                                                                                           
             [@4...]                                                                                                                       
             (3) {I000D050::I0-1843||I0-1844|0}                                                                                            
             [@4...]                                                                                                                       
       (1) {9-2247||9-2244|9-2248}
          (2) {9-2244|02|V0|9-2245}                                                                                                        
             (3) {V000D000::V0||V0-2029|0 [OR;]}       <<<<< CCCCC (V -- or)                                                                                 
             [@4...]                                                                                                                       
          (2) {9-2245||A0|9-2246}                                                                                                          
             (3) {A000D000::A0||A0-1780|0 [FREE VARIABLE A;]}     <<<<< DDDDD (A)                                                                     
             [@4...]                                                                                                                       
          (2) {9-2246||A0|0}                                                                                                               
             (3) {A000D000::A0||A0-1780|0 [FREE VARIABLE A;]}       <<<<< EEEEE (A)                                                                       
             [@4...]                                                                                                                       
       (1) {9-2248||A0|0}                                                                                                                  
          (2) {A000D000::A0||A0-1780|0 [FREE VARIABLE A;]}   <<<<< FFFFF (A)                                                                            
             (3) {A000D010::A0-1780||0|A0-1781}                                                                                            
             [@4...]                                                                                                                       
             (3) {A000D020::A0-1781||Q5|A0-1782}                                                                                           
             [@4...]                                                                                                                       
             (3) {A000D030::A0-1782||Q5|A0-1783}                                                                                           
             [@4...]                                                                                                                       
             (3) {A000D040::A0-1783||Q6|A0-1784}                                                                                           
             [@4...]                                                                                                                       
             (3) {A000D050::A0-1784||Q6|A0-1785}                                                                                           
             [@4...]                                                                                                                       
             (3) {A000D060::A0-1785||Q7|A0-1786}                                                                                           
             [@4...]                                                                                                                       
             (3) {A000D070::A0-1786||A0-1787|0}                                                                                            
             [@4...]                                                                      
    

    I've added some notes, preceeded by "<<<<<". You can sort of read off the expression in this uber complex internal representation at comments B through F.

    Comment A (<<<<< AAAAA) is actually the problem here. This cell:

         {*12|14|0|9-2354} 
    

    has a PQ=14 and a zero symbol. This is a marker used by IPL programmers to mark the list, in this case, to indicate that the list has been processed. The comment at R630 says: "UNMARK IF MARKED", and most of the subsequent code seems to try to do this, by calling J133 (R640), which is test for this exact sort of mark, and then branching (R650). BUT THEN COMES THE PROBLEM! The way it tried to remove the mark seems to be to execute the errant "31H0" command (R660), which, since H0's symbol is *12, tries to pop *12's stack -- note that this is trying to pop the CELL *12's stack, NOT THE LIST *12. It's the LIST, NOT THE CELL, that has the "processed" marker on it that J133 just checked for. And, indeed, the CELL *12 has no stack at all, so when this 31H0 command is called -- that is, when it tried to pop the non-existant *12 cell's stack, this is the result:

       H0={H0||*12|0|("9-2353" "0" "*EOS")}                                                                                                
       H1={H1||M62-906|0|("exit" "J100" "M62-895" "M62-888" "M62-873" "M12-242" "M1-130" "M2-154" "exit" "J100" "M2-145" "exit" "0" "*EOS"\
    )}                                                                                                                                     
       W0={W0||9-2294|0|("9-2293" "9-2293" "*202" "*202" "0" "*EOS")}                                                                      
       W1={W1||9-2257|0|("L4" "*202" "0" "*EOS")}                                                                                          
       W2={W2||9-2349|0|("9-2348" "0" "0" "*EOS")}                                                                                         
    @2215+ >>>>> {M062R660::M62-907|31|H0|J8} (Pop the stack of the sym in the named cell)                                                 
    
    debugger invoked on a SIMPLE-CONDITION in thread #<THREAD "main thread" RUNNING {1001670003}>: IPOP asked to pop beyond the bottom of the stack of {*12|14|0|9-2354}                       
    

    Yeah, there i no stack in *12 to pop!

    I think what it means to be doing is to call J68, on *12, which is a J function that deletes a cell in a list and closes the list up. That would actually seem to do the right thing, and remove the 14/"0" from *12.

    That is, I will replace:

                31  H0  J8      M062R660
    

    with:

                00  J68 J8      M062R660
    

    I'm sure you're all sitting on the edge of your seats to see whether this works!

  • Jeff -- thanks so much for this update.

    Regarding the manual recursion in IPL, this seems relevant to the conversation in Gregor's thread code critique of the example from Structure and Interpretation of Computer Programs (SICP), Ch. 1.1 about the role of recursion in that textbook, and, as you point out there, how

    "The invention of what some might call a “mere notational convenience” literally revolutionized computation turning an essentially unusable and difficult to implement language (IPL) into an elegant and trivial to implement one.

    My further reponse below is mainly to your previous post. Yes, your spreadsheet is extremely useful -- including the floating annotation of the flowchart near the relevant line on worksheet tab 2! Thank you so much. It is remarkable the labor that can go into thoughtfully transcribing a PDF into something that is once again usefully structured (or thoughtfully semi-automating such transcription). From worksheet to typescript to PDF was a long way for the information to fall.

    I think that sometimes the aids that we create for ourselves in decompiling, porting, or reimplementing code are often just the things to help new readers of that code, because they represent a concerted effort to aid understanding.

    I am not sorry that I went through that full exercise without knowing that you had already encoded it in a spreadsheet -- sometimes you really do learn a lot on the journey. That said, I'm very glad to learn about Rupert Lane's gridlock and enjoyed reading up on the OCR+LLM grid alignment approach. Having created the text file for one page manually so that I understood the process, the next logical step seemed to be to create a parser for the rest of the pages... but that way lies madness when you don't even have an end emulator in mind, so I'm relieved to know that the work is already being done.

  • @jeremydouglass We do lots of work in the normal work-a-day software engineering to to make the invisible visible. There are lots of traces in the IPL-V book, and literally half of my IPL-V emulator is debugging code. Here's a block of what it looks like when it's running with the hood open for just 2 cycles (the whole process takes many thousands of cycles, and I'm only tracing 5 cells here; in theory I could trace every relevant cell, but of course that would be WAY bigger -- I already have debugging tools to read my debugging tool outputs!):

    <== retreiving "X1"@0+ >>>>> {X001R000::X1|11|W26|X1-2179} (Push cntnts of the cell named by symb, onto H0)                            
    -----> At INTERPRET-Q: CELL ={X001R000::X1|11|W26|X1-2179}      Q = 1, symb="W26"                                                      
     @0[RUN-FULL]                                                                                                                          
         -----> At INTERPRET-P w/P = 1, S="W26-2226" @0[RUN-FULL]                                                                          
         -----> At INTERPRET-P w/P = 1, S="W26-2226" @0[S]                                                                                 
    IPUSH wants to push "W26-2226" on H0-----> At ADVANCE @0[RUN-FULL]                                                                     
       H0={H0||W26-2226|0|("0" "*EOS")}                                                                                                    
       H1={H1||X1|0|("exit" "0" "*EOS")}                                                                                                   
       W0={W0||0|0}                                                                                                                        
       W1={W1||0|0}                                                                                                                        
       *12=NIL                                                                                                                             
    -----> At ADVANCE-W/FORCED-LINK (link="X1-2179") @1[RUN-FULL]                                                                          
    ---> At INTERPRET-Q w/H1 = {H1||X1-2179|0|("exit" "0" "*EOS")}! (*fname-hint* = "X1-2179") X1-2179@1[RUN-FULL]                         
    <== retreiving "X1-2179"@1+ >>>>> {X001R010::X1-2179|10|X23|X1-2180} (Push the symb (name) itself on H0)                               
    -----> At INTERPRET-Q: CELL ={X001R010::X1-2179|10|X23|X1-2180}      Q = 0, symb="X23"                                                 
     X1-2179@1[RUN-FULL]                                                                                                                   
         -----> At INTERPRET-P w/P = 1, S="X23" X1-2179@1[RUN-FULL]                                                                        
         -----> At INTERPRET-P w/P = 1, S="X23" X1-2179@1[S]                                                                               
    IPUSH wants to push "X23" on H0-----> At ADVANCE X1-2179@1[RUN-FULL]                                                                   
       H0={H0||X23|0|("W26-2226" "0" "*EOS")}                                                                                              
       H1={H1||X1-2179|0|("exit" "0" "*EOS")}                                                                                              
       W0={W0||0|0}                                                                                                                        
       W1={W1||0|0}                                                                                                                        
       *12=NIL                                                                                                                             
    -----> At ADVANCE-W/FORCED-LINK (link="X1-2180") X1-2179@2[RUN-FULL]                                                                   
    ---> At INTERPRET-Q w/H1 = {H1||X1-2180|0|("exit" "0" "*EOS")}! (*fname-hint* = "X1-2180") X1-2180@2[RUN-FULL]                         
    <== retreiving "X1-2180"@2+ >>>>> {X001R020::X1-2180||J73|X1-2181} (Execute fn named by symb name itself)                              
    -----> At INTERPRET-Q: CELL ={X001R020::X1-2180||J73|X1-2181}      Q = 0, symb="J73"                                                   
     X1-2180@2[RUN-FULL]                                                                                                                   
         -----> At INTERPRET-P w/P = 0, S="J73" X1-2180@2[RUN-FULL]                                                                        
         -----> At INTERPRET-P w/P = 0, S="J73" X1-2180@2[S]                                                                               
    -----> At TEST-FOR-PRIMITIVE w/S = "J73", Q = 0, symb="J73" X1-2180@2[RUN-FULL]                                                        
    -----> At DESCEND w/S = "J73" X1-2180@2[RUN-FULL]                                                                                      
    IPUSH wants to push "J73" on H1   H0={H0||X23|0|("W26-2226" "0" "*EOS")}                                                               
       H1={H1||J73|0|("X1-2180" "exit" "0" "*EOS")}                                                                                        
       W0={W0||0|0}                                                                                                                        
       W1={W1||0|0}                                                             
    
  • edited January 22

    @jeremydouglass On the topic of recursion; It really is just stack and memory management (recursion being only one thing that requires stack management -- and stacks being only one of many things that require memory management). A few points. First, Fortran (the only other leading language at the time) cannot (or at least at that time could not) do recursion, because they had static memory management. Also, as Lisp starting eating IPL's lunch (and breakfast and dinner!) the IPL folks actually tried to jump no the s-expression bandwagon, creating the abortive "Linear IPL":

  • BTW ( @jeremydouglass ) McCarty is also credited with inventing garbage collection, which was another genius invention because it relieved the programmer from doing their own memory management, which on had to do to some extent in IPL (although the language managed the symbol stack memory, which was the most important memory being used for function call stack and thus recursion, and most other memory management was hidden inside J functions, so there wasn't really any need to do a lot of memory management. (I will nod to those who hate GC because it creates unpredictable lags when it kicks in, and at the time, and for highly speed sensitive applications this is partly the case, but these days there's so much memory around that you could just run all day and then kick of a GC "at night" for most applications, and never know it was there.) Anyway, between elegance of representation, elegance of implementation, complete invisibility of memory and stack management, Lisp won ... and once Macros were discovered, it was pretty much over for any other programming language. All the rest are still learning to be more like Lisp.

  • Sorry that I've had too many start-of-term duties to engage with this week's topic, but this thread triggered a fit of nostalgia, since I was first taught programming on punchcards, then spent years in assembly code before my Master's dissertation in LISP. Since then, I've seen many projects on visualisation and annotation of low-level machines. If anyone would like to build on this great work by making an executable visual annotation, I can certainly see some approaches that might be taken, for a diagrammatic mode of critical reading.

  • This week (and the last) I've re-approached my IPL-V emulator in honor of this CCS event. I'd dropped it a couple of time before (August of 2025 and October of 2025) partly because I'd got most of the basic machinery to work, and most of the basic test program to work. But the Logic Theorist, which was my Holy Grail (Blue, BTW, in case you're wondering!) remained stubbornly broken. A big step came a couple of months ago when Rupert Lane created GridLock https://github.com/rupertl/gridlock), which correctly OCRs code out of PDFs. This found some recalcitrant typos in our transcription of LT, and I tried again, and got further, but still fell short. Then, this week I decided to pick it up again, and with some distance, just over the past couple of days, made a massive critical discovery which revolutionized my whole understanding of IPL-V and is going to require a rewrite of the two core functions of my emulator (as well as a rewrite of many of the secondary functionalities that rest on that core!)

    The problem has to do with stacks. As I've mentioned elsewhere (indeed, everywhere!), IPL is basically the assmbly language for an imaginary stack machine which would essentially be the machine that Lisp could run on (had Lisp been invented a decade before is was!) Indeed, IPL-V is basically Lisp with terrible syntax. And, indeed encore, the raison d'etre of Lisp: Lists [which actually isn't the raison d'etre, most like the raison d'nom :-)] is also the core functionality of IPL -- just as everything in Lisp is a list, everything in IPL is a list!

    Now, let's look at that word: "everything". My emulator, alas, did not take to heart this core observation -- the very first line in the very first paragraph of the IPL-V manual by Newell et al.:


    Later, however, the manual calls out storage cells:

    And here is where I went off the rails. I assume that this means that storage cells were special; that they were a special part of the machine, so my my emulator had (has -- although I'm about to rip this out!) special machinery for storage cells. In addition to a symbol table for cells, there was (is -- "") a special table called the system stack:

    (defvar *symtab* (make-hash-table :test #'equal))                                                                                      
    (defvar *systacks* (make-hash-table :test #'equal))  
    

    And mostly everything worked fine....although LT didn't quite work ... and I had no idea why...until CCS brought me back to this, and I wrote up the long post of a few days ago:

    The problem I'm having actually seems to be a bug in LT itself, but having worked with the program for a year, now, I'm loathe to jump to the conclusion that LT is wrong -- usually, to date, bugs end up being tracked to a bug in my IPL emulator, or a transcription error, but this appears to be an actual bug in the LT code.
    
    The culprit is actually the very last (or near very last) return: R660. Note that the PQ|Symbol here is: 31H0. What this means is: Pop the stack of the cell whose symbol name is contained in H0. Recall that H0 is the master communication cell -- it's sort of the working memory for the whole system. (There's actually nothing special about H0 as regards the IPL machine -- it's just that H0 is conventionally used in this way.) Very often H0 is pushed and popped, but an indirect cell pop off of H0 is NOT very common. Moreover, I think it's wrong! 
    

    Note the ominous warning to myself:

    I'm loathe to jump to the conclusion that LT is wrong -- usually, to date, bugs end up being tracked to a bug in my IPL emulator
    

    Well guess what....the last quote above was right, and the one just above was wrong: LT is right, and my emulator is wrong!

    The instructional instruction is the one from the previous post, which I reproduce herebelow:

    31  H0  J8      M062R660
    

    I had hypothesized that this was trying to use the (simulated) hardware of the IPL machine to pop a non-system stack, that is, using PQ=31 to pop the list *12. This shouldn't be doable the way I had understood (and built) the IPL machine where the system stacks were the things manipulated by the machine (PQ=31), and data lists (stacks in the simplest case of a linear list that you push/pop to/from) were handled by J functions, specifically J68.

    BUT I WAS WRONG!

    In fact, the way that storage cells SHOULD HAVE been implemented was exactly to just push/pop to/from simple linear lists! Then applying PQ=3x to EITHER a system (storage) cell, OR a data stack (like *12) would work perfectly well!

    So over the next few days I'm going tear out all my special machinery for storage cells unify the storage cell machinery with the list processing machinery.

    Newell was a fucking genius!

Sign In or Register to comment.