fluorite-7　日本語リファレンス　関数


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

# 基礎

関数は、型名`FUNCTION`を持つ値である。

`() -> 1`は0個の引数を取り、常に1を返す関数を生成する式である。
`(a) -> a * 10`は1個の引数の10倍の値を返す関数を生成する式である。
`(a; b) -> a * b`は2個の引数の積を返す関数を生成する式である。

関数は呼び出すことができる。

`f()`は関数`f`に0個の引数を与えて呼び出す式である。
`f(10)`は関数`f`に1個の引数を与えて呼び出す式である。
`f(10; 20)`は関数`f`に2個の引数を与えて呼び出す式である。

```bash:
$ fl7 'TYPE(  () -> 1  )'
FUNCTION
$ fl7 '(  () -> 1  )()'
1
$ fl7 '(  (a) -> a * 10  )(10)'
100
$ fl7 '(  (a; b) -> a * b  )(10; 20)'
200
```

# 関数の生成

## ラムダ式

ラムダ式は、ラムダ演算子`args -> formula`によって関数を生成する式である。
ラムダ演算子は列挙演算子`a,b,c`と代入系演算子`var = val` `var : val`の間の結合優先度を持つ中置演算子である。

`args`には括弧`(` `)`を書き、その中で`;`区切りで引数列を記述する。
引数が0個の場合、空の括弧`()`を記述する。
`formula`には関数の本文を記述する。
関数の本文では、引数を参照できる。

```perl:
() -> 10
(a) -> a
(a; b; c) -> a * b * c
```

### 呼び出し時の引数チェック

ラムダ式で生成された関数は、生成時に指定された個数の引数でしか呼び出すことはできない。

### 引数列の区切り文字は`,`であってもよい

```perl:
(a, b, c) -> a * b * c
```

### 引数列を囲う`(` `)`は省略してもよい

```perl:
a, b, c -> a * b * c
```

ただし、引数が0個の場合や区切り文字が`;`の場合は簡単には適用できない。

----

**Tips** この記法を使うと変数への代入時に括弧が要らなくなる。

```perl:
f : a, b, c -> a * b * c;
```

## 即席関数

即席関数は、即席関数演算子`\formula`によって関数を生成する式である。
即席関数演算子は、そのほかの前置演算子と等しい結合優先度を持つ前置演算子である。

`formula`には関数の本文を記述する。

```perl:
\50
```

```bash:
$ fl7 '(  \50  )()'
50
```

### 即席関数は何個の引数でも呼び出せる

```bash:
$ fl7 '(  \50  )(1; 2; 3; 4; 5)'
50
```

### `_`で第一引数を参照できる

ただし、第一引数が存在しない場合はNULLが格納されている。

```bash:
$ fl7 '(  \_  )(50)'
50
$ fl7 '(  \_  )()'
NULL
```

----

**Tips** 前置演算子の結合優先度は後置演算子の後なので、第一引数のアクセサをコンパクトに記述できる。

次の例は、関数を与えると50に適用して返す関数fに、数値を10倍する関数を適用する例である。

```bash:
$ fl7 'f : \_(50); f(a -> a * 10)'
500
```

### `__`で引数列全体を参照できる

```bash:
$ fl7 '(  \__  )()'
{LENGTH:[FluoriteFunction]}
$ fl7 '(  \__  )(10)'
{0:10;LENGTH:[FluoriteFunction]}
```

`$#__`で引数の個数、`__.0`で最初の引数が得られる。

```bash:
$ fl7 '(  \$#__  )(10; 20; 30; 40; 50)'
5
$ fl7 '(  \__.0  )(10; 20; 30; 40; 50)'
10
```

## 配列

配列を関数として呼び出すと、呼び出し時の引数の個数に応じた要素の値が呼び出される。

```perl:
f : [
  0 : () -> 1;
  1 : a -> a * 10;
  2 : a, b -> a * b;
];
f(), f(5), f(5; 7)
```

```bash:
$ fl7 'f : [0 : () -> 1; 1 : a -> a * 10; 2 : a, b -> a * b]; f(), f(5), f(5; 7)'
1
50
35
```

## オブジェクト

オブジェクトを関数として呼び出すと、`CALL`メソッドが呼び出される。

```perl:
obj : {
  val : 3;
  CALL : _, a, b -> _.val * a * b;
};
obj(5; 7)
```

```bash:
$ fl7 'obj : {val : 3; CALL : _, a, b -> _.val * a * b}; obj(5; 7)'
105
```

## 正規表現

正規表現を関数として呼び出すと、マッチが行われる。

```bash:
$ fl7 '/-(.)-/("-g-").1'
g
$ fl7 '"abc", "123", "abc123" | */^\d+$/'
NULL
123
NULL
```

## ストリーマ

正規表現を関数として呼び出すと、各要素の関数呼び出しのストリーマ結合になる。

