あなたが何を望んでいるかを私が正しく理解しているなら、それは理論的に不可能です。あなたが説明しているように見える変換は、コンパイルされた形式で保持されない可能性が高いソースコードの表面的な詳細に応じて、同等の機能に異なる影響を与えるものです。たとえば、特定の関数の次の 2 つのバージョンについて考えてみます。
def a (n, acc):
print('called a(%d,%d)' % (n, acc))
if n == 0: return acc
return a (n - 1, acc + n)
def a (n, acc):
print('called a(%d,%d)' % (n, acc))
if n == 0: return acc
ret = a (n - 1, acc + n)
return ret
明らかに、それらは機能的に同一です。ソース コードでの唯一の違いは、前者はreturn
特定の式を直接使用するのに対し、後者はその式の結果をローカル変数に保存してから、return
その変数を使用することです。コンパイルされた形式では、違いはまったくありません。
ここで、「パッチを適用した」バージョンを検討してください。
def a (n, acc):
print('called a(%d,%d)' % (n, acc))
if n == 0: return acc
return lambda: a (n - 1, acc + n)
def a (n, acc):
print('called a(%d,%d)' % (n, acc))
if n == 0: return acc
ret = a (n - 1, acc + n)
return lambda: ret
明らかにこれらは大きく異なります: たとえば、n
is3
とacc
is 0 の場合、前者は を出力called a(3,0)
して返す関数を出力called a(2,3)
して返す関数を出力し、 を出力called a(1,5)
して返す関数を出力called a(0,6)
して返します6
が、後者は and を出力called a(3,0)
しcalled a(2,3)
てcalled a(1,5)
andcalled a(0,6)
を返します。を返す関数を返す関数 を返す関数6
。
より広い違いは、最初の「パッチを適用した」関数は、新しい戻り値が呼び出されるたびに計算の 1 つのステップを実行するのに対し、2 番目の「パッチを適用した」バージョンは、最初の呼び出し中に計算のすべてのステップを実行し、単純に系列を配置することです。娯楽のためのその後の呼び出しの。この違いは、副作用 (メッセージを出力する、スタックをオーバーフローさせるほど深く再帰するなど) がある場合は常に重要になります。呼び出し元が副作用を導入するかどうかも問題になる可能性があります。これらの関数はa
、コードの他のビットが再定義されるまでのみ再帰的であることに注意してください。a
はすでにすべての呼び出しを完了しています。
2 つの「パッチが適用されていない」バージョンを区別できないため、変換が意味する個別の「パッチが適用された」バージョンを生成することは明らかにできません。