無名関数
無名関数は、関数オブジェクトを名付けずその場で生成するための文法です。
# `->`は無名関数演算子
# same as `f x, y = x + y`
f = (x, y) -> x + y
# same as `g(x, y: Int): Int = x + y`
g = (x, y: Int): Int -> x + y
引数が1つの場合は()
を省略できます。
assert [1, 2, 3].map_collect(i -> i + 1) == [2, 3, 4]
assert ((i, j) -> [i, j])(1, 2) == [1, 2]
下の場合0..9, (i -> ...)
であって(0..9, i) -> ...
ではありません。
->
は左辺に一つだけ引数をとります。複数の引数は一つのタプルとして受け取ります。
for 0..9, i: Int ->
...
無名関数では、空白による構文解釈の差異が存在します。
# この場合は`T(() -> Int)`と解釈される
i: T () -> Int
# この場合は(U()) -> Intと解釈される
k: U() -> Int
無名関数は引数なしでも使えます。
# `=>`は無名プロシージャ演算子
p! = () => print! "`p!` was called"
# `() ->`, `() =>`には`do`, `do!`という糖衣構文がある
# p! = do! print! "`p!` was called"
p!() # `p!` was called
引数なし関数は遅延初期化に使えます。
time = import "time"
date = import "datetime"
now = if! True:
do!:
time.sleep! 1000
date.now!()
do date.new("1970", "1", "1", "00", "00")
型付け、パターンマッチもできます。このため、match
関数はほとんど無名関数の力で実現されています。
match
関数の引数に与える無名関数は上から順番にトライされます。なので、上の方は特殊なケースを、下に行くほど一般的なケースを記述する必要があります。順番を間違えると(可能な限り)コンパイラがWarningを出します。
n = (Complex or Ratio or Int).sample!()
i = match n:
PI -> PI # 定数PIに等しい場合
(i: 1..10) -> i # 1~10のIntの場合
(i: Int) -> i # Intの場合
(c: Complex) -> c.real() # Complexの場合。Int < Complexだが、フォールバックできる
_ -> panic "cannot convert to Int" # 以上のいずれにも該当しない場合。matchは全パターンを網羅していなくてはならない
エラーハンドリングも?
かmatch
を使用して行うのが一般的です。
res: ParseResult Int
match res:
i: Int -> i
err: Error -> panic err.msg
res2: Result Int, Error
match res2:
ok: Not Error -> log Typeof ok
err: Error -> panic err.msg
無名多相関数
# same as id|T| x: T = x
id = |T| x: T -> x