関数型言語でのゲッターとセッター


9

関数型プログラミングの原則の1つは、純粋関数の使用です。ピュア関数は、副作用がなく、参照的に透過的な関数です。

ゲッターは参照透過的ではありません-ゲッターへの呼び出しの間にセッターが呼び出されると、ゲッターの戻り値はパラメーターがない(通常はパラメーターがない)場合でも変化します。

セッターは副作用を生み出します-セッターを呼び出すと、通常、戻り値ではない値が操作されます(実際、伝統的にセッターは何も返しません)。

Scalaでは、2つのパラダイム(関数型とオブジェクト指向)を組み合わせてJavaのような言語で行うようにゲッター/セッターを使用しているという事実を受け入れてくれることを知っています。

Haskellのような言語(私は流暢ではありませんが、「純粋な」関数型言語に当てはまると言われています)では、ゲッターが参照透過でセッターであるようにオブジェクトのプロパティをモデル化する方法に興味があります副作用はありませんか?

解決策は、セッターが呼び出されたオブジェクトのコピーをセッターの戻り値として返すことであり、このコピーにはプロパティ値の変更が含まれていますか?


8
ゲッターとセッターはオブジェクトをパラメーターとして持っています-それは通常暗黙的ですが-ゲッター参照的に透過的です。

@delnan、それが読み取っている属性が不変の場合のみ。
dan_waterworth '07

3
@dan_waterworth:オブジェクトIDとして「参照的に透明」の「同じ」を読み取る場合のみ。基礎となる属性が異なるという事実は、それを異なる引数を使用した呼び出しにします(これは、同等性のほとんどの定義と一致しています)。これは、setterを呼び出す別のスレッドを無視し、getterの呼び出しとgetterの終了の間にそれを終了していますが、その場合はとにかくより深刻な問題が発生します。

回答:


7

丁度。ケースクラスメソッドcopy、またはレンズの一般的な概念をご覧ください。

特に、状態を変更する必要がある場合は、Stateモナドを使用します。その状態モナドへの変更は、レンズを介して行うことができます。これにより、「状態」からの情報の抽出と変更が容易になります。

「状態」のような深い構造とそれに変更を加えることから生じる一般的な問題に関するこの質問も参照してください。レンズとジッパーの両方について詳しく知りたい場合は、回答に両方のリンクが含まれています。


質問Daniel:copy()がCaseクラスに関連付けられている特別な理由はありますか?これは具体的にはCaseクラスのニーズ(間違った言葉ですが、別のものとは考えられません)に固有ではないようです。(私にとって)すべてのクラスに適した機能のようです。Case以外のクラスでcopy()が必要な場合はどうなりますか?その機能を取得するために使用できる特性はありますか?
ThaDon、2011

1
@ThaDonケースクラスは、コンストラクターパラメーターによって定義されることになっています。それらの等価性、ハッシュコード、エクストラクターはこの仮定に基づいており、コピーメソッドも同様です。ケース以外のクラスでは、クラスをコピーするために必要なのはコンストラクターのパラメーターだけかどうかはだれでも推測できます。ただし、独自のコピーメソッドを簡単に作成できます。
ダニエルC.ソブラル2011

11

まあ、Haskellでは、オブジェクトは(通常)不変であるため、ゲッター(レコード構文を使用すると取得されます)またはゲッターのように機能する関数参照的に透過的です。そして、オブジェクトに値を「設定」しないでください。古いオブジェクトに似た新しいオブジェクトを作成する場合は、フィールドの1つに異なる値を使用します。これも純粋な関数です。


1
「オブジェクトは(通常は)不変」でないのはいつですか?
サラ

-1

「ゲッターとセッターはオブジェクトをパラメーターとして持っています-それは通常暗黙的ですが-ゲッターは参照的に透過的です。–デルナン」

参照透過とは、関数が常に同じ入力に対して同じ出力を返すことを意味します。したがって、オブジェクト属性がセッターによって変更された場合、同じ出力を返しません。:)


しかし、オブジェクトがセッターによって変更された場合、ゲッターへの入力(つまり、暗黙の自己引数)が変更されました。
スティーブンC.スチール

1
オブジェクト参照値/ポインターは、オブジェクトがヒープ上で移動されない限り変更されません。
Casey Hawthorne

5
はい、ただし論理的には、暗黙の入力はオブジェクト自体であり、ポインタの値ではありません。
スティーブンC.スティール、

「オブジェクト属性がセッターによって変更された場合、同じ出力を返さない」:機能的には、最初のオブジェクトを破棄し、新しいオブジェクトを作成しました。パフォーマンス上の理由から(古いオブジェクトから新しいオブジェクトへの参照のコピーおよび更新を避ける)、古いオブジェクトが含まれていたのと同じメモリ領域に新しいオブジェクトを格納します。
ジョルジオ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.