My initial question is as per below, then I had to cox ChatGPT to get closer to the desired target code. Even then ChatGPT introduced it's on quirky bugs.
None-the-less, it does give a nice insight into how ChatGPT "thinks"... ;-)
Try compiling/running/debugging ChatGPT's code to get an idea of the key issues.


#include <stdio.h>
#include <math.h>
int is_perfect_square(int n) {
int root = (int)sqrt(n);
return root * root == n;
}
int sum_squares() {
int total = 0;
for (int i = 1; ; ++i) { // Infinite loop, will return from inside
total += i * i;
if (is_perfect_square(total) && total != 1) {
return total;
}
}
}
int main() {
int result = sum_squares();
printf("The sum is a perfect square: %d\n", result);
return 0;
}
This C program does the following:
- It includes
<stdio.h>
for input/output operations and<math.h>
for thesqrt
function used in theis_perfect_square
function. - The
is_perfect_square
function checks if a given integern
is a perfect square. - The
sum_squares
function iterates over integers starting from 1, squares each integer, adds it to a total, and checks if the total is a perfect square other than 1. It returns the total when such a condition is met. - The
main
function callssum_squares
to find the sum and prints the result.
Compile this program with a C compiler, such as gcc
, using a command like:
sh

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
// Define a function pointer type for the yield callback
typedef void (*yield_func)(int, void*);
void inf_int(yield_func yield, void *context) {
for (int i = 1; ; ++i) {
yield(i, context);
}
}
void sqr(yield_func yield, void *context, yield_func inf_int_yield) {
void sqr_yield(int value, void *ctx) {
yield(value * value, ctx);
}
inf_int_yield(sqr_yield, context);
}
int is_perfect_square(int n) {
int root = (int)sqrt(n);
return root * root == n;
}
void sum_squares(yield_func yield, yield_func sqr_yield) {
int total = 0;
void sum_yield(int value, void *ctx) {
total += value;
if (is_perfect_square(total) && total != 1) {
*((int*)ctx) = total;
exit(0); // Stop the iteration by exiting the program
}
}
sqr_yield(sum_yield, &total);
}
int main() {
int result = 0;
sum_squares(NULL, sqr);
printf("The sum is a perfect square: %d\n", result);
return 0;
}
This program uses nested functions, a feature supported by GNU C, to implement the yield
functionality. Each generator function (inf_int
, sqr
) takes a function pointer (yield_func
) as an argument, which it calls to "yield" values back to the caller. The sum_squares
function sets up the chain by providing a yield
callback to sqr
, which in turn provides a yield
callback to inf_int
.
A few key points about this implementation:
- It uses nested functions, which are a GNU C extension and not part of standard C. This code will not compile with compilers that do not support GNU extensions.
- The use of
exit(0)
to break out of the infinite loop ininf_int
when the desired condition is met is a simplistic way to stop the iteration. In a real-world scenario, you'd likely want a more graceful method to cease iteration, possibly involving setjmp/longjmp for non-local jumps. - This example serves to demonstrate how one might simulate Python-like generator behavior in C using GNU extensions and should be adapted carefully for use in production environments.
Compile this with a GNU Compiler Collection (GCC) that supports nested functions, using a command like:
sh






PROC is perfect square = (INT n)BOOL: BEGIN REAL root := sqrt(n); INT rounded root := ENTIER(root + 0.5); # Round to nearest integer # rounded root * rounded root = n END; PROC inf int = (PROC(INT)INT yield)INT: BEGIN INT i := 1; INT result := 0; # Label for early loop exit # loop: DO result := yield(i); IF result /= 0 THEN GOTO done FI; i := i + 1 OD; # Label indicating the end of the procedure for a normal exit # done: EXIT result END; PROC sqr = (PROC(INT)INT yield)INT: BEGIN PROC sqr yield = (INT value)INT: yield(value * value); sqr yield END; PROC sum squares = INT: BEGIN INT total := 0; PROC sum yield = (INT value)INT: BEGIN total := total + value; IF is perfect square(total) & total /= 1 THEN total # Return the perfect square sum # ELSE 0 # Signal to continue iteration # FI END; sum yield END; BEGIN INT result := sum squares; print(("The sum is a perfect square: ", result)) END
Key Changes:
- Removed explicit
RETURN
statements, as ALGOL 68 procedures complete with the last expression evaluated or explicitly withEXIT
. - Introduced a
loop:
label and usedGOTO
to exit loops early based on specific conditions, which is a common pattern in ALGOL 68 to control flow within loops and procedures. - Made sure that procedures that need to "return" a value from different points use
EXIT
with the value to be returned following the label that marks the end of the procedure (done:
in the case ofinf int
). - Adjusted
sqr
andsum squares
to ensure they align with ALGOL 68's idiomatic way of handling the last expression as the return value without explicitly usingEXIT
, as their flow is straightforward.
This revised version should now be more in line with ALGOL 68's idioms and practices, especially regarding procedure completion and loop control.
File: sum10.js
Now I do like anchovies and olives on my Neapolitan pizza … most kids don`t… so (to me) the above Javascript code is REALLY yummy, especially “for(i=1; i<=100; i++)…;” and wonderfully loaded with possibilities and flavour… I can almost smell the code a “C” compiler would generate…
On the other hand the Algol68 code is a bit “OD”…
File: sum10.a68
But ignoring the “OD” we still get “FOR i FROM 1 BY 1 TO 100 DO … OD” … Which I find totally vanilla, and deceptively readable… Maybe even boring.
With JS and a junior, I found it really surprising the number of ways a “newbie” can get the “for(i==1, i<100, i+=i)” code wrong… If you dont believe me, find a code fearing 11th-grader and ask them generate the following primary school multiplication triangle:
As a result, I also needed to tutor (and demonstrate) the difference between “curly brackets”, “round brackets” and “square brackets”…. as I said at the top, I like anchovies and olives, part of the fun of discovering a new Neapolitan pizza, but we should not inflict our acquired tastes on juniors.
I finish with a quote by Daniel Klein: “The only thing that separates us from the animals is superstition and mindless rituals.” (also attributed to – Latka Gravas (Andy Kauffman), Taxi)
ps. the “DO ~ OD” blocks I call “Guarded Blocks” inspired by Dijkstra around 1974. cf. https://www.cs.utexas.edu/users/EWD/transcriptions/EWD04xx/EWD472.html