Skip to content
Playground

関数

関数 binding、curried 呼び出し形式、ラムダ、型注釈と effect 注釈をまとめる。 record pattern 引数、method、role constraint も扱う。

宣言

yulang
my add x y = x + y
our greet name = "hello, " + name
pub double x = x + x

binding の左辺は pattern である。 pattern が直接の名前のとき、その後ろに続く pattern が関数引数になる。

キーワード公開範囲
my現在の module / block で private
our囲んでいる companion から見える(method の標準形)
pubmodule 境界をまたいで export される

引数と curry

yulang
my add x y = x + y
my add_curried = \x -> \y -> x + y

複数引数の binding は左から右に curry される。 add 1y を待つ関数である。 裸 application(add 1 2)でも C 風(add(1, 2))でも呼べる。 両方とも内部は curried application に lower される。

yulang
my inc = add 1
inc 41                 // 42

呼び出しの形

yulang
add 1 2                // 裸 application
add(1, 2)              // C 風呼び出し
add: 1                 // colon application(2 引数関数では稀)

裸 application が標準形である。 視覚的に引数をまとめたいときや、裸だと token が流れて読みづらいときに C 風を使う。

ラムダ

yulang
my inc = \x -> x + 1
my add = \x y -> x + y

(inc 1, add 1 2)

ラムダは \ で始まる。 複数引数のラムダ \x y -> ... は binding の頭と同じく curry される。

ラムダの引数自体も pattern である。

yulang
my add_pair = \(x, y) -> x + y
my greet = \{ name } -> "hello, " + name

(add_pair (1, 2), greet { name: "world" })

特別な lambda 形式

\sub

\sub pattern -> body は、body に早期 return scope を持つ関数を作る。 return value はその関数の現在の呼び出しから抜ける。

yulang
my step = \sub n ->
    if n > 0: return (n + 1)
    0

say (step 41)

\case

\case: は、引数を列挙した arm と照合する 1 引数関数を作る。

yulang
my classify = \case:
    0 -> "zero"
    _ -> "other"

say (classify 5)

\catch

\catch: は 1 引数の handler 関数を作る。 引数は、列挙した operation arm と value arm で処理する effectful computation である。

yulang
act signal:
    our ask: () -> int

my answer = \catch:
    signal::ask(), k -> k 42
    value -> value

say (answer signal::ask())

型注釈

yulang
my double(x: int): int = x + x
my mark(label: str, value: 'a): 'a = value

引数と戻り型の注釈は任意である。 省略すると推論が埋める。 API 境界のドキュメント、そのままだと開いてしまう generic の固定、曖昧さの解消、のいずれかに使う。

effect 付きの注釈

yulang
act console:
    our read: () -> str

my ask(): [console] str = console::read()
my run_console(action: [console] 'a): 'a = catch action:
    console::read(), k -> run_console (k "42")

run_console (ask())

戻り型の角括弧形は effect row である。 [console] str は「str を返し、console effect を要求する」という意味。 [console; 'e] 'a のように tail 変数を入れると他の effect も開いたままになる。

オプショナル引数としての record pattern

yulang
my area {width = 1, height = 2} = width * height

area { width: 3 }
area { width: 3, height: 4 }
area {}

default 付きの record pattern は、呼び出し側で各 field を省略可能にする。 default は左から右へ評価され、後ろの default は前の field を参照できる。

yulang
my f {a = 1, b = a + 1} = (a, b)

with: 経由の method

yulang
struct point { x: int, y: int } with:
    our p.norm2 = p.x * p.x + p.y * p.y
    our p.scale n = point { x: p.x * n, y: p.y * n }

with: 内の our recv.name args = body で、value.name args で呼べる method を定義する。 receiver recv は単なる名前(読みやすい名前を選ぶ)。

role の method

yulang
role Add 'a:
    our a.add: 'a -> 'a

impl Add int:
    our x.add y = std::int::add x y

role の method ヘッダーは with: と同じ receiver 形を使う。 : の後ろは receiver を当てた後の関数型(Add なら a.add は相手側の引数を取る関数)。

where 句

yulang
my twice(x: 'a) =
    where 'a: Add
    x.add x

where 'a: Role は binding の type variable に role constraint を追加する。 binding の推論型にその constraint が伝播するので、twice 1 の呼び出しは Add int を要求する。

where 句は role の body や impl の body にも書ける。 role の body に書くと各 method に継承される。 impl の body に書くと、その impl 候補の前提条件になる。

ファイルの検査

bash
yulang check examples/showcase.yu
# repo から動かす場合
cargo run -q -p yulang -- check examples/showcase.yu

check はファイルを検査する。 成功時は何も出力せず、失敗時だけ diagnostic を出す。 compiler IR には、推論された binding 型が含まれる。 residual な type variable(αβ、…)と role constraint(Add<α> => ...)も含まれる。 yulang dump examples/showcase.yu --poly で確認できる。

関連ページ

Yulang