```bash:
$ fl7 'SIN(PI), COS(PI), TAN(PI)'
1.2246467991473532e-16
-1
-1.2246467991473532e-16
$ fl7 '(SIN, COS, TAN)(PI)'
1.2246467991473532e-16
-1
-1.2246467991473532e-16
```

# 関数の呼び出し

## 関数呼び出しアクセス

関数呼び出しアクセス演算子`func(args)`は、関数を呼び出す後置演算子である。
`func`には関数を記述する。
`args`には引数列を`;`区切りで記述する。
引数がゼロ個の場合、`args`は省略される。

```perl:
f0 : () -> 1;
f1 : (a) -> a * 10;
f2 : (a; b) -> a * b;
f0(), f1(), f2(10; 20)
```

```bash:
$ fl7 'f : () -> 1; f()'
1
$ fl7 'f : (a) -> a * 10; f(10)'
100
$ fl7 'f : (a; b) -> a * b; f(10; 20)'
200
```

## 即席関数呼び出し

即席関数呼び出し演算子`*func`は、引数として`_`を与えて関数を呼び出す前置演算子である。

```perl:
_ : 50;
f : a -> a * 10;
*f
```

```bash:
$ fl7 '_ : 50; f : a -> a * 10; *f'
500
```

**Tips** この演算子は即席関数演算子`\formula`やパイプ演算子`streamer | formula`など暗黙に識別子`_`を定義する演算子と組み合わせて使うと強力である。

```bash:
$ fl7 '1 .. 5 | *SQRT'
1
1.4142135623730951
1.7320508075688772
2
2.23606797749979
```

## 関数呼び出しパイプ

関数呼び出しパイプ演算子`value => function`は、`value`を`function`に適用する、パイプ系演算子と同等の結合優先度を持つ中置演算子である。

```bash:
$ fl7 '1, 2, 3 => JOIN'
1,2,3
```

これは、以下と同等である。

```bash:
$ fl7 'JOIN(1, 2, 3)'
1,2,3
```

## 中置関数呼び出し

中置関数呼び出し演算子``` left `function` right ```は、関数`function`を、`left`および`right`に対して適用する中置演算子である。

```10 `DIV` 3```は`DIV(10; 3)`と同等である。

```bash:
$ fl7 'DIV(10; 3)'
3
$ fl7 '10 `DIV` 3'
3
```

中置関数呼び出し演算子の結合優先度は、べき乗演算子よりも高い。

```bash:
$ fl7 ' 10 `DIV`  3  ^ 2 '
9
$ fl7 '(10 `DIV`  3) ^ 2 '
9
$ fl7 ' 10 `DIV` (3  ^ 2)'
1
```

## 前置関数呼び出し

前置関数呼び出し演算子``` `function` arg ``は、関数`function`を、`arg`に対して適用する前置演算子である。

``` `SQRT` 4```は`SQRT(4)`と同等である。

```bash:
$ fl7 'SQRT(4)'
2
$ fl7 '`SQRT` 4'
2
```

前置関数呼び出し演算子の結合優先度はそのほかの前置演算子と共通である。

```bash:
$ fl7 '-`SQRT`--4'
-2
```

## コンポジット

コンポジット`123iden`は、数値部`123`と識別子部`iden`を単位のように繋げて記述することで関数`UNIT_iden`の呼び出しができる文法である。
`123`は、1文字以上の半角数字列（`[0-9]+`）もしくは中腹に1個の小数点`.`を含む2文字以上の半角数字列（`[0-9]+\.[0-9]+`）である
`iden`は、識別子に利用可能な文字集合のうち、半角数字である10個を除いたもの（`[a-zA-Z_\u0080-\uFFFF]`）である。

```perl:
UNIT_km : _ -> _ * 1000;
UNIT_㍍ : _ -> _ * 1;

4km + 34㍍
```

```bash:
$ fl7 'UNIT_km : _ -> _ * 1000; UNIT_㍍ : _ -> _ * 1; 4km + 34㍍'
4034
```

### 二項コンポジット

数値部と識別子部の後に更に数値部があってもよい。
ただし、`iden`が`e`もしくは`E`である場合、指数リテラルが優先される。

```perl:
UNIT_div : a, b -> a / b;
UNIT_e : a, b -> a / b;

100div50, 100e50
```

```bash:
$ fl7 'UNIT_div : a, b -> a / b; UNIT_e : a, b -> a / b; 100div50, 100e50'
2
1e+52
```

### 多重コンポジット

数値部で始まり数値部と識別子部が交互に来ていれば、コンポジットはいくらでもつなげることができる。

その場合、コンポジットは**右優先結合**で入れ子状に呼び出される。

```perl:
UNIT_a : [
  1 : a    -> "[$a]";
  2 : a, b -> "[$a, $b]";
];

