fluorite-7　日本語チュートリアル　Part 11　文と副作用


[チュートリアルトップ](https://qiita.com/MirrgieRiana/items/a0906c72ebfb46693ab5)

[←前回](https://qiita.com/MirrgieRiana/items/e69d38f6a1f1213f7760)　[次回→](https://qiita.com/MirrgieRiana/items/e914a4c15aaba3ae5402)

# レッスン1　文

fluorite-7では、「**評価**」して「値を**返却**」するものを**式**、「動作」だけを行うものを**文**と呼びます。
ソースコード全体などの一部の場所に現れる式は、`;`で区切って複数の部分に分けることができます。
このような複数の部分を持つ式を**複式**と呼びます。
複式のうち、最後の`;`より右側にある部分以外はすべて文です。
文は0個以上書くことができ、式は0個か1個書くことができます。
`;`は無駄に多数書いた場合、単に無視されます。

```bash:
$ fl7 'x: 1; y: x + 1; y + 1'
3

$ fl7 ';;;;; x: 1;;;;; y: x + 1;;;;; y + 1'
3
```

# レッスン2　文だけで構成された複式

複式は、戻り値の式を省略することができます。

```bash:
$ fl7 'x: 1; y: x + 1;'

$ fl7 ''
```

戻り値の省略された複式は、空ストリーマ`()`が返ります。

# レッスン3　丸括弧による複式の配置

複式が直接置けない場所でも、丸括弧`(` `)`で囲うことで複式が置けるようになります。

----

次に示すものは中置`*`の左辺に複式を置く例です。

```bash:
$ fl7 'x: 10; x + x * 100'
1010

$ fl7 '(x: 10; x + x) * 100'
2000
```

`(` `)`がなければ`x + x * 100`が一つの式としてくっついてしまいますが、`(` `)`によってそれを防いでいます。

----

次に示すものは関数呼び出しの引数に複式を置く例です。

```
$ fl7 'f: a, b, c -> a * b * c; f(2; (x: 3; x); 5)'
30
```

関数呼び出しの`(` `)`内では、`;`は関数の引数の区切りという特別な役割を持っています。
そこで、一旦`(` `)`で囲うことで`;`が引数の区切りとして認識されるのを防ぎ、複式を置けるようにしています。

# レッスン4　変数宣言文

これまでにも何度か登場しましたが、「変数名`:`値`;`」で変数を宣言できます。
これは**変数宣言文**という文の一種です。
変数宣言文は、以降の部分でその変数を名前で呼べるようにし、かつ指定された値を変数に代入します。

```bash:
$ fl7 'x: 10; x'
10
```

# レッスン5　式文

一部の式は、そのまま文として埋め込むことができます。
文として埋め込まれた式を**式文**と呼びます。

```bash:
$ fl7 '1; 2; 3'
3
```

`1`や`2`はそのままでは評価をし、値を返却する式です。
これを文の場所に置くと、評価だけをして返された値を無視するようになります。

# レッスン6　OUT関数

OUT関数は、評価されると第1引数の値を標準出力（ブラウザ版ではF12で現れる開発者モード内のコンソール）にログとして出力する関数です。

```bash:
$ fl7 '1; OUT(2); 3'
2
3
```

文は「評価」だけを行って戻り値を無視しますが、OUT関数は「評価」されただけで処理を行うため、式文にしても効果を発揮します。

このような、評価しただけで効果を発揮するような処理を**副作用**のある処理と呼びます。

# レッスン7　代入

中置`=`は、**代入演算子**です。
`=`の左辺が表すものに、右辺を値を代入します。
`=`の左辺は、**セッター**として解釈されます。
セッターとして解釈できない式は、`=`の左辺に置くことはできません。

セッターは、値を代入するための箱を表します。
対して、値そのものを生成する式は**ゲッター**と呼びます。
`1 + 2`のような値を返す式はすべてゲッターです。

----

変数宣言文で作った変数はセッターになることができます。

```bash:
$ fl7 'x: 10; x = 20; x'
20
```

変数に代入を行うと、その変数の値が書き換わり、以降その変数を呼び出したときに、最後に代入された値が得られるようになります。

----

配列の要素はセッターになることができます。

```bash:
$ fl7 'a: [1, 2]; a[0] = 20; a'
20,2
```

配列は変数が多数集まったようなものです。

配列の定義域を外れる添え字を指定した場合、その添え字が正であれば、配列が自動的に拡張されて代入されます。

```bash:
$ fl7 'a: [1, 2]; a[4] = 20; a'
1,2,NULL,NULL,20
```

配列の長さを得る前置`$#`と組み合わせて、「配列`[$#`配列`] =`値」で配列の末尾に要素を追加できます。

```bash:
$ fl7 'a: [1, 2]; a[$#a] = 20; a'
1,2,20
```

----

オブジェクトのプロパティはセッターになることができます。

```bash:
$ fl7 'p: {a: 1}; c: p{b: 2}; c.a = 20; p, c'
{a:1}
{b:2;a:20}
```

```perl:
p: {
  a: 1
};
c: p{
  b: 2
};
c.a = 20;

p, c
```

[オンラインエディタで見る](https://mirrgieriana.github.io/fluorite-7/editor/?s=%0D%0Ap%3A%20%7B%0D%0A%20%20a%3A%201%0D%0A%7D%3B%0D%0Ac%3A%20p%7B%0D%0A%20%20b%3A%202%0D%0A%7D%3B%0D%0Ac.a%20%3D%2020%3B%0D%0A%0D%0Ap%2C%20c%0D%0A%0D%0A)

変数`p`は親オブジェクトで、プロパティ`a`が定義されています。
変数`c`は子オブジェクトで、プロパティ`b`が定義されているとともに、`p`のプロパティ`a`がメンバとして見えています。
このとき、`c`のプロパティ`a`に代入を行うと、`c`に新たにプロパティ`a`が定義され、`p`は書き換わりません。

オブジェクトのプロパティへの代入は、常にそのオブジェクトに対して行われ、親オブジェクトはその影響をうけません。
また、定義されていないメンバに対して代入を行うと、プロパティが新たに定義されて代入されます。

# レッスン8　クロージャ内での代入

fluorite-7では、クロージャ内からクロージャ外の変数に対して代入ができます。

以下のコードを見てみましょう。

```bash:
$ fl7 'f: (a: 1; [(() -> a), (b -> a = b),]); out: []; out[$#out] = f[0](); f[1](50); out[$#out] = f[0](); out[]'
1
50
```

```perl:
f: (
  a: 1;
  [
    (  () -> a      ),
    (  b  -> a = b  ),
  ]
);

out: [];

out[$#out] = f[0]();
f[1](50);
out[$#out] = f[0]();

out[]
```

[オンラインエディタで見る](https://mirrgieriana.github.io/fluorite-7/editor/?s=%0D%0Af%3A%20(%0D%0A%20%20a%3A%201%3B%0D%0A%20%20%5B%0D%0A%20%20%20%20(%20%20()%20-%3E%20a%20%20%20%20%20%20)%2C%0D%0A%20%20%20%20(%20%20b%20%20-%3E%20a%20%3D%20b%20%20)%2C%0D%0A%20%20%5D%0D%0A)%3B%0D%0A%0D%0Aout%3A%20%5B%5D%3B%0D%0A%0D%0Aout%5B%24%23out%5D%20%3D%20f%5B0%5D()%3B%0D%0Af%5B1%5D(50)%3B%0D%0Aout%5B%24%23out%5D%20%3D%20f%5B0%5D()%3B%0D%0A%0D%0Aout%5B%5D%0D%0A)

----

コードの前半部分を抜き出してみます。

```perl:
f: (
  a: 1;
  [
    (  () -> a      ),
    (  b  -> a = b  ),
  ]
);
```

`f`は関数（クロージャ）が2個入った配列です。
変数`a`は`(` `)`の中に入っているので`(` `)`の外部からはアクセスできませんが、`a`にアクセスしている2個の関数が配列にまとめられて`f`に代入されています。
これにより、`f`を通じて変数`a`を操作することができます。

`() -> a`は変数`a`の値を取得する関数で、`f[0]`に格納されています。
`b  -> a = b`は第1引数の値を変数`a`に代入する関数で、`f[1]`に格納されています。

----

コードの後半部分を抜き出してみます。

```perl:
out: [];

out[$#out] = f[0]();
f[1](50);
out[$#out] = f[0]();

out[]
```

配列変数`out`に値を格納すると、最後にそれを表示します。
`out[$#out] = `は配列変数`out`の末尾に要素を追加するイディオムです。

`out[$#out] = f[0]();`がやっていることは、`out`の最後に`f[0]()`を追加しています。
`f[0]`例の変数`a`の値を得る関数だったので、`f[0]()`は変数`a`の値を表します。
結果、`out`の末尾に変数`a`の現在の値が入ります。

`f[1](50);`は同様に変数`a`に`50`を代入する動作を行います。

まとめると、`a`の初期値である`1`を`out`に追加し、`a`に`50`を代入し、`a`の代入後の値である`50`を`out`に追加しています。

----

最終的に`out`の中身は1と50となり、それをストリーマ展開して出力すると

```
1
50
```

という出力が得られます。

# まとめ

- 式を`;`で区切ると複式になる。
- 最後の`;`より左は全部文で右にあるのは式。
- 複式内で式を省略すると空ストリーマが返る。
- 直接複式を置けない場所には`(` `)`で囲んで置く。
- 中置`:`で構成された文は変数宣言文。
- 式を文の場所に置くと式文。
- OUT関数は式文にしても効果がある。
- 中置`=`は代入。
- 変数には代入できる。
- 配列要素には代入できる。
- 定義域を超える添え字を指定して代入すると、配列が拡張される。
- オブジェクトのプロパティには代入できる。
- 関数内から関数の外部にある変数に対して直接代入ができる。

# Part 12

[次回→](https://qiita.com/MirrgieRiana/items/e914a4c15aaba3ae5402)