こんな例はどうだろう。

C言語でRobotをコントロールする。

このRobotには、例えばforward(前進),turn(回転)などのコマンドが
使えるとする。

roboMainという配列に、
char *roboMain[] = { "turn 45", "forward 10", ...};
のように書いておくと、Robotがこれを読み取って実行するものとする。
Cの世界では全く副作用は起きていない。

しかし、これだとRobotからの値を受け取ることができない。
また、Robotの動きを実行時に変えることもできない。

なので、配列に入れるのではなくて、lazyなリスト構造にしよう。
struct roboProgram {
 command (*command_generator)(void);
 struct roboProgram *(next_command)(int arg);
};

commandは(まあchar*でも良いのだが)Robotへのコマンドを表すデータ。
command_generatorはcommandを生成する関数。
next_commandはプログラムの続きを生成する関数。

関数 make_program(command (*com_gene)(void), struct roboProgram (*next)(int));
で、リスト構造が作れるとしよう。

struct roboProgram *roboMain()
{
 return make_program(turn_45, step2);
}

command turn_45(void) { return turn(45); }
struct roboProgram *step2(int ignore)
{
 return make_program(forward_10, step3);
}

command forward_10(void) { return forward(10); }
struct roboProgram *step3(int ignore)
{
 return make_program(get_x_pos, step4);
}

struct roboProgram *step4(int x_pos)
{
 return make_program(turn(x_pos / 2), robo_stop);
}

#しかしCでlazyなリスト作るって面倒だな...

上で、forward(10)やturn(45)を実行したときにRobotが動くわけじゃない。
"forward 10"とか"turn 45"とかいう「コマンド」を返すだけ。
同様に、get_x_posは常に"get_x_pos"という同じコマンド値を返す。

さあ、どこに副作用がある?(いやsprintfは副作用だけどさ^_^;)