If I think hard, I can sort of remember how I used to do things before I worked almost exclusively in languages that natively support closures ("Let's see... I create a state object, and it copies or retains reference to all the relevant variables... and for convenience I put my function pointer in there too usually... But I still need rules for disposing the state when I'm done with it..." It's so much nicer when the language handles all of that bookkeeping for you and auto-generates those state constructs).
They weren't fully first-class because there were no function-typed variables, nor could you return a function. Even so, this already lets you do stuff like map and filter. And Algol-60 programs from that era did use those capabilities, e.g.:
PROCEDURE EULER (FCT, SUM, EPS, TIM)
VALUE EPS, TIM;
INTEGER TIM;
REAL PROCEDURE FCT;
REAL SUM, EPS;
BEGIN
INTEGER I, K, N, T;
ARRAY M [0 .. 15];
REAL MN, MP, DS;
I := N := T := 0;
M[0] := FCT(0);
SUM := M[0] / 2;
NEXTTERM:
I := I+1;
MN := FCT(1);
FOR K := 0 STEP 1 UNTIL N DO
BEGIN
MP := (MN + M[K]) / 2;
M[K] := MN;
MN := MP
END;
IF (ABS(MN) < ABS(M[N]) AND N < 15) THEN
BEGIN
DS := MN/2;
N := N+1;
M[N] := MN
END
ELSE
DS := MN;
SUM := SUM + DS;
IF ABS(DS) < EPS THEN
T := T + 1
ELSE
T := 0;
IF T < TIM THEN
GOTO NEXTTERM
END;