インデントブロック

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 にあります。 かなり極端な例ではありますが。