2013年5月10日金曜日

Rとクロージャ その2

前回の続きです。

Rのプロンプトで demo(scoping) を実行すると、クロージャの使用例を見ることができます。
SICPの銀行口座 (3.1.1 Local State Variables) をRで実装したものだと思います。

> demo(scoping)


        demo(scoping)
        ---- ~~~~~~~

Type  <Return>   to start : 

> ## Here is a little example which shows a fundamental difference between
> ## R and S.  It is a little example from Abelson and Sussman which models
> ## the way in which bank accounts work.       It shows how R functions can
> ## encapsulate state information.
> ##
> ## When invoked, "open.account" defines and returns three functions
> ## in a list.  Because the variable "total" exists in the environment
> ## where these functions are defined they have access to its value.
> ## This is even true when "open.account" has returned.  The only way
> ## to access the value of "total" is through the accessor functions
> ## withdraw, deposit and balance.  Separate accounts maintain their
> ## own balances.
> ##
> ## This is a very nifty way of creating "closures" and a little thought
> ## will show you that there are many ways of using this in statistics.
> 
> open.account <- function(total) {
+ 
+     list(
+        deposit = function(amount) {
+            if(amount <= 0)
+                stop("Deposits must be positive!\n")
+            total <<- total + amount
+            cat(amount,"deposited. Your balance is", total, "\n\n")
+        },
+        withdraw = function(amount) {
+            if(amount > total)
+                stop("You don't have that much money!\n")
+            total <<- total - amount
+            cat(amount,"withdrawn.  Your balance is", total, "\n\n")
+        },
+        balance = function() {
+            cat("Your balance is", total, "\n\n")
+        }
+        )
+ }

> ross <- open.account(100)

> robert <- open.account(200)

> ross$withdraw(30)
30 withdrawn.  Your balance is 70 


> ross$balance()
Your balance is 70 


> robert$balance()
Your balance is 200 


> ross$deposit(50)
50 deposited. Your balance is 120 


> ross$balance()
Your balance is 120 


> try(ross$withdraw(500)) # no way..
Error in ross$withdraw(500) : You don't have that much money!

> 

銀行口座の状態(total: 残高)はカプセル化されていて、外部からは直接参照できません。 代わりにアクセサ(deposit: 預入れ、 withdraw: 払出し、 balance: 残高確認) を通してやり取りしています。

オブジェクト指向っぽいものを簡単に実現できていて素敵ですね。

0 件のコメント:

コメントを投稿