Cyan においては、インデントによってブロックを表現することができます。 その前に、porter と messenger におけるブロック引数について紹介します。
porter と messenger の引数を指定する際に、ブロックと関数の場合は 引数の括弧の後に記述することができます。具体的には、次のようになります。
# func1(1, 2, { say("func1") }) と等価 func1(1, 2){ say("func1") } # func2(2, 3, ^(x, y){ say("func2") }) と等価 func2(2, 3)^(x, y){ say("func2") } |
引数がブロックや関数以外にない場合、引数の括弧は省略できます。
# func3({ say("func3") }) と等価 func3{ say("func3") } # func4(^(x){ say("func4") }) と等価 func4^(x){ say("func4") } |
さらに、間にシンボルをはさむことで、 複数のブロックや関数を引数として指定できます。 この場合、それらはキーワード引数となります。
# func5(1, 2, { say("func5") }, :sym1 { a }, :sym2 ^(x){ x }) と等価 func5(1, 2){ say("func5") }sym1{ a }sym2^(x){ x } |
さて、ここでインデントブロックについて説明しましょう。 Cyan において、インデントは重要な意味を持ちます。
式の途中で改行し、インデントして続きを書くと、 それらは一続きの式として認識されます。 改行は、前の式の先頭に揃えて式を書いた場合に挿入されます。
x = 1 + 2 + 3 + 4 + 5 + 6 say(x) #=> 21 |
しかし、関数を記述する際の仮引数の後や、 porter や messenger の引数の後にコロン(:)をおくと、 次に現れた式の先頭が改行を挿入するための目印になります。 つまり、その式の先頭に揃えて次の式を書けば、改行が挿入されるのです。 また、もし次の式がその先頭より前に現れた場合、 特殊なトークン End が挿入されます。 それでは、改行を表すトークンをセミコロン(;)として、 式がどのように解析されるか見てみましょう。
func6(1, 2): say("func6") say("func6") say("func6") |
上のコードは、次のように解析されます。
func6 ( 1 , 2 ) : say ( "func6" ) ; say ( "func6" ) End ; say ( "func6" ) |
ここで、コロンは { と、End は } と等価なので、それぞれ置き換えてみましょう。
func6 ( 1 , 2 ) { say ( "func6" ) ; say ( "func6" ) } ; say ( "func6" ) |
これは、次のコードを解析した結果と同じです。
func6(1, 2){ say("func6") say("func6") } say("func6") |
このようにして、Cyan ではインデントによってブロックを表現できるのです。 また、次のような書き方もできます。
if(x == 0): say("x == 0") else: say("x != 0") |
これは、
if(x == 0){ say("x == 0") }else{ say("x != 0") } |
と等価です。
実は、ブレースを用いたブロックにおいてもインデントは考慮されており、 インデントが失われた場合そのままでは実行できません。 しかし、開始と終端が明示されているため、復元は可能です。
Cyan にインデントブロックを導入したのは、私がそう書きたかったからです。 ブレースも end も嫌いではないですが、連続して現れているのを見るのは あまり好きではありません。 特に関数型言語的に書こうと(ブロックに1つの式しか書かないように)すると、 ネストが深くなればなるほど大量の終端子が現れます。
その例は、サンプルフォルダ内の qsort3.cy にあります。 かなり極端な例ではありますが。