-
Notifications
You must be signed in to change notification settings - Fork 2
Language New Features
第一級オブジェクトとしての関数を導入!関数型プログラミング言語へ!!
関数オブジェクトの基本
a = function(int x, int y){
return x + y
}
MessageClip(String(a)) # Function
b = a
MessageClip(String(b)) # Function
MessageClip(String(a == b)) # true
引数にとったり
function MyFunc(func f) {
return f(2, 3)
}
a = MyFunc(function(x, y) {
return x + y
})
MessageClip(String(a)) # 5
戻り値で返したり
function MyFunc() {
return function(x, y) {
return x + y
}
}
a = MyFunc()(2, 3)
MessageClip(String(a)) # 5
仮引数の前に '[]' でその時点での変数をキャプチャ
function MyFunc() {
x = 2
y = 3
return function[x, y]() {
return x + y
}
}
a = MyFunc()()
MessageClip(String(a)) # 5
関数オブジェクトは新しい構文で定義された関数です。
function[](){ ... }
これまでの通常の関数定義と比べて名前のない関数のような形になっています。[]はオプションでなくても構いません。
普通の関数形式で定義された関数は関数オブジェクトではありません(互換性維持のため)。
function MyFunc() { return 123 }
a = MyFunc
MessageClip(String(a)) # 123 (Not Function)
同様に組み込み関数やプラグイン関数も、関数オブジェクトではありません。
a = Invert # Error: I don't know what 'Invert' means.
関数オブジェクトでない関数は、func関数を使えば関数オブジェクト化できます。
a = func(Invert)
Version().a() # Invert a clip
値の型に、新しく'func'が加わりました。
function MyFunc(func x, func y, int z) {
return x() + y() + z
}
a = MyFunc(function(){1},function(){2},3)
MessageClip(String(a)) # 6 (= 1 + 2 + 3)
関数オブジェクトを判定するIsFunction関数が追加されています。
a = function(){}
MessageClip(String(IsFunction(a))) # true
ScriptClipを書きやすくするプラグインGRunTとNeoを比較してみましょう。
GRunTの紹介ページにある以下のコード
function bracket_luma(clip c, float th1, float th2) {
Assert(0 <= th1 && th1 < th2 && th2 <= 255, "Invalid thresholds!")
ScriptClip(c, """
avl = AverageLuma()
avl <= th1 ? last.BlankClip() : avl >= th2 ? last.BlankClip(color=color_white) : last
""", args="th1,th2", local=true)
}
GRunTの良さをアピールするためのサンプルですが、Neoだと以下のように書けます。
function bracket_luma(clip c, float th1, float th2) {
Assert(0 <= th1 && th1 < th2 && th2 <= 255, "Invalid thresholds!")
ScriptClip(c, function[th1,th2]() {
avl = AverageLuma()
avl <= th1 ? last.BlankClip() : avl >= th2 ? last.BlankClip(color=color_white) : last
})
}
GRunTと比べて以下のような違いがあります。
- 処理の内容を文字列で渡す必要がない
- 使う変数は専用の構文で書けるので、記述量が減っている
処理の内容をスクリプトの文字列で渡していた関数は、関数を渡せるバージョンが追加されました。
ScriptClip(clip clip, func filter [, bool show, bool after_frame] )
例)
Version()
ScriptClip(function[](clip c) {
c.Subtitle(String(current_frame))
})
ConditionalFilter(clip testclip, clip source1, clip source2, func condition [, bool show] )
例)
a = Version()
b = a.Invert()
ConditionalFilter(a, a, b, function[](clip c) {
current_frame < 30 # if true return a else b
})
ConditionalSelect(clip testclip, func get_index, clip source0 [, clip source1...] [, bool show] )
例)
Version()
ConditionalSelect(function[](clip c) {
current_frame / 100
}, subtitle("0"), subtitle("1"), subtitle("2"))
WriteFile(clip clip, string filename, func expression1 [, func expression2 [, ...]] [, bool append, bool flush])
WriteFileIf(clip clip, string filename, func expression1 [, func expression2 [, ...]] [, bool append, bool flush])
WriteFileStart(clip clip, string filename, func expression1 [, func expression2 [, ...]] [, bool append])
WriteFileEnd(clip clip, string filename, func expression1 [, func expression2 [, ...]] [, bool append])
例)
Version().ConvertToY()
WriteFile("out.txt", function() {
string(current_frame) + ": " + string(YPlaneMedian())
})
eプリフィックスが付いた文字列 e"..."
は、バックスラッシュによるエスケープ処理が有効になります。
例)
Version().ConvertToY()
WriteFileStart("out.txt", function() {
e"foo\tbar\nhoge\thoge"
})