It is well-known that closures and objects are equivalent. So are actors. Which one is the most fundamental?
よく知られたように、クロージャとオブジェクトは等価です。アクターも同様です。どの概念が最も基本的なのでしょうか?
Closures vs Objects
2024/02/19(月) 20:39:15.91ID:VT95BnI9
2024/02/19(月) 20:49:06.93ID:VT95BnI9
A closure is a function with state in the local scope.
An object also has methods and state which belong to its instance.
These are compatible with each other.
クロージャはローカル・スコープに状態をもつ関数です。
オブジェクトもまたそのインスタンスに属するメソッドと状態を持ちます。
これらは互いに互換性があります。
An object also has methods and state which belong to its instance.
These are compatible with each other.
クロージャはローカル・スコープに状態をもつ関数です。
オブジェクトもまたそのインスタンスに属するメソッドと状態を持ちます。
これらは互いに互換性があります。
2024/02/20(火) 09:36:12.34ID:fQy0X2aE
オブジェクトは複数のメソッドを持てる
クロージャは関数をひとつしか返せない
オブジェクトの勝ち
クロージャは関数をひとつしか返せない
オブジェクトの勝ち
2024/02/20(火) 11:01:18.21ID:BFMbzAij
>>3
ハッシュテーブルに関数を追加して返すことで、複数のメソッドを返すことが可能
より柔軟に、オブジェクトとそれを操作する関数の組を返すこともできるし、無限個のメソッドをもったオブジェクトだって作れる
これらは書く対象によって使い分ければよいのであって、オブジェクトにメソッドが属しているのが常に最適とは限らない
たとえばイベントハンドラにコールバック関数として渡すような場合は、ひとつの関数として取得できたほうが便利
ハッシュテーブルに関数を追加して返すことで、複数のメソッドを返すことが可能
より柔軟に、オブジェクトとそれを操作する関数の組を返すこともできるし、無限個のメソッドをもったオブジェクトだって作れる
これらは書く対象によって使い分ければよいのであって、オブジェクトにメソッドが属しているのが常に最適とは限らない
たとえばイベントハンドラにコールバック関数として渡すような場合は、ひとつの関数として取得できたほうが便利
2024/02/20(火) 23:29:16.13ID:0cXn/136
クロージャのほうがprimitive
今時、高階関数やイテレータを書くのにわざわざデザインパターンとか使いたいかって話
クラスは、レキシカル環境つきオブジェクトだけが欲しくても必ず新しい名前空間が作られるし、単品で購入できない福袋みたいなもん
今時、高階関数やイテレータを書くのにわざわざデザインパターンとか使いたいかって話
クラスは、レキシカル環境つきオブジェクトだけが欲しくても必ず新しい名前空間が作られるし、単品で購入できない福袋みたいなもん
2024/02/21(水) 05:55:14.17ID:j79lZ4PO
二変数以上の関数のほとんどは、どの引数のオブジェクトに属しているともアプリオリには言えないし、オブジェクト指向は不自然
オブジェクトと引数は別物だし、もし関数を特定のオブジェクトに属するようにしたいなら、クロージャでラップすれば簡単にできる
オブジェクトと引数は別物だし、もし関数を特定のオブジェクトに属するようにしたいなら、クロージャでラップすれば簡単にできる
2024/02/21(水) 05:56:37.93ID:j79lZ4PO
二変数以上の関数のほとんどは、どの引数のオブジェクトに属しているともアプリオリには言えないし、オブジェクト指向は不自然
オブジェクトと関数は別物だし、もし関数を特定のオブジェクトに属するようにしたいなら、クロージャでラップすれば簡単にできる
オブジェクトと関数は別物だし、もし関数を特定のオブジェクトに属するようにしたいなら、クロージャでラップすれば簡単にできる
2024/02/21(水) 10:09:33.92ID:HBySQ9lj
2変数関数をクロージャにラップして1変数関数にしても、メソッドチェーンはできないよね
2024/02/21(水) 10:29:18.43ID:Cg6r5DK9
[1, 2, 3, 4, 5]にメソッドが属してれば
[1, 2, 3, 4, 5]
.filter(hoge) # ←戻り値もオブジェクト
.map(piyo) # ←これも
.sum()
みたいにできるけど、配列がオブジェクトじゃなかったら
map([1, 2, 3, 4, 5], hoge)
の戻り値はただの配列なので、繰り返し関数適用するには、Lispみたいな醜い入れ子にするしかない
sum(
map(
filter([1, 2, 3, 4, 5], hoge),
piyo))
[1, 2, 3, 4, 5]
.filter(hoge) # ←戻り値もオブジェクト
.map(piyo) # ←これも
.sum()
みたいにできるけど、配列がオブジェクトじゃなかったら
map([1, 2, 3, 4, 5], hoge)
の戻り値はただの配列なので、繰り返し関数適用するには、Lispみたいな醜い入れ子にするしかない
sum(
map(
filter([1, 2, 3, 4, 5], hoge),
piyo))
2024/02/21(水) 12:32:59.23ID:pWazjr0Z
>>8-9
これでどうよ
chain = (obj) => {
return (f, ...args) => {
if (!f) return obj
return chain(f(obj, ...args))
}
}
chain([1, 2, 3, 4, 5])(
filter, (x) => x % 2)(
map, (x) =>x * x)(
sum)()
// => 35
これでどうよ
chain = (obj) => {
return (f, ...args) => {
if (!f) return obj
return chain(f(obj, ...args))
}
}
chain([1, 2, 3, 4, 5])(
filter, (x) => x % 2)(
map, (x) =>x * x)(
sum)()
// => 35
2024/02/21(水) 15:43:45.17ID:im/wtuEl
一時期メタプログラミングとかいって、動的にクラスやメソッドを作れるのがすごいって言われてたけど、クロージャをデータ構造として使うならそれは自明にできることでは
2024/02/21(水) 16:28:56.20ID:4iB0jwLo
やり方が複数ある場合は、一番綺麗に書けるコードを採用するのが基本
2024/02/21(水) 22:54:29.50ID:DX/jvS2m
入れ子にしなくても関数合成でいいのでは?
メソッドチェーンっぽく書くには
Reverse-application operatorってのもあるけど
個人的には関数合成のほうがスッキリしててすこ
https://ideone.com/gCWxLP
let hoge n = n mod 2 = 1
let piyo = ( * ) 2
let () = print_int (List.fold_left (+) 0 (List.map piyo (List.filter hoge [1;2;3;4;5])))
(* function composition *)
let (<<) f g x = f (g x)
let f = print_int << List.fold_left (+) 0 << List.map piyo << List.filter hoge
let () = f [1;2;3;4;5]
let (>>) f g x = g (f x)
let f = List.filter hoge >> List.map piyo >> List.fold_left (+) 0 >> print_int
let () = f [1;2;3;4;5]
(* @@ Application operator *)
let () = print_int @@ List.fold_left (+) 0 @@ List.map piyo @@ List.filter hoge [1;2;3;4;5]
(* |> Reverse-application operator *)
let () = [1;2;3;4;5] |> List.filter hoge |> List.map piyo |> List.fold_left (+) 0 |> print_int
メソッドチェーンっぽく書くには
Reverse-application operatorってのもあるけど
個人的には関数合成のほうがスッキリしててすこ
https://ideone.com/gCWxLP
let hoge n = n mod 2 = 1
let piyo = ( * ) 2
let () = print_int (List.fold_left (+) 0 (List.map piyo (List.filter hoge [1;2;3;4;5])))
(* function composition *)
let (<<) f g x = f (g x)
let f = print_int << List.fold_left (+) 0 << List.map piyo << List.filter hoge
let () = f [1;2;3;4;5]
let (>>) f g x = g (f x)
let f = List.filter hoge >> List.map piyo >> List.fold_left (+) 0 >> print_int
let () = f [1;2;3;4;5]
(* @@ Application operator *)
let () = print_int @@ List.fold_left (+) 0 @@ List.map piyo @@ List.filter hoge [1;2;3;4;5]
(* |> Reverse-application operator *)
let () = [1;2;3;4;5] |> List.filter hoge |> List.map piyo |> List.fold_left (+) 0 |> print_int
14デフォルトの名無しさん
2024/02/22(木) 01:30:07.21ID:seCGgTJE Forth で書いてよ
2024/02/22(木) 08:01:15.94ID:5dknMZXg
>>13
カリー化のなせる技やね
カリー化のなせる技やね
2024/02/22(木) 08:40:34.15ID:GWomKHpC
chainl = (obj) => {
return (f, arg) => {
if (!f) return obj
return chainl(f(arg, obj))
}
}
cons = (x, xs) => [x, xs]
foreach = (lst, f) => {
if(!lst) return
[x, xs] = lst
f(x)
foreach(f, xs)
}
linkedList =
chainl(null)(
cons, 1)(
cons, 2)(
cons, 3)()
chainl(linkedList)(foreach, console.log)()
// 3
// 2
// 1
いろいろ書けるんだな
return (f, arg) => {
if (!f) return obj
return chainl(f(arg, obj))
}
}
cons = (x, xs) => [x, xs]
foreach = (lst, f) => {
if(!lst) return
[x, xs] = lst
f(x)
foreach(f, xs)
}
linkedList =
chainl(null)(
cons, 1)(
cons, 2)(
cons, 3)()
chainl(linkedList)(foreach, console.log)()
// 3
// 2
// 1
いろいろ書けるんだな
2024/02/22(木) 10:55:42.37ID:2PGen9gt
カリー化もクロージャと可変長引数があればできるね
currying = (f, ...args) => (...rest) => f(...args, ...rest)
currying = (f, ...args) => (...rest) => f(...args, ...rest)
2024/02/22(木) 11:04:45.60ID:2PGen9gt
これで、mapなどが
map(f, col)
と、関数を先にとる形でも、>>16のchainlを用いて
chainl([1, 2, 3, 4, 5])(
currying(filter, (x) => x % 2))(
currying(map, (x) => x * x))(
sum)()
と書けるわけか
map(f, col)
と、関数を先にとる形でも、>>16のchainlを用いて
chainl([1, 2, 3, 4, 5])(
currying(filter, (x) => x % 2))(
currying(map, (x) => x * x))(
sum)()
と書けるわけか
2024/02/22(木) 11:11:29.91ID:2PGen9gt
いや、単にchainlを
chainl = (obj) => {
return (f, ...arg) => {
if (!f) return obj
return chainl(f(...arg, obj))
}
}
とすればいいのか
chainl = (obj) => {
return (f, ...arg) => {
if (!f) return obj
return chainl(f(...arg, obj))
}
}
とすればいいのか
2024/02/22(木) 12:04:47.68ID:0KLGqPZR
クロージャの真価はコンテキストを導入できること
(let ((a 1) (b 2)) (+ a b))
((lambda (a b) (+ a b)) 1 2)
は等価
なので、上のa + bの変わりに関数を返却すれば独立したスコープの状態をもつ何かを作れる
クラスベースのオブジェクト指向でも同様だが、そのようなコンテキストのテンプレート(= class)は静的にしか作れない
(let ((a 1) (b 2)) (+ a b))
((lambda (a b) (+ a b)) 1 2)
は等価
なので、上のa + bの変わりに関数を返却すれば独立したスコープの状態をもつ何かを作れる
クラスベースのオブジェクト指向でも同様だが、そのようなコンテキストのテンプレート(= class)は静的にしか作れない
21デフォルトの名無しさん
2024/02/22(木) 12:15:29.98ID:Q3haYGVO 静的なほうがバグの発見は早そう
2024/02/22(木) 13:03:51.54ID:BdBf3uc1
なんでも自由を許すと無秩序になる
>>10だって、シグネチャを無視することが前提の設計になってる
(最後に結果を呼び出す時は第一引数のfを省略する)
TypeScriptが使われるのもそれが理由
今やPythonやRubyにも型がある
>>10だって、シグネチャを無視することが前提の設計になってる
(最後に結果を呼び出す時は第一引数のfを省略する)
TypeScriptが使われるのもそれが理由
今やPythonやRubyにも型がある
23デフォルトの名無しさん
2024/02/22(木) 13:23:57.40ID:v9QmWW2c2024/02/22(木) 13:24:08.05ID:WrtsfcL/
型なんて、プログラマがちまちま書かずとも、コンパイラや型チェッカが実行前に検査してくれればいいと思う
2024/02/22(木) 15:02:53.21ID:bbu+R1aP
currying = (f) => {
args = []
apply = (a) => {
if (a === undefined) return f(...args)
args.push(a)
return apply
}
return apply
}
args = []
apply = (a) => {
if (a === undefined) return f(...args)
args.push(a)
return apply
}
return apply
}
2024/02/22(木) 18:39:34.82ID:SfbO+Gz+
クロージャはポリモーフィズムができない
オブジェクト指向言語ではたとえば比較演算子の動作を型によって変えられる
a.compare(b)とソースコードのどこに書いても、aの型に応じて適切にcompareの動きが選択される
変数の型によって実行する関数を変えるにはどうする?
まさか関数定義に型による条件分岐をいちいち書くわけじゃあるまいし
オブジェクト指向言語ではたとえば比較演算子の動作を型によって変えられる
a.compare(b)とソースコードのどこに書いても、aの型に応じて適切にcompareの動きが選択される
変数の型によって実行する関数を変えるにはどうする?
まさか関数定義に型による条件分岐をいちいち書くわけじゃあるまいし
27デフォルトの名無しさん
2024/02/22(木) 19:07:57.79ID:v9QmWW2c class構文が入るまでどうやってJSでクラスを定義してたのか調べれば分かるよ
2024/02/22(木) 19:20:20.77ID:bu5i+qrs
>>27
a.hoge()のようにしてダックタイピングするなら当然できる
hogeがa(or a.prototype)に属さないただの関数の場合でも
hogeの中で型による条件分岐を書く以外の方法でできるか
a.hoge()のようにしてダックタイピングするなら当然できる
hogeがa(or a.prototype)に属さないただの関数の場合でも
hogeの中で型による条件分岐を書く以外の方法でできるか
2024/02/22(木) 19:30:27.02ID:coyprm7i
30デフォルトの名無しさん
2024/02/22(木) 19:41:55.54ID:v9QmWW2c >>28
なんて?
なんて?
2024/02/22(木) 20:46:51.05ID:5LGf2QVl
>>26,28
a, bではなくcompareのほうを、状態をもった関数オブジェクトとして生成する
一例として、
compareのクロージャには、「型名=>その型の引数を受け取った時に呼び出す関数」のテーブルを保持する
そのテーブルに関数を動的に登録するための関数を作成する
例:
IComparable = () => {
dispatch = {}
compare = (self, other) => { /*dispatchテーブルから関数を検索して実行*/ }
implement = (type, fn) => { /* dispatchテーブルにfnを登録 */ }
return [compare, implement]
}
もちろんdispatchの条件は型名じゃなくても、別の判定用関数を用意してもいい
a, bではなくcompareのほうを、状態をもった関数オブジェクトとして生成する
一例として、
compareのクロージャには、「型名=>その型の引数を受け取った時に呼び出す関数」のテーブルを保持する
そのテーブルに関数を動的に登録するための関数を作成する
例:
IComparable = () => {
dispatch = {}
compare = (self, other) => { /*dispatchテーブルから関数を検索して実行*/ }
implement = (type, fn) => { /* dispatchテーブルにfnを登録 */ }
return [compare, implement]
}
もちろんdispatchの条件は型名じゃなくても、別の判定用関数を用意してもいい
2024/02/22(木) 20:49:14.36ID:5LGf2QVl
インタフェースの実装は、型定義に書くよりも使用時に動的にできた方が自然だ
たとえば木構造にイテレータを実装するとして、深さ優先探索にするのか幅優先探索にするのかは、その時々によって変わる。木構造の定義だけからは決まらない
たとえば木構造にイテレータを実装するとして、深さ優先探索にするのか幅優先探索にするのかは、その時々によって変わる。木構造の定義だけからは決まらない
2024/02/22(木) 22:14:42.54ID:BzyFji/L
最近のフレームワークはどんどん脱オブジェクト指向・関数型化してないか?
Pythonのフレームワークは機能のMixinは継承ではなくデコレータ(ようはクロージャ)によるものが多い
Reactなんか思想は元々関数型的だったけど、ついにクラスコンポーネントやめちゃった
Pythonのフレームワークは機能のMixinは継承ではなくデコレータ(ようはクロージャ)によるものが多い
Reactなんか思想は元々関数型的だったけど、ついにクラスコンポーネントやめちゃった
2024/02/23(金) 00:14:17.41ID:vwgp24xa
cps = (f) => (...args) => args.pop()(f(...args))
eq = cps((a, b) => a === b)
sub = cps((a, b) => a - b)
mul = cps((a, b) => a * b)
fact = (n, k) => {
eq(n, 0, (isZero) => {
if(isZero) {
return k(1)
}
else {
return sub(n, 1, (prevn) =>{
fact(prevn, (prevf) => {
mul(n, prevf, k)
})
})
}
})
}
fact(5, console.log)
eq = cps((a, b) => a === b)
sub = cps((a, b) => a - b)
mul = cps((a, b) => a * b)
fact = (n, k) => {
eq(n, 0, (isZero) => {
if(isZero) {
return k(1)
}
else {
return sub(n, 1, (prevn) =>{
fact(prevn, (prevf) => {
mul(n, prevf, k)
})
})
}
})
}
fact(5, console.log)
2024/02/23(金) 13:52:03.15ID:P8ZW/vvm
Closures are functions with contexts.
Objects are structures with contexts.
A structure can have functions as its member, and vice versa.
So both are equal.
Objects are structures with contexts.
A structure can have functions as its member, and vice versa.
So both are equal.
2024/02/23(金) 19:20:29.47ID:mZKLNS+O
オブジェクトよりも、クロージャよりも、第一級継続のほうが強い
37デフォルトの名無しさん
2024/02/24(土) 00:22:58.31ID:PF21lJOY >>36
パフォーマンスは?
パフォーマンスは?
2024/02/24(土) 06:28:09.62ID:dndVDS6q
39デフォルトの名無しさん
2024/02/24(土) 11:30:44.99ID:PF21lJOY >>38
その回答、第一級継続関係無いやん。
その回答、第一級継続関係無いやん。
2024/02/24(土) 21:14:52.39ID:4BGFiybC
オブジェクトとクロージャが使えることは、コードブロック(+ ローカル変数)を第一級オブジェクトに持っているのだと思える
継続が第一級オブジェクトなのは、プログラム実行時の任意の状態が第一級オブジェクトということ
継続が第一級オブジェクトなのは、プログラム実行時の任意の状態が第一級オブジェクトということ
41デフォルトの名無しさん
2024/02/24(土) 21:42:30.15ID:fbMBQzh4 >>40
継続使う場合のパフォーマンスは?
継続使う場合のパフォーマンスは?
2024/02/25(日) 00:23:07.77ID:bNSutqDu
2024/02/25(日) 09:10:18.70ID:zl+9FS4I
継続はクロージャで表現されるけど、オブジェクトとクロージャが同値なら、オブジェクトによる表現もできるの?
44デフォルトの名無しさん
2024/02/25(日) 10:52:31.35ID:5QMstwYR : fact dup
1 = if
drop
else
dup 1- rot rot *
swap recurse
then
;
1 5 fact cr .
1 = if
drop
else
dup 1- rot rot *
swap recurse
then
;
1 5 fact cr .
2024/02/25(日) 11:03:04.14ID:O8qt4uJC
インタフェースが静的に決まれば保守性はおちないと思う
46デフォルトの名無しさん
2024/02/25(日) 11:17:17.62ID:azDE+Je3 近年まれにみる良スレ
2024/02/25(日) 11:28:28.39ID:PRxvM5Hr
>>31
これ継承の問題点を全部解消してる上に継承よりも強力だな
これ継承の問題点を全部解消してる上に継承よりも強力だな
48デフォルトの名無しさん
2024/02/25(日) 16:27:53.33ID:4fScDWQR ハァ?
2024/02/25(日) 16:36:21.69ID:wVCQJTWx
2024/02/25(日) 17:38:12.08ID:EvE7ghxV
2024/02/25(日) 17:55:13.30ID:BE8i65fG
>>43
できるだろうけど、継続自体が手続き/関数的な概念なので、オブジェクトによる表現をするメリットは少ないと思う
できるだろうけど、継続自体が手続き/関数的な概念なので、オブジェクトによる表現をするメリットは少ないと思う
2024/02/25(日) 19:51:34.20ID:O9l+7I5E
継続とコルーチンなら、継続のほうがprimitiveなの?
2024/02/25(日) 20:50:19.80ID:ZY2lsWgE
>>52
継続が第一級なら保存した継続を何度も呼び出せるが、コルーチンはyieldしたらもうその時点には戻れないので、継続のほうが根本的
継続が第一級なら保存した継続を何度も呼び出せるが、コルーチンはyieldしたらもうその時点には戻れないので、継続のほうが根本的
2024/02/26(月) 12:34:53.26ID:9feDQZG5
なんでもクロージャだと戻り値全部関数だけど、型情報を持つことはできる?
ディスパッチするのに必要だよね?
ディスパッチするのに必要だよね?
2024/02/26(月) 15:19:09.55ID:L4EYeETV
>>54
type属性をもったオブジェクトとして返却すればいいんじゃないんですかね
それを毎回書きたくないなら、生成用関数を受け取って新しい生成用関数を返す関数
makeConstructor = (f) => (type, ...args) => {type: type, value: f(...args)}
みたいなのを使ってみてはどうでしょうか
type属性をもったオブジェクトとして返却すればいいんじゃないんですかね
それを毎回書きたくないなら、生成用関数を受け取って新しい生成用関数を返す関数
makeConstructor = (f) => (type, ...args) => {type: type, value: f(...args)}
みたいなのを使ってみてはどうでしょうか
2024/02/26(月) 18:51:01.76ID:k7j7cG9/
>>55
これ、オブジェクトからtype属性つきオブジェクトへの関数、を持ち上げる関数書けばモナドになるから自動的に変換できるんだな
これ、オブジェクトからtype属性つきオブジェクトへの関数、を持ち上げる関数書けばモナドになるから自動的に変換できるんだな
2024/02/26(月) 22:39:42.49ID:qQrR5NbL
そもそもオブジェクトの型を動的に判定することは不可能なのだ
ただのシンボル'0'が整数であるとは数学的に決して言えない
整数の性質を満たす集合に属しているから整数と言えるのだ
だからオブジェクトが型を授かるためにクラスは絶対に必要なのだ
ただのシンボル'0'が整数であるとは数学的に決して言えない
整数の性質を満たす集合に属しているから整数と言えるのだ
だからオブジェクトが型を授かるためにクラスは絶対に必要なのだ
2024/02/26(月) 22:55:13.16ID:9WvTd710
そもそもふだんそんなにポリモーフィズムしてるか?
型ヒント書いたら実行前にチェックできるとか、中間コードにコンパイルされる時高速になるとか、それでよくないか?
型ヒント書いたら実行前にチェックできるとか、中間コードにコンパイルされる時高速になるとか、それでよくないか?
2024/02/26(月) 22:58:38.34ID:sdXywFcL
モダンなプログラミング言語
Go、Rust、Zig、Nim、Julia、Elixirなどは
クラスおよびその継承を言語仕様から排除している
それぞれの言語は全く異なる方針を採っているがクラス排除だけは全てで一致している
クラスとその継承は悪手であるとプログラミング言語界では結論が出ている
Go、Rust、Zig、Nim、Julia、Elixirなどは
クラスおよびその継承を言語仕様から排除している
それぞれの言語は全く異なる方針を採っているがクラス排除だけは全てで一致している
クラスとその継承は悪手であるとプログラミング言語界では結論が出ている
2024/02/26(月) 23:36:19.27ID:L97i44S4
xの型がT
y = Foo(x)なら
yの型はFoo(T)
というシステムでいいと思うの
Length ::= Float
Angle ::= Float
Point ::= Tuple(Float, Float)
Triangle ::=
Triangle(Length, Length, Length)
| Triangle(Length, Length, Angle)
| Triangle(Length, Angle, Angle)
| Triangle(Point, Point)
y = Foo(x)なら
yの型はFoo(T)
というシステムでいいと思うの
Length ::= Float
Angle ::= Float
Point ::= Tuple(Float, Float)
Triangle ::=
Triangle(Length, Length, Length)
| Triangle(Length, Length, Angle)
| Triangle(Length, Angle, Angle)
| Triangle(Point, Point)
2024/02/26(月) 23:50:16.48ID:TyGRqLb7
62デフォルトの名無しさん
2024/02/27(火) 00:02:52.99ID:woInknqq クラスは不要で型クラスは必要
2024/02/27(火) 06:56:00.52ID:cCaBYlch
Natural = fn
[0] 0
[n: n >= 0] n
end
succ = fn [Natural(n)] Natural(n + 1) end
add = fn
[n, Natural(0)] n
[n, succ(m)] succ(add(n, m))
end
mul = fn
[n, Natural(0)] Natural(0)
[n, succ(m)] add(mul(n, m), n)
end
AdditiveMonoid = Monoid()
AdditiveMonoid.implimentsIdentity(Natural, fn [] Natural(0) end)
AdditiveMonoid.implimentsAppend(Natural, add)
MultiplicativeMonoid = Monoid()
MultiplicativeMonoid.implimentsIdentity(Natural, fn [] Natural(1) end)
MultiplicativeMonoid.implimentsAppend(Natural, mul)
[0] 0
[n: n >= 0] n
end
succ = fn [Natural(n)] Natural(n + 1) end
add = fn
[n, Natural(0)] n
[n, succ(m)] succ(add(n, m))
end
mul = fn
[n, Natural(0)] Natural(0)
[n, succ(m)] add(mul(n, m), n)
end
AdditiveMonoid = Monoid()
AdditiveMonoid.implimentsIdentity(Natural, fn [] Natural(0) end)
AdditiveMonoid.implimentsAppend(Natural, add)
MultiplicativeMonoid = Monoid()
MultiplicativeMonoid.implimentsIdentity(Natural, fn [] Natural(1) end)
MultiplicativeMonoid.implimentsAppend(Natural, mul)
2024/02/27(火) 11:48:35.86ID:T+tKpG5+
たしかに「この関数から返ってたらこの型」というのはそうか
インタフェース型を返す関数から返った値は、その実体がなんであってもインタフェース型として受け取らないといけないのか
インタフェース型を返す関数から返った値は、その実体がなんであってもインタフェース型として受け取らないといけないのか
2024/02/27(火) 14:07:25.42ID:HfXhKUnc
Pythonの型ヒントも、内部的にやってることは型の階層構造を保存したオブジェクト作ったりしてるだけだし、型をクロージャで表すというのは十分に現実的
2024/02/28(水) 09:15:01.79ID:ZVd213Rl
なんでもクロージャでは構造に基づくサブタイピングができないから、ポリモーフィズムするなら必然的に名前に基づくサブタイピングをする必要がある
2024/02/28(水) 18:59:36.77ID:FE9gquBK
型注釈はクロージャで実現できるけど、肝心の個別のオブジェクトに型を付与するには、処理系に手加えないと無理だね
2024/02/28(水) 20:20:50.87ID:YGaU0GOk
ただのクロージャにこれはLinkedListだみたいな型情報をつけるなら
JavaScriptのようにすべてのオブジェクトがフィールドを持てるようにして、クロージャもtype属性みたいなのを持てるようにする
Pythonのように__call__()メソッドを実装すればオブジェクトも関数として呼び出せるようにして、オブジェクトにラップする
おとなしくにハッシュテーブルにラップするとかして、関数としてのインタフェースを保つのは諦める
JavaScriptのようにすべてのオブジェクトがフィールドを持てるようにして、クロージャもtype属性みたいなのを持てるようにする
Pythonのように__call__()メソッドを実装すればオブジェクトも関数として呼び出せるようにして、オブジェクトにラップする
おとなしくにハッシュテーブルにラップするとかして、関数としてのインタフェースを保つのは諦める
2024/02/28(水) 22:56:39.74ID:E1vk9WfJ
型定義
Counter = Type(fn [n]
fn [i] n += i end
end)
f = Counter(0)
f is Counter # true
f(1) # 1
f(2) # 3
f(3) # 6
エイリアス
Adder = Counter
f is Adder # true
多相型
Pair = Type(fn [T, S]
fn [t: T, s: S] (t, s)
end)
p = Pair(Int, Str)(1, 'Hello')
p is Pair(Int, Str) # true
Counter = Type(fn [n]
fn [i] n += i end
end)
f = Counter(0)
f is Counter # true
f(1) # 1
f(2) # 3
f(3) # 6
エイリアス
Adder = Counter
f is Adder # true
多相型
Pair = Type(fn [T, S]
fn [t: T, s: S] (t, s)
end)
p = Pair(Int, Str)(1, 'Hello')
p is Pair(Int, Str) # true
2024/02/28(水) 23:27:14.87ID:BtUR2apE
クロージャはその外の変数をキャプチャできてこそ本領を発揮する
2024/02/29(木) 09:14:52.93ID:kNys7UfZ
実行のたびに無名関数を生成すると
Pair(Int, Str)の実体が毎回変わってしまう
同じ型として扱うならキャッシュしとかんといかん
Foo()の結果がFoo型になるので、自然にヒエラルキー
Pair(Int, Str) ⊂ Pair ⊂ Type
ができる
子はすべての親を知っているが、親は直接の子しか知らない
Pair(Int, Str)の実体が毎回変わってしまう
同じ型として扱うならキャッシュしとかんといかん
Foo()の結果がFoo型になるので、自然にヒエラルキー
Pair(Int, Str) ⊂ Pair ⊂ Type
ができる
子はすべての親を知っているが、親は直接の子しか知らない
2024/02/29(木) 21:57:07.71ID:FO1fpwyp
ユニオン型
Male = Type()
Female = Type()
Sex = Male | Female
代数的データ型
Nil = Type()
Cons = Type(fn
[T] fn [x: T, xs: List(T)] (x, xs) end
end)
List = Type(fn [T] Nil | Cons(T) end)
c = Cons(Int)(1, Nil())
c is Cons(Int) # true
nl = Nil()
nl is Nil # true
nl is List(Int) # ( = Nil | Cons(T) ) true
l = Cons(2, c)
l is List(Int) # true
Male = Type()
Female = Type()
Sex = Male | Female
代数的データ型
Nil = Type()
Cons = Type(fn
[T] fn [x: T, xs: List(T)] (x, xs) end
end)
List = Type(fn [T] Nil | Cons(T) end)
c = Cons(Int)(1, Nil())
c is Cons(Int) # true
nl = Nil()
nl is Nil # true
nl is List(Int) # ( = Nil | Cons(T) ) true
l = Cons(2, c)
l is List(Int) # true
2024/03/01(金) 09:17:33.48ID:uT9YQz7T
クロージャは
(1) 評価可能な任意のコードブロックをオブジェクト化できる
(2) 新しいコンテクストを導入できる
(3) 評価を遅延可能
(4) 即時生成可能
(1) 評価可能な任意のコードブロックをオブジェクト化できる
(2) 新しいコンテクストを導入できる
(3) 評価を遅延可能
(4) 即時生成可能
2024/03/01(金) 13:47:12.10ID:hUzmZgl8
クロージャは、評価可能な任意のコードブロックを第一級オブジェクトとして扱える
継続は、プログラム実行時の任意の状態と処理を第一級オブジェクトとして扱える
継続は、プログラム実行時の任意の状態と処理を第一級オブジェクトとして扱える
75デフォルトの名無しさん
2024/03/01(金) 15:52:11.47ID:5dJkdiP3 欠点は何?
2024/03/01(金) 16:27:28.29ID:lcFJqP/H
>>75
汎用的な制御構造として使うには難解すぎること
汎用的な制御構造として使うには難解すぎること
2024/03/01(金) 17:06:01.87ID:lcFJqP/H
継続を入れ子にするともう予測不可能になる
2024/03/02(土) 00:04:51.39ID:WOl8O7ii
言語の高速化は処理系の仕事なのだから、特定の処理系で実行速度を最適化するために冗長な書き方を強いられるのは馬鹿げている
2024/03/02(土) 00:15:28.02ID:A93OEkS3
型がクロージャなら例外もクロージャで表現できそう
80デフォルトの名無しさん
2024/03/02(土) 01:38:33.15ID:vVlrIC3U >>76
そこはシンタックスシュガー用意できる?
そこはシンタックスシュガー用意できる?
2024/03/02(土) 02:47:41.13ID:WOl8O7ii
>>80
たとえばコルーチンとか、非決定的なバックトラックとかなら
たとえばコルーチンとか、非決定的なバックトラックとかなら
2024/03/02(土) 09:23:44.53ID:ykoZd5Kv
>>79
例外処理こそ継続とパターンマッチを使うべきだよなあと思う
例外処理こそ継続とパターンマッチを使うべきだよなあと思う
83デフォルトの名無しさん
2024/03/02(土) 11:12:48.28ID:hFGO4sAk 決定性のバックトラックなんてあるの?
2024/03/02(土) 16:06:45.66ID:BdR3F6bT
>>81
Pythonでいうとこのジェネレータ内包表記みたいなのがあれば、多くの場面で十分なのかな
Pythonでいうとこのジェネレータ内包表記みたいなのがあれば、多くの場面で十分なのかな
2024/03/02(土) 19:52:13.99ID:IQAkxugo
>>84
コルーチンの中でコルーチンを呼び出したら、yieldしたら最上位の呼び出し元まで返ってくるのが望ましい
コルーチンの中でコルーチンを呼び出したら、yieldしたら最上位の呼び出し元まで返ってくるのが望ましい
2024/03/02(土) 21:01:52.57ID:yMdn9rGJ
>>85
非同期コルーチンAの中で非同期コルーチンBを呼ぼうとしたら自動的にAはyieldして戻ってからコルーチンBを呼び出し
そのBについても全て終えるか他コルーチン呼び出しで自動的にyield
それぞれyieldして待機中の非同期コルーチンは呼び出し先が解決するとyield時点から再開
というスタックレス非同期コルーチンが何万も稼働しています
非同期コルーチンAの中で非同期コルーチンBを呼ぼうとしたら自動的にAはyieldして戻ってからコルーチンBを呼び出し
そのBについても全て終えるか他コルーチン呼び出しで自動的にyield
それぞれyieldして待機中の非同期コルーチンは呼び出し先が解決するとyield時点から再開
というスタックレス非同期コルーチンが何万も稼働しています
2024/03/03(日) 13:45:11.38ID:qMaLplcd
「コ」ルーチンなんだから上位という概念がそもそもない
2024/03/03(日) 14:01:49.17ID:IZl/xWS6
>>87
スタックレス非同期コルーチンは上位ランタイムがCPUコアスレッド数をフルに使って幾万個の軽い非同期コルーチンをスケジューリングすることでCPU性能を使い尽くすことができる
スタックレス非同期コルーチンは上位ランタイムがCPUコアスレッド数をフルに使って幾万個の軽い非同期コルーチンをスケジューリングすることでCPU性能を使い尽くすことができる
2024/03/03(日) 14:47:38.82ID:qMaLplcd
的外れ
2024/03/03(日) 14:53:35.32ID:IZl/xWS6
的外れとは?
現在のネットインフラは>>88の通り動いている現実を認めたくない?
現在のネットインフラは>>88の通り動いている現実を認めたくない?
2024/03/03(日) 17:03:12.55ID:Vr3nU8ht
>>87
あなたの言うコルーチンの定義は?
あなたの言うコルーチンの定義は?
2024/03/05(火) 13:01:59.74ID:hcPpBjWs
スタックフルのコルーチンは、内部で呼び出したコルーチンがyieldしてるかどうか呼び出し元が知っていないといけない
つまりカプセル化を破壊する
つまりカプセル化を破壊する
2024/03/05(火) 14:58:20.75ID:QuH/Int2
複数のスレッドが協調して何かするなんてのは、もはやプログラミング言語の領分じゃないんだよなぁ
2024/03/05(火) 22:53:42.99ID:1H/gFsr2
Erlang OTPみたいなアプローチが良いと思う
2024/03/08(金) 23:46:15.42ID:7wk+t80g
重要なのはプロトコル
定められた型のメソッドを持つことが重要
定められた型のメソッドを持つことが重要
2024/03/11(月) 12:27:38.30ID:HvPoaoEY
実装の継承は悪手
2024/03/13(水) 21:40:17.77ID:lx8X47UA
関数とオブジェクトなんて、要はどっちも値を入れたら何かを返す箱なのだから、内部構造を考えなければ共通化できるはず
配列も、機能だけ見れば、キーが数値なだけのただのオブジェクト
リストやジェネレータなどをイテレートするのも、関数を引数なしで呼び出すようなもの
配列も、機能だけ見れば、キーが数値なだけのただのオブジェクト
リストやジェネレータなどをイテレートするのも、関数を引数なしで呼び出すようなもの
2024/03/13(水) 23:38:55.71ID:+S4Brq3S
Pythonは__call__()メソッドを実装することでオブジェクトも関数のように振る舞える
これは小規模なプログラムでは関数として実装しておき、大規模になったらシームレスに移行できるように
これは小規模なプログラムでは関数として実装しておき、大規模になったらシームレスに移行できるように
2024/03/14(木) 18:36:51.37ID:rbf7F1li
Iterable⊂Callable⊃Associative
だが、Iterableとしての呼び出し方とAssociativeとしての呼び出し方が異なる
だが、Iterableとしての呼び出し方とAssociativeとしての呼び出し方が異なる
100デフォルトの名無しさん
2024/03/14(木) 18:40:46.10ID:rbf7F1li x = [1, 2, 3]をIterableとしてCallableだと思う場合、x() = next(x)
AssociativeとしてCallableだと思う場合、x(n) = x[n]
になる
AssociativeとしてCallableだと思う場合、x(n) = x[n]
になる
101デフォルトの名無しさん
2024/03/14(木) 21:09:23.66ID:xE50NtDY マシン語を知らないと妙なこだわりを言い出すからおもしろいよなw
102デフォルトの名無しさん
2024/03/14(木) 23:24:02.50ID:yxqrN1vV 異なる層の話を出すのもどうかと思うがね
レスを投稿する
ニュース
- 【外国人問題】小野田紀美担当相「不法就労や不法滞在は許さない」 [シャチ★]
- 橋下徹氏 外務省幹部の訪中受け「口だけ番長」へ痛烈指摘 「喧嘩は日本の完敗…なんとかっこ悪い日本か」 [冬月記者★]
- 【野球】井端監督 大谷翔平、山本由伸らのWBCへの参加 「1日も早く返事ほしい」「待っててといっても、国内組が遅くなってしまう」★3 [冬月記者★]
- 中国で「クレしん」公開延期 対日報復、エンタメに波及 [蚤の市★]
- 経団連会長、日中は建設的対話を 経済3団体が高市首相と初会談も日中関係は話題に登らず… [BFU★]
- 【映画】『クレヨンしんちゃん』 中国で公開延期 対日報復、エンタメに波及 [冬月記者★]
- 日経時間外、5万円割れ 垂直落下始まる [402859164]
- 有識者「高市総理が発言を撤回したり、辞職するしかないと言っている人は、それで日中関係が今まで通りになると思ってる?」 [834922174]
- ウッドデッキで調子こいてたやついたじゃん
- 🦉エッホエッホ アンパンマンは猫舌って伝えなきゃ
- えんやすー
- 中国人「昔の仇を取る」「高市は狂ってる。制裁すればいい」「高市はことの重大さを認識してない」 [931948549]