1a2a3a4, 1a2a3a4a
```

```bash:
$ fl7 'UNIT_a : [ 1 : a -> "[$a]"; 2 : a, b -> "[$a, $b]"; ]; 1a2a3a4, 1a2a3a4a'
[1, [2, [3, 4]]]
[1, [2, [3, [4]]]]
```

**Tips** キロやミリのついた単位関数を作成する際は、第2引数を戻り値に統合すると呼び出しが便利である。

```perl:
UNIT_km : [
  1 : a    -> a * 1000;
  2 : a, b -> a * 1000 + b;
];
UNIT_m : [
  1 : a    -> a * 1;
  2 : a, b -> a * 1 + b;
];
UNIT_mm : [
  1 : a    -> a * 0.001;
  2 : a, b -> a * 0.001 + b;
];

54km13m265mm
```

```bash:
$ fl7 'UNIT_km : [ 1 : a    -> a * 1000; 2 : a, b -> a * 1000 + b; ]; UNIT_m : [ 1 : a    -> a * 1; 2 : a, b -> a * 1 + b; ]; UNIT_mm : [ 1 : a    -> a * 0.001; 2 : a, b -> a * 0.001 + b; ]; 54km13m265mm'
54013.265
```

### 関数名には`UNIT_`がなくてもよい

`UNIT_`付きの関数とそうでない関数が両方存在する場合、前者が優先される。

```perl:
UNIT_f : _ -> _ * 100;
f : _ -> _ * 10;
g : _ -> _ * 10;

7f, 7g
```

```bash:
$ fl7 'UNIT_f : _ -> _ * 100; f : _ -> _ * 10; g : _ -> _ * 10; 7f, 7g'
700
70
```

### 関数は動的名前解決される

ただし、動的名前解決では`UNIT_`を省略することはできない。

```perl:
@{UNIT_f : _ -> _ * 100};

7f
```

静的名前解決される関数が優先される。

```bash:
$ fl7 '@{UNIT_f : _ -> _ * 100}; 7f'
700

$ fl7 '@{UNIT_f : _ -> _ * 100}; f : _ -> _ * 10; 7f'
70
```

# 部分適用

## 左部分適用・右部分適用

左部分適用演算子`func << args`は、`func`の引数列に先頭から`args`を部分適用する中置演算子である。
右部分適用演算子`func >> args`は、`func`の引数列に末尾から`args`を部分適用する中置演算子である。

`args`は、部分適用する引数列を括弧`(` `)`内に`;`区切りで指定する。

```perl:
f : a, b, c, d -> [a, b, c, d];
(  f << (10; 20)  )(30; 40),
(  f >> (10; 20)  )(30; 40),
```

```bash:
$ fl7 'f : a, b, c, d -> [a, b, c, d]; (  f << (10; 20)  )(30; 40), (  f >> (10; 20)  )(30; 40),'
10,20,30,40
30,40,10,20
```

### `(` `)`は省略してもよい

```bash:
$ fl7 'JOIN(1, 2, 3; "|")'
1|2|3
$ fl7 '(JOIN >> "|")(1, 2, 3)'
1|2|3
```

## メソッドアクセス

メソッドアクセス演算子`object::method`は、`object`のメンバ`method`に対して、`object`を左部分適用する**後置演算子**である。

```perl:
{
  m = obj, i -> i * obj.v;
  v = 20;
}::m(5)
```

```bash:
$ fl7 '{m = obj, i -> i * obj.v; v = 20}::m(5)'
100
```

働きとしては、`object::method`は`object.method << object`と等価である。

```perl:
obj : {
  m = _, i -> i * _.v;
  v = 20;
};
obj::m(5),
(obj.m << obj)(5),
obj.m(obj; 5),
```

```bash:
$ fl7 'obj : {m = _, i -> i * _.v; v = 20}; obj::m(5), (obj.m << obj)(5), obj.m(obj; 5)'
100
100
100
```

**Tips** メソッドアクセスは関数呼び出しアクセスとともに後置演算子扱いなので、前置演算子である即席関数`\formula`よりも優先する。

以下のコードの関数`f`は与えられたオブジェクトのメソッド`m`を呼び出して返す関数である。

```perl:
f : \_::m();
obj : {
  m : \_.a;
  a : 50;
};
f(obj)
```

```bash:
$ fl7 'f : \_::m(); obj : {m : \_.a; a : 50}; f(obj)'
50
```

## メソッド風左バインド

メソッドアクセス演算子`object::method`の`method`節が丸括弧だった場合、メソッド風左バインド演算子`value::(function)`となる。
これは左バインド演算子を用いた式`function << value`と同等である。

```perl:
repeat : string, number -> string * number;
"a"::(repeat)(5),
(repeat << "a")(5),
repeat("a"; 5),
```

```bash:
$ fl7 'repeat : string, number -> string * number; "a"::(repeat)(5), (repeat << "a")(5), repeat("a"; 5)'
aaaaa
aaaaa
aaaaa
```