基礎
関数は、型名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個の引数を与えて呼び出す式である。
$ 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
には関数の本文を記述する。
関数の本文では、引数を参照できる。
() -> 10
(a) -> a
(a; b; c) -> a * b * c
呼び出し時の引数チェック
ラムダ式で生成された関数は、生成時に指定された個数の引数でしか呼び出すことはできない。
引数列の区切り文字は,
であってもよい
(a, b, c) -> a * b * c
引数列を囲う(
)
は省略してもよい
a, b, c -> a * b * c
ただし、引数が0個の場合や区切り文字が;
の場合は簡単には適用できない。
Tips この記法を使うと変数への代入時に括弧が要らなくなる。
f : a, b, c -> a * b * c;
即席関数
即席関数は、即席関数演算子\formula
によって関数を生成する式である。
即席関数演算子は、そのほかの前置演算子と等しい結合優先度を持つ前置演算子である。
formula
には関数の本文を記述する。
\50
$ fl7 '( \50 )()'
50
即席関数は何個の引数でも呼び出せる
$ fl7 '( \50 )(1; 2; 3; 4; 5)'
50
_
で第一引数を参照できる
ただし、第一引数が存在しない場合はNULLが格納されている。
$ fl7 '( \_ )(50)'
50
$ fl7 '( \_ )()'
NULL
Tips 前置演算子の結合優先度は後置演算子の後なので、第一引数のアクセサをコンパクトに記述できる。
次の例は、関数を与えると50に適用して返す関数fに、数値を10倍する関数を適用する例である。
$ fl7 'f : \_(50); f(a -> a * 10)'
500
__
で引数列全体を参照できる
$ fl7 '( \__ )()'
{LENGTH:[FluoriteFunction]}
$ fl7 '( \__ )(10)'
{0:10;LENGTH:[FluoriteFunction]}
$#__
で引数の個数、__.0
で最初の引数が得られる。
$ fl7 '( \$#__ )(10; 20; 30; 40; 50)'
5
$ fl7 '( \__.0 )(10; 20; 30; 40; 50)'
10
配列
配列を関数として呼び出すと、呼び出し時の引数の個数に応じた要素の値が呼び出される。
f : [
0 : () -> 1;
1 : a -> a * 10;
2 : a, b -> a * b;
];
f(), f(5), f(5; 7)
$ fl7 'f : [0 : () -> 1; 1 : a -> a * 10; 2 : a, b -> a * b]; f(), f(5), f(5; 7)'
1
50
35
オブジェクト
オブジェクトを関数として呼び出すと、CALL
メソッドが呼び出される。
obj : {
val : 3;
CALL : _, a, b -> _.val * a * b;
};
obj(5; 7)
$ fl7 'obj : {val : 3; CALL : _, a, b -> _.val * a * b}; obj(5; 7)'
105
正規表現
正規表現を関数として呼び出すと、マッチが行われる。
$ fl7 '/-(.)-/("-g-").1'
g
$ fl7 '"abc", "123", "abc123" | */^\d+$/'
NULL
123
NULL
ストリーマ
正規表現を関数として呼び出すと、各要素の関数呼び出しのストリーマ結合になる。
$ 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
は省略される。
f0 : () -> 1;
f1 : (a) -> a * 10;
f2 : (a; b) -> a * b;
f0(), f1(), f2(10; 20)
$ fl7 'f : () -> 1; f()'
1
$ fl7 'f : (a) -> a * 10; f(10)'
100
$ fl7 'f : (a; b) -> a * b; f(10; 20)'
200
即席関数呼び出し
即席関数呼び出し演算子*func
は、引数として_
を与えて関数を呼び出す前置演算子である。
_ : 50;
f : a -> a * 10;
*f
$ fl7 '_ : 50; f : a -> a * 10; *f'
500
Tips この演算子は即席関数演算子\formula
やパイプ演算子streamer | formula
など暗黙に識別子_
を定義する演算子と組み合わせて使うと強力である。
$ fl7 '1 .. 5 | *SQRT'
1
1.4142135623730951
1.7320508075688772
2
2.23606797749979
関数呼び出しパイプ
関数呼び出しパイプ演算子value => function
は、value
をfunction
に適用する、パイプ系演算子と同等の結合優先度を持つ中置演算子である。
$ fl7 '1, 2, 3 => JOIN'
1,2,3
これは、以下と同等である。
$ fl7 'JOIN(1, 2, 3)'
1,2,3
中置関数呼び出し
中置関数呼び出し演算子left `function` right
は、関数function
を、left
およびright
に対して適用する中置演算子である。
10 `DIV` 3
はDIV(10; 3)
と同等である。
$ fl7 'DIV(10; 3)'
3
$ fl7 '10 `DIV` 3'
3
中置関数呼び出し演算子の結合優先度は、べき乗演算子よりも高い。
$ 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)
と同等である。
$ fl7 'SQRT(4)'
2
$ fl7 '`SQRT` 4'
2
前置関数呼び出し演算子の結合優先度はそのほかの前置演算子と共通である。
$ 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]
)である。
UNIT_km : _ -> _ * 1000;
UNIT_㍍ : _ -> _ * 1;
4km + 34㍍
$ fl7 'UNIT_km : _ -> _ * 1000; UNIT_㍍ : _ -> _ * 1; 4km + 34㍍'
4034
二項コンポジット
数値部と識別子部の後に更に数値部があってもよい。
ただし、iden
がe
もしくはE
である場合、指数リテラルが優先される。
UNIT_div : a, b -> a / b;
UNIT_e : a, b -> a / b;
100div50, 100e50
$ fl7 'UNIT_div : a, b -> a / b; UNIT_e : a, b -> a / b; 100div50, 100e50'
2
1e+52
多重コンポジット
数値部で始まり数値部と識別子部が交互に来ていれば、コンポジットはいくらでもつなげることができる。
その場合、コンポジットは右優先結合で入れ子状に呼び出される。
UNIT_a : [
1 : a -> "[$a]";
2 : a, b -> "[$a, $b]";
];
1a2a3a4, 1a2a3a4a
$ fl7 'UNIT_a : [ 1 : a -> "[$a]"; 2 : a, b -> "[$a, $b]"; ]; 1a2a3a4, 1a2a3a4a'
[1, [2, [3, 4]]]
[1, [2, [3, [4]]]]
Tips キロやミリのついた単位関数を作成する際は、第2引数を戻り値に統合すると呼び出しが便利である。
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
$ 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_
付きの関数とそうでない関数が両方存在する場合、前者が優先される。
UNIT_f : _ -> _ * 100;
f : _ -> _ * 10;
g : _ -> _ * 10;
7f, 7g
$ fl7 'UNIT_f : _ -> _ * 100; f : _ -> _ * 10; g : _ -> _ * 10; 7f, 7g'
700
70
関数は動的名前解決される
ただし、動的名前解決ではUNIT_
を省略することはできない。
@{UNIT_f : _ -> _ * 100};
7f
静的名前解決される関数が優先される。
$ fl7 '@{UNIT_f : _ -> _ * 100}; 7f'
700
$ fl7 '@{UNIT_f : _ -> _ * 100}; f : _ -> _ * 10; 7f'
70
部分適用
左部分適用・右部分適用
左部分適用演算子func << args
は、func
の引数列に先頭からargs
を部分適用する中置演算子である。
右部分適用演算子func >> args
は、func
の引数列に末尾からargs
を部分適用する中置演算子である。
args
は、部分適用する引数列を括弧(
)
内に;
区切りで指定する。
f : a, b, c, d -> [a, b, c, d];
( f << (10; 20) )(30; 40),
( f >> (10; 20) )(30; 40),
$ 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
(
)
は省略してもよい
$ fl7 'JOIN(1, 2, 3; "|")'
1|2|3
$ fl7 '(JOIN >> "|")(1, 2, 3)'
1|2|3
メソッドアクセス
メソッドアクセス演算子object::method
は、object
のメンバmethod
に対して、object
を左部分適用する後置演算子である。
{
m = obj, i -> i * obj.v;
v = 20;
}::m(5)
$ fl7 '{m = obj, i -> i * obj.v; v = 20}::m(5)'
100
働きとしては、object::method
はobject.method << object
と等価である。
obj : {
m = _, i -> i * _.v;
v = 20;
};
obj::m(5),
(obj.m << obj)(5),
obj.m(obj; 5),
$ 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
を呼び出して返す関数である。
f : \_::m();
obj : {
m : \_.a;
a : 50;
};
f(obj)
$ fl7 'f : \_::m(); obj : {m : \_.a; a : 50}; f(obj)'
50
メソッド風左バインド
メソッドアクセス演算子object::method
のmethod
節が丸括弧だった場合、メソッド風左バインド演算子value::(function)
となる。
これは左バインド演算子を用いた式function << value
と同等である。
repeat : string, number -> string * number;
"a"::(repeat)(5),
(repeat << "a")(5),
repeat("a"; 5),
$ fl7 'repeat : string, number -> string * number; "a"::(repeat)(5), (repeat << "a")(5), repeat("a"; 5)'
aaaaa
aaaaa
aaaaa