Skip to content

Instantly share code, notes, and snippets.

@sounisi5011
Last active January 1, 2022 11:38
Show Gist options
  • Save sounisi5011/e447909a0774491e4c67844fbf80cdfc to your computer and use it in GitHub Desktop.
Save sounisi5011/e447909a0774491e4c67844fbf80cdfc to your computer and use it in GitHub Desktop.
関数の多重定義とカリー化を両立する言語の案

関数の多重定義とカリー化を両立する言語の案

本当にこれが実現できるかどうかは極めて怪しい。

多重定義とカリー化の両立

// range関数を多重定義で定義
let range =
  (stop: number) -> range(0, stop)
  (start: number, stop: number) -> ...

// 変数xに、`[0, 1, 2, 3, 4, 5]`か「stop引数を受け取って配列を返す関数」の「どちらとしても解釈可能な値」を代入
let x = range(5)

// `[1, 2, 3, 4, 5, 6]`の値を生成
// 変数xの値を配列と解釈して処理
let list1 = x |> map(num -> num + 1)

// `[ [5, 6], [5, 6, 7, 8] ]`の値を生成
// 変数xの値を「stop引数を受け取って配列を返す関数」と解釈して処理
let list2 = [6, 8] |> map(x)

問題点

// 変数xの値をコンソールに表示する。print関数は配列も関数も受け付ける。
// …この場合のxの値は何!?
print(x)

解決策の案

引数の数が同じ多重定義のみ可能とすれば、カリー化と多重定義の両立が可能かもしれない。関数のUnion型として表現できる。

let multi =
  (a: number, b: number)       -> a * b
  (str: string, count: number) -> str.repeat(count)
  (count: number, str: string) -> multi(str, count)

// このdoubleの型は`(number -> number) | (string -> string)`
let double = multi(2)

// 値は`4`
print(double(2))

// 値は`"ベベ"`
print(double("ベ"))

// 値はおそらく`( (b: number): number -> a * b ) | ( (str: string): string -> multi(str, count) )`
print(double)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment