サンプルコードの解説
以下の前回の記事のコードをベースにRedにおけるコーディングの基本的な部分や構文などについて解説をしていきます。
Red []
dir: request-dir
files: read dir
show-file-or-folder: func [ files [block!] ] [
foreach file files [
print [form file "is" either dir? file ["folder"] ["file"] ]
]
]
show-file-or-folder files
パート1:プログラムのヘッダー
1行目はRedのヘッダー部分です。
本来はアプリ名や作成者名などを記載しますが、今回は省略しています。
パート2:フォルダ選択ダイアログの表示
2行目は以下のようになっています。
dir: request-dir
dirはいわゆる変数のようなものですが、Redではwordと呼びます。
wordは初めて使うときでも特に初期化の構文はなく、いきなり任意の名称を書けばOKです。
コロンがいわゆる代入のような(C#などでの「=」に似たもの)もので、
ここではdirというwordにrequest-dirの結果をセットしています。
request-dirは組み込みの関数で、フォルダの選択ダイアログを表示して、選択結果を戻り値として返します。
パート3:選択したフォルダの中身の読み込み
次の行は以下のようになっています。
files: read dir
これも前の行同様、「files」というwordにreadの結果をセットしています。
readも組み込みの関数で、フォルダパスを受け取って、そのフォルダの中身を取得します。
readに渡しているのが1行前でrequest-dirの結果をセットしたword、dirです。
これでfilesにread関数の結果がセットされます。
なお、Redでは関数呼び出しの時に( )はつけず、また引数を区切る時にカンマなどを使うこともありません。
どちらも半角スペースを空けることで表現します。
引数が複数ある場合はそれぞれ半角スペースを入れることになります。
パート4:関数を作る
次の行あたりがRedっぽさが出てきますが、関数の定義を行っている部分になります。
show-file-or-folder: func [ files [block!] ] [
foreach file files [
print [form file "is" either dir? file ["folder"] ["file"] ]
]
]
show-file-or-folderが作った関数を受け取っているwordです。
Redでは関数を定義する時に専用の構文は使わず、関数オブジェクトを作ってそれをwordに代入する、というやり方をします。
そして、関数を作るために使っているのがfuncという関数です。1
コンソールで「? 関数名」と打つと使い方を見ることができるため、以下のようにfuncの使い方を確認してみます。
red>> ? func
上記のコマンドを実行すると、以下の説明が表示されました。
USAGE:
func spec bodyDESCRIPTION:
Defines a function with a given spec and body.
func is of type: native!ARGUMENTS:
spec [block!]
body [block!]REFINEMENTS:
引数(ARGUMENTS)が2つで、両方ともblock!型であるとなっています。
block!は複数の要素を持てる配列とかタプルのようなものです。
Redでは[ ]がblock!を意味します。[ ]の中に[ ]が入ることもあります。
今回のソースではfuncに以下の2つのblock!を渡しています。
[ files [block!] ]
[
foreach file files [
print [form file "is" either dir? file ["folder"] ["file"] ]
]
それぞれについて説明します。
関数のシグネチャの定義
funcに渡しているblock!の1個目はC#などで言うメソッドシグネチャを記載するblock!で、ここでは引数としてfilesというwordがあり、型がblock!だと指定しています。2
関数本体の定義
渡しているblock!の2個目が関数の処理の本体部分です。
ここは割と他の言語と似た感じなのでイメージつきやすいかと思いますが、
foreachは2つ目の引数(files)の中身を順番に列挙して1つ目の引数(file)に格納し、
そのたびにblock!の中身を実行する関数です。
「foreach 文」ではなく関数の一種なのが面白いところです。
printは標準出力への文字列表示ですが、渡しているのはまたしてもblock!です。
中で使っている関数を知らないと分かりにくいかもしれないですが、
このblock!は意味的には以下の3つのパートに分かれています。
form file
"is"
either dir? file ["folder"] ["file"]
1つ目のパートのformは渡されたwordの中身をフォーマットして文字列化する関数です。
Redだとfile!データ型が若干独特の文字列表現になりますが、
formを通すと一般的な感覚のパスになります。
2つ目のパートは、単純な文字列リテラルの「is」です。
3つ目のパートのeitherはいわゆるifで、第1引数がtrueなら第2引数、
falseなら第3引数のblock!の結果を返すようになっています。
第1引数はdir? fileという関数呼び出しになっていて、
これはfileがフォルダであるかをチェックしています。
これをprintで文字列化すると、以下のような出力が得られます。
XXX is file ; XXXがファイルだった場合
または
YYY is folder ; YYYがフォルダだった場合
block!の中身は半角スペースで区切られますが、printするとそのまま
スペース区切りで出力されるので、上記のような出力になってくれます。
パート5:作成した関数の呼び出し
さて、サンプルの最後は以下の1行になります。
show-file-or-folder files
厳密にはshow-file-or-folderもfilesもwordな訳ですが、直感的に言えばここは
show-file-or-folder関数に引数としてfilesを渡している、という理解でよいかと思います。
随分長くなってしまいましたが、これでサンプルコードの説明が終わりました。
次回からまた色々試してみたいと思います。