今日は関数のお勉強になるんですが、これがまた深いところなんで、いつも言ってますが
とりあえず簡単なとこだけやります。
僕もまだまだよくわかってなくて、本当はFukiyaさんかmatsuさんに解説してもらってから記事書きたいぐらいです。間違ったこと言ってたら殴ってくださいね
さて
と、そのまえに前回記事の補足です
sas.submit([[SASコード]],{置換パラメータ指定})の
置換パラメータ指定の部分ですが、別にsubmitの中で指定しなくても
実行時点で置換パラメータがLuaの中で変数として定義されていればそれが適応されます
ので以下のコードも成立します。
proc lua;
submit;
local ds="b"
local var="y"
local code=[[data @ds@;
@var@=1;
run;]]
sas.submit(code)
endsubmit;
quit;
あと、さらに唐突な補足です。Luaの論理式はFalseとnilが偽でそれ以外が真という話をしました。それに絡んで面白い性質があって、以下のような代入式(SASでいう割り当てステートメント)において左辺をorで結ぶと、左から順に評価して、偽である値はスキップされ、初めて真である値が代入されます
コードと結果を見てください
proc lua;
submit;
local a = 99;
local b = nil;
local v1 = b or a
local v2 = (1>2) or a
local v3 = d or e or f or a or 88
local v4 = g or h
print(v1)
print(v2)
print(v3)
print(v4)
endsubmit;
quit;
結果
それがなんじゃい?なにに使うんじゃい?と思われた方はちょっと甘い!
X=Y or 99 は、YがあればYの値を使うし、Yがなければ99を使う。初期化されていない変数にはnilが入っている。それらの性質を使うと、パラメータのデフォルト値を設定できるということなんですよ。
SASマクロにも、キーワードパラメータが指定されなかったときにはこの値を使うみたいな書き方できるでしょう、あれと同じことができるんですね
はい、いよいよ本題です。
Luaの関数ですが、以下のように作って、使います
proc lua;
submit;
--定義
function add(a,b)
return a+b
end
--型もみてみよう
print(type(add))
--早速使ってみる
print(add(1,2))
print(add(1,5))
endsubmit;
quit;
結果
文法は
function 関数名(引数)
戻り値があるならreturn 戻り値
end
です。簡単ですね。
ただ、細かい話なんですが、正確に言うと、Luaには「関数名」っていう考え方は間違ってるんです。
関数名というものは存在しません。
はぁ?って話なんですが、以下のコードを見てください
proc lua;
submit;
--[[厳密にいうとLuaの関数に名前はない(無名関数)、
関数を変数に入れて使っており、変数に名前がついている
]]--
add=function(a,b)
return a+b
end
endsubmit;
quit;
実は最初に紹介したのは、こういう書き方もできるって話で糖衣構文みたいなもんです。
本質的には
変数名 = function(引数)
戻り値があるならreturn 戻り値
end
なんです。これは無名関数といって、本当は関数自体には名前がなくて、その名前のない処理を
変数に入れる。変数には名前がある。ので関数の入ってる変数名がいわゆる関数名みたいになるということです。
だからそれがどうしたって話なんですけど、一応知っておいてください。
いずれ複雑なことをするときに必要になるので。
さて、わけのわからん話はやめて、続きです。
冒頭に紹介したorを使えば、関数の引数を省略した場合の挙動を制御できますよという話
proc lua;
submit;
function add(a,b)
local a= a or 3
local b= b or 5
return a+b
end
print(add(aaa))
print(add(1))
print(add(nill,1))
endsubmit;
quit;
結果
そして、引数の部分について以下のようにハッシュ型の変数定義も使うことができます
こうすると本当キーワードパラメータマクロのようですね
proc lua;
submit;
function add(para)
para.a= para.a or 3
para.b= para.b or 5
return para.a+para.b
end
print(add({a=2,b=2}))
print(add({a=2}))
print(add({b=2}))
endsubmit;
quit;
結果
戻り値のない関数も全然ありなので
たとえば、以下のようなSASコードの実行を関数にすることもできますよっと
proc lua;
submit;
function ds_make(para)
local ds= para.ds or "aaa"
local var= para.var or "bbb"
sas.submit([[data @ds@;@var@=1;run;]])
end
ds_make({ds="ds1",var="var1"})
ds_make({})
endsubmit;
quit;
次に、引数の数がが可変の場合の定義です。
以下のように...とかきます。その後、関数の中でテーブルに入れて
捌いてやればOK。
引数がいくつでも動く関数ができます
proc lua;
submit;
function add3(...)
list = {...}
result=0
for val in pairs(list) do
result =result+val
end
return (result)
end
print(add3(1,2))
print(add3(1,2,3,4))
endsubmit;
quit;
結果
・・・で引数を定義するのが面白いですね、受け取ったらまずテーブルに入れて捌いてます。
ループで足してます。sum関数みたいなのができましたね。
逆に、戻り値が複数あるパターン。
海外論文にも載ってた(論文のコードには誤植あるけど)、本日日付を年月日に分解して
3つの戻り値をえるコードです
proc lua;
submit;
function split_date()
local date = sas.date()
return sas.day(date), sas.month(date), sas.year(date)
end
local day, month, year = split_date()
print("d=", day, "m=", month, "y=",year)
endsubmit;
quit;
結果(実行したのは2016/8/30です)
さらに、戻り値をテーブルにしたり、テーブルを引数にするパターンを見てみましょう。
まず、与えた文字列を1文字ずつ分解してテーブルを返すsplit_char関数をつくってみて
その後、テーブルを受け取ってまた1つの文字にするcats_table関数を作ってみました。
ただテーブルから文字をつくるのは普通にtable.concat関数というものがあって、これだと連結文字や対象範囲も指定できて、絶対こっちの方がいいです。車輪の再発明も勉強にはなりますけどね
proc lua restart;
submit;
--文字列を1文字ずつ取り出してテーブルにする関数(戻り値はテーブル)
function split_char(char)
local result_table={}
local len=string.len(char)
for i =1,len do
result_table[i]=string.sub(char, i,i)
end
return(result_table)
end
local tb1=split_char("abc")
print("★文字列が分解されてテーブルになりました→",table.tostring(tb1))
--テーブルを引数にして、テーブルの中身を連結して1つの文字値にする関数
function cats_table(table)
local result=''
for i, item in pairs(table) do
result = result..item
end
return result
end
local st1=cats_table(tb1)
print("★テーブルが連結されて文字列にになりました→",st1)
local st2=table.concat(tb1,"/")
print("★concat関数はcatxみたいで便利だな→",st2)
endsubmit;
quit;
結果
なんかFCMPよりだいぶ書きやすいなぁって思うのは僕だけしょうか。
--おまけ
ちょっと難しい話になりますが、
関数は、変数に過ぎないので、関数の中に関数を入れることができ
それを使うと関数を作る関数とかも定義できます
proc lua;
submit;
function concat3_func(x,y,z)
print(x..' '..y..' '..z)
end
function make_func(x,y)
return function (target)
concat3_func(x, y, target)
end
end
i_love_func =make_func("I","love")
you_love_func =make_func("You","love")
i_study_func =make_func("I","study")
print(i_love_func("SAS"))
print(you_love_func("SAS"))
print(i_study_func("Lua"))
endsubmit;
quit;
こういうのの詳しい話はまたいずれ。とりあえず今日はここまで!!