解決編:その理解は確かか

ここまでの理解が確かなら、その理由を説明できるはずです。

    if (!i.MoveNext()) {
throw Ops.TypeError(...);
}

ex1 では、第2引数が "A" なので、次の要素 "A" に進めます。すると、条件式 !i.MoveNext() は成立しないので、例外を生成しません。

    object ret = i.Current;
while (i.MoveNext()) {
ret = Ops.Call(func, ret, i.Current);
}
return ret;

ret は、要素 "A" を保持します。次の要素が残っていないので、先に進めません。すると、条件式 i.MoveNext() は成立しないので、ret がリターン値になります。

TypeError: 'NoneType' object is not callable

ex3 で、このエラーメッセージを出力するのは、第1引数に None を指定したからです。None には、メソッド呼び出しを適用できません。