0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

KuinAdvent Calendar 2018

Day 11

Kuinでクロージャ

Posted at

クロージャは関数を拡張した概念で、環境(スコープのようなもの)を持った関数のことです。と言っても関数型言語に触った人間でなければなかなか分かりづらい概念だと思います。

Wikipedia - クロージャ

Java言語などではクロージャはクラスで実装されています。これに習ってクラスを使ってクロージャを作ってみましょう。

足し合わせを行うクロージャ

まずは、決められた数を足し合わせるクロージャです。

increment.kn
; クロージャのインターフェース
class ClosureIntToInt()
	+func body(n: int): int
		ret 0
	end func
end class

; クロージャを生成する関数
func increment(delta: int): @ClosureIntToInt
	class Increment(@ClosureIntToInt)
		+var delta1: int
		+*func body(n: int): int
			ret n + me.delta1
		end func
	end class
	
	var res: Increment :: #Increment
	do res.delta1 :: delta
	ret res
end func

func main()
	var f: @ClosureIntToInt :: @increment(3)
	do dbg@print(f.body(1).toStr() ~ "\n")
	do dbg@print(f.body(3).toStr() ~ "\n")
	do dbg@print(f.body(5).toStr() ~ "\n")
end func

クロージャを生成する関数の外側にインターフェースを作るのがポイントです。Kuinにはインターフェースを作成する機能はないのでクラスで代用します。クロージャのメソッドを呼び出すことで計算を行います。

クロージャを生成する関数の中にクロージャクラスの定義を書きます。生成関数はクロージャクラスではなく、先ほどのインターフェースの参照を送出することでクロージャの実装を隠蔽します。具体的に言うと、@increment(3)で3を足し合わせるクロージャを生成するのですが、その値を保持するdelta1フィールドにはアクセスすることができません。なぜならば、increment関数の外側でIncrementクラスを指定することができないからです。試しにmain関数内にdo dbg@print((f $ @Increment).delta1)と記述するとコンパイルエラーになります。

クロージャによってイミュータブル(immutable)なオブジェクトを生成することができます。イミュータブルは「書き換え不能な」という意味です。Kuinでもイミュータブルなオブジェクトを作ることは可能なのです。

カウントを行うクロージャ

次に、カウントを行うクロージャです。

counter.kn
; クロージャのインターフェース
class ClosureVoidToInt()
	+func body(): int
		ret 0
	end func
end class

; クロージャを生成する関数
func counter(): @ClosureVoidToInt
	class Counter(@ClosureVoidToInt)
		+var cnt: int
		+*func body(): int
			do me.cnt :+ 1
			ret me.cnt
		end func
	end class
	
	var res: Counter :: #Counter
	do res.cnt :: 0
	ret res
end func

func main()
	var f: @ClosureVoidToInt :: @counter()
	do dbg@print(f.body().toStr() ~ "\n")
	do dbg@print(f.body().toStr() ~ "\n")
	do dbg@print(f.body().toStr() ~ "\n")
end func

プログラムを実行して結果を確認してみましょう。クロージャを呼び出すたびにカウント値が1つずつ増えていきます。

結論

Kuin言語でもクロージャを生成することが可能であることが分かりました。また、Kuinの入れ子構造と継承機能を使えばファイルスコープを使わなくともイミュータブルなオブジェクトを作ったりカプセル化を行うことが可能であることが分かりました。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?