web-dev-qa-db-ja.com

このプログラムで「参照透過性」を適用するにはどうすればよいですか?

以下は、関数型プログラミングで 経験則 に従うように記述されたpythonプログラムです。

簡単なルールは次のとおりです。プログラムがその意味を変更せずに、式、部分式、またはサブルーチン呼び出しをプログラム内の任意の場所でその式、部分式、またはサブルーチン呼び出しの戻り値に置き換えることができる場合、参照があります。透明性。そして、これが意味することは、実際には、I/Oを持たず、可変状態を持たず、副作用を持たないということです。すべての式で、式の値は、式の構成部分の値のみに依存する必要があります。また、すべてのサブルーチン呼び出しで、戻り値は引数のみに依存する必要があります。

def identity(k):
    return k

def cube(k):
    return pow(k, 3)

def summation(n, term):
    total, k = 0, 1
    while k <= n:
        total, k = total + term(k), k + 1
    return total

def sum_naturals(n):
    return summation(n, identity)

def sum_cubes(n):
    return summation(n, cube)

if __name__ == '__main__':
    sum = sum_naturals(4)
    print(sum)

上記のプログラムでは、totalkが指すオブジェクトは状態の不変性を維持し、I/Oは確認のためのドライバーコード以外では使用されません結果。

このプログラムで使用されるすべての式/部分式に対して、プログラムで「参照透過性」を適用するにはどうすればよいですか?

1
overexchange

あなたはすでにあなたの質問であなたのプログラムが参照透過性であるかどうかを見分ける方法を言いました:プログラムの意味を変えずに式をその値で置き換えることができれば、それは参照透過性です。それができないのなら、そうではありません。

それでは、いくつかの式をそれらの値に置き換えてみましょう!

summationメソッドの最初の行で、total0に設定します。したがって、プログラムが参照透過性である場合は、totalの出現箇所を0に置き換えることができるはずです。たとえば、次のようになります。

def summation(n, term):
    total, k = 0, 1
    while k <= n:
        total, k = 0 + term(k), k + 1
    return total

またはこのように:

def summation(n, term):
    total, k = 0, 1
    while k <= n:
        total, k = total + term(k), k + 1
    return 0

同じことがkにも当てはまります。

def summation(n, term):
    total, k = 0, 1
    while k <= n:
        total, k = total + term(k), 1 + 1
    return total

またはここ:

def summation(n, term):
    total, k = 0, 1
    while k <= n:
        total, k = total + term(1), k + 1
    return total

またはここ:

def summation(n, term):
    total, k = 0, 1
    while 1 <= n:
        total, k = total + term(k), k + 1
    return total

それをすべてまとめましょう:

def summation(n, term):
    total, k = 0, 1
    while 1 <= n:
        total, k = 0 + term(1), 1 + 1
    return 0

また、whileループの戻り値は何ですか? whileループは戻り値をhaveせず、何も返しません。参照透過性の規則によれば、プログラムergoの意味を変更せずに、式を戻り値に置き換えることができるはずです。whileループ全体を何も置き換えることができないはずです。

def summation(n, term):
    total, k = 0, 1
    return total

繰り返しますが、プログラムが参照透過性である場合、これによって結果が変わることはありません。

ループは単に参照透過性にはなり得ないことに注意してください。参照透過性は、「私が同じことをすると、同じことが起こる」と解釈することもできます。しかし、ループでは、do同じことが何度も繰り返されますが、毎回、または少なくとも1回は異なることが起こると予想されます。ループが停止します。

参照透過性を損なうことなくsummationを実装する方法の例を次に示します。

def summation(n, term):
    if n == 0:
        return term(n)
    else:
        return term(n) + summation(n - 1, term)

そして、これが標準の「アキュムレータの導入」トリックを使用した末尾再帰的な実装です。

def summation(n, term):
    def summation_rec(n, total):
        if n == 0:
            return total
        else:
            return summation_rec(n-1, total + term(n))
    return summation_rec(n, 0)

(残念ながら、Pythonは適切な末尾呼び出しを実装しておらず、適切な末尾再帰も実装していないため、これは役に立ちません。したがって、これでもスタックが大きくなりますn 。しかし、末尾再帰または適切な末尾呼び出しが適切に実装されている言語では、これはO(1)スタックスペースで実行されます。)

5
Jörg W Mittag