Closures vs Objects

2024/02/19(月) 20:39:15.91ID:VT95BnI9
It is well-known that closures and objects are equivalent. So are actors. Which one is the most fundamental?

よく知られたように、クロージャとオブジェクトは等価です。アクターも同様です。どの概念が最も基本的なのでしょうか?
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でいうとこのジェネレータ内包表記みたいなのがあれば、多くの場面で十分なのかな
2024/03/02(土) 19:52:13.99ID:IQAkxugo
>>84
コルーチンの中でコルーチンを呼び出したら、yieldしたら最上位の呼び出し元まで返ってくるのが望ましい
2024/03/02(土) 21:01:52.57ID:yMdn9rGJ
>>85
非同期コルーチン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性能を使い尽くすことができる
2024/03/03(日) 14:47:38.82ID:qMaLplcd
的外れ
2024/03/03(日) 14:53:35.32ID:IZl/xWS6
的外れとは?
現在のネットインフラは>>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としての呼び出し方が異なる
2024/03/14(木) 18:40:46.10ID:rbf7F1li
x = [1, 2, 3]をIterableとしてCallableだと思う場合、x() = next(x)
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
異なる層の話を出すのもどうかと思うがね
2024/03/15(金) 08:26:32.50ID:vBMVv6T3
>>101
コンピュータサイエンスにおいて低レイヤーが上位という価値観があるのって、おそらく日本だけだと思うんだけど、どうしてこういう逆行現象が起こるんだろう?
2024/03/15(金) 08:47:50.82ID:0zJIPs3S
数学だと基礎論は馬鹿にされてるよね
通常の数学やるときに選択公理だとか不完全性定理だとかいってるのは素人だけ
そりゃ形式的に「基礎論のほうが原理に近い」というだけならべつに数学を知らなくても分かるからね
2024/03/15(金) 08:56:58.18ID:wSiNosZi
>>103
マシン語わかる
でもコンピューターサイエンスの素養なし
って感じのロートルが必至にマウントとろうとしてるだけだろな
2024/03/15(金) 09:01:28.78ID:0zJIPs3S
ふつうは情報学科でも昔ならSICPでやったようなプログラミングの概念や機能に関する講義があるはずで、
ちゃんと勉強している人で実装と機能を分けて考えるということができない人はいないよ

日本で低レイヤーが偉そうな顔してるのは単に、大学等で体系的に学ばずに昔からパソコンに触ってただけのおじさんが言ってるだけ
日本ではプログラマが高等教育が必要な専門技術職として見なされておらず、パソコンしか取り柄のない社会不適合者を低賃金でこきつかう職種だと見なされていたのが原因
2024/03/15(金) 09:10:45.64ID:5Fl9dqIV
>>104
物理学科の自称秀才がやたらと素粒子論専攻したがるのもこれだよなぁ……
実際に勉強して内容に興味を持てたかどうかではなくて、ラベルで判断してる
20過ぎた大人が将来の進路に関わる選択でそういうことするのは、病的としか言いようがない
2024/03/15(金) 12:38:47.19ID:ohT/C40H
>>99
ってことは>>31の方法でも菱形継承問題ふつうに発生するやん

Iterable < Callable
__call__ = __next__

Associative < Callable
__call__ = __getattr__

Array < Iterable, Associative
__next__ = piyopiyo
__getattr__ = hogehoge

arr = Array(blahblahblah)
arr() はどっちになるべき?
2024/03/15(金) 14:11:38.88ID:DTF+UIWv
a) 実装継承
b) 多重継承
c) 多段階継承

ができる時点で菱形継承問題は避けられない
Rubyは、クラスは(b)を、モジュールは(c)を諦めることでこの問題を回避している
110デフォルトの名無しさん
垢版 |
2024/03/15(金) 14:37:43.94ID:zsH6n39D
>>108
pythonはそうだよ
2024/03/15(金) 16:37:06.04ID:HEyD2qcN
Rubyのrefinementsみたいに、このスコープでは型定義を変えるみたいなのがあればまだマシになんのかな
たとえば、あるブロック内でだけ(Int, Int)をPoint2Dとみなすとか
2024/03/15(金) 17:16:49.88ID:Ratd2baE
>>108
・具象型とインタフェースを分ける
 具象型→Int, Str, List<T>など
 インタフェース→Comparable, Iterableなど
・多重継承したインタフェースで仮想でないメソッドに名前の重複があったらエラーにする

とするしかないのでは
2024/03/15(金) 17:20:27.60ID:Ratd2baE
型とインタフェースは分けないと、たとえば

equal(x: Eq, y: Eq) -> bool

とか無意味になる
xとyには具体的な型が同じものが入ってほしいのに、Eqインタフェースを持っている型すべてを許容してしまう
ほんとうにやりたいのは

equal(x: T, y: T) -> bool where T: Eq

ということ
2024/03/15(金) 17:33:55.76ID:UiCkupYq
型システムと並行性はむずかしいな
でも、言語がプログラマに好まれるかどうかってそんなとこにないと思うよ
一時期、高機能なタスクランナーやら単体テストフレームワークやらがたくさん出てきたけど、結局はnpm-scriptsとか言語標準のunittestライブラリに収束した
2024/03/15(金) 17:40:58.53ID:UiCkupYq
powershellはプログラミング言語としてはbashよりもはるかに高機能だが、誰もあれで書きたいとは思わない
2024/03/15(金) 18:11:48.66ID:RqiZ+uh9
>>108
inheritanceを型に対して行うのが間違いな気がする
Int x Intを、Point2DとRationalのサブクラスとしたとする
Point2DとRationalの両方に + を実装(前者にはベクトルとして、後者には有理数として)したとして、

(1, 2) + (3, 4)

はどうなるか?
それは結局、今(1, 2), (3, 4)をどの型だとみなしているかによるのであって、型Int x Intの与り知らぬところだ
2024/03/15(金) 18:25:53.61ID:C8O2+ggF
>>109
Mixinで多重継承問題回避できる理屈がよくわからんかったけど、今ようやっと理解できたわ
2024/03/15(金) 18:31:58.44ID:8+Y0uCh5
>>113
結局Rustのトレイト境界が正解ということか
2024/03/15(金) 19:43:07.16ID:UT4yxmsS
>>109
Javaの場合は、クラスは(b)を、インタフェースは(a)を諦めている
2024/03/15(金) 21:35:17.15ID:XzxHtHqU
ダイヤモンド継承は、コンパイラが検出するのが正しい気がする
構文で回避するには、>>109みたく機能を制限するしかない
RustとHaskellはしてくれる
2024/03/15(金) 21:53:50.95ID:WMhMrtUW
まあ、でもプログラミング言語が人気になるかどうかは
>>114の言うように、処理系の完璧さではなく、実用のニーズに耐え得ることなんだろうな
2024/03/15(金) 22:34:31.87ID:3o/QlmnN
クロージャとオブジェクトが同等なのはわかったが、それよりもさらに強力な言語機能はないのか?
2024/03/15(金) 23:30:35.88ID:rbMui8Ez
継続

プログラマが直接触らないものとしては、ガベージコレクションとかレキシカルクロージャとかもそうかもね
2024/03/16(土) 20:49:53.31ID:TBzj9DHS
Eiffel、Delphi、C#なんかは菱形継承してもそれぞれに別名を与えて捌ける機能を持ってるが
オブジェクト指向自体が下火なのもあって、最近のやつはそこまで作り込まれてない感
2024/03/16(土) 21:44:17.40ID:gqfrZq4+
多重継承は名前がぶつかろうがそれ自体に問題は一切ない
抽象型から具象型への継承で実装継承でないならば区別できる限り問題は生じない

本質的な問題は実装継承であること
特にに具象型から具象型への継承が問題
これは多重かどうかに関係なく問題となる
2024/03/16(土) 22:15:39.23ID:ajdJdfuW
そもそもOOPにおける継承ってのは、数学的に破綻してるんだよ
>>116で述べているとおり
型定義にサブタイピングの実装方法が入るわけがない
2024/03/16(土) 22:18:29.76ID:ajdJdfuW
自然数 is a モノイド

と自然にみなす方法は2通りある
その方法は自然数の定義とは関係ない
2024/03/16(土) 22:28:23.06ID:UqSB/mst
クラスが欠陥品なのは同意だが
クラスを捨てて型クラスを使えばよい
2024/03/16(土) 22:30:52.34ID:ajdJdfuW
行列式=1の2次正方行列が、
自分の型はM(2)なのか、GL(2)なのか、SL(2)なのかなんて知らんがな
2024/03/16(土) 22:35:57.52ID:TBzj9DHS
>>127の問題は型クラスやtraitでも発生するしなあ
C++で没になったconcept_mapのようなものを複数切り替えられる機能が求められる
2024/03/19(火) 03:55:14.66ID:5WuD+qyw
x: T where T: K where K: L where ...

のように高階の型や

fn(x: T) -> Type

のようにパラメータに依存する型などがいくらでも作れたらどんなことができるのだろうか
2024/03/19(火) 22:24:36.99ID:TBPz9mXO
>>131
具象型Tに対して抽象型Kの制約を課すところまでは普通として
抽象型Kに対して高階抽象型Lの制約を課すメリットが見つからなかった

代替の方法として高階とせずに
抽象型Kに対して同じレベルの抽象型Lの制約を常に課す宣言ができれば十分にみえる
2024/03/20(水) 17:07:37.10ID:yZelKyNv
>>60
これを一般化したのが依存型やね
これが扱えると数学の証明を型で書ける
2024/04/06(土) 13:15:05.66ID:IRVxBt67
なんでもラムダ
→なんでもオブジェクト
→なんでも型
2024/04/07(日) 01:46:27.75ID:HXZiHVf3
全称量化子は関数で
存在量化子はパターンマッチングで
表せるので、一階述語論理もラムダ式で書けそう
2024/04/07(日) 05:29:44.44ID:FOjhJ4gr
書けるの意味がわからんな
書いてどうする?
カリー・ハワード対応とかチューリング完全と関係ある話か?
2024/04/07(日) 06:21:18.75ID:ZeXbAXZK
存在命題とか背理法とか、仮定を仮引数にしたラムダ式を使えば、具体的に証明や値を構成しなくても所望のものを取ってこられるんだな
2024/04/07(日) 07:33:56.22ID:FOjhJ4gr
それは理論的に不可能
2024/04/07(日) 09:52:53.31ID:/E0pQilp
res = hoge()みたいにただ結果返すのと、
hoge((res) => doSomething())みたいに引数に結果入ってくるのと、何が違うんや
2024/04/07(日) 10:45:31.26ID:thR/d4RZ
まず、hogeが同期的でない場合は

res = hoge()

とは書けない
async/awaitのような機構が必要になる

またたとえば、エラーの場合は処理を分岐させたいような場合、

hoge(
(res) => doSomething(),
(err) => handleError())

のように拡張できる
ただし、内部でさらに同じようなことをやっているとコールバック地獄になる
2024/04/07(日) 11:19:43.04ID:0gYyGnNT
>>134
依存型のあるHaskellやLean4はとくにオブジェクト指向という感じはしない
2024/04/07(日) 13:08:22.06ID:IfUr/96a
>>141
純粋関数型で、(クラスベースの)オブジェクト指向をやる意味は皆無だからな
2024/04/07(日) 19:27:40.79ID:m+fa22Uj
純関数型言語でなくても
モダンなプログラミング言語
Go、Rust、Zig、Nim、Julia、Elixirなどは
クラスおよびその継承を言語仕様から排除しておりクラスは存在しない

それら各々の言語は全く異なる方針を採っている言語だがクラス排除だけは全てが同じ方針である
クラスとその継承は悪手であるとプログラミング言語界では結論が出ている
2024/04/07(日) 20:16:17.84ID:mSidkHeO
だからってduck typingはクラスよりさらに悪いと思うんだ
2024/04/07(日) 20:37:39.53ID:rmfTjPEc
>>144
だからクラスとダックタイピングを採用しない言語が増えているね
2024/04/07(日) 21:18:11.49ID:E193nq4c
ポエムはよそでやれ
2024/04/08(月) 14:29:36.32ID:LhsijIe9
P∧Qの導入則は、P -> Q -> P∧Q
これは(P, Q)ならばP∧Qとも読めるし
Pを仮定したとき、QならばP∧Qとも読める
2024/04/09(火) 18:44:27.40ID:kKsSVHOb
限定継続(reset/shift)の動きが意味わかんない
resetで範囲絞ってる分call/ccより実用的には扱いやすいというのは分かるが、ローカルで見たらcall/ccのほうが直感的に思える
2024/04/09(火) 23:18:54.13ID:Aro4tJCD
実装の都合では?
フル機能の継続はそこまでのスタック全部を生かし続けないといけないし分岐できないといけないしで
スタック自体をOSの用意してくれるものとは別に自前で構成しないといけないしそうするとABIからなにからつらい
2024/04/10(水) 01:07:10.63ID:uPucvtCR
内部で継続渡しに変換してるなら、フルの継続のほうが実装しやすいと思うけど
Schemeの場合、dynamic-windとかも実装しなきゃいかんからより複雑だろうけど
2024/04/10(水) 03:30:06.71ID:qIIVcoEj
継続渡しはスタック消費をクロージャで置き換えてるわけで、スタックを自前で用意してるのと同じようなもんでは
2024/04/10(水) 04:04:38.17ID:nlTt4/RM
会話が噛み合ってない
2024/04/10(水) 09:16:26.52ID:fNUeJXq8
いや割と噛み合ってる
2024/04/10(水) 11:55:16.47ID:dXGnSmQj
処理が

A → B → C → ...

とあって

A → ... → shift(fn k -> hoge) → B → ... → C → reset

とすると

k に処理 _ → B → ... → Cが束縛される
hogeを実行するとresetまでジャンプする
resetの値はhogeの値になる

なので、たとえばバックトラックがしたいなら、
戻ってきたい場所にshiftを設置して、
fn () -> k next_valueをスタックに積んで、
クロージャの内部でk current_valueを実行すればいい
2024/04/10(水) 11:57:37.66ID:dXGnSmQj
で、スタックから継続をpopして実行する関数を別に作って
選択肢がなくなったときはそれを呼べばいい
2024/04/10(水) 16:24:50.24ID:gx493tSk
カプセル化を破壊するのが前提なので、ものすごく気を遣う
2024/04/10(水) 17:47:04.13ID:uxnW16Zl
call/ccやreset/shiftの型はどうなるの?
2024/11/11(月) 12:09:40.22ID:eaS0ivay
call/ccの型は

((T -> ⊥) -> T) -> T

これは、¬Tを仮定してTが導けるならTということ
つまり、直観主義論理に排中律を追加することに相当する
2024/11/28(木) 14:50:39.31ID:D62ASfXP
first-class typeがあると、どのような抽象化が可能になるのか
160デフォルトの名無しさん
垢版 |
2024/11/28(木) 21:23:23.02ID:tgeVSyIQ
output_integer = input_string.filter(is_number).map(char_to_integer).sum()
161デフォルトの名無しさん
垢版 |
2024/11/28(木) 22:26:33.20ID:U97loGz8
何かしらんけどHaskell版

import Data.Char

outputInteger = getLine >>= return.sum.map digitToInt.filter isDigit

f = outputInteger >>= putStrLn.("sum = " ++).show -- IOな値は必ず >>= 経由で渡される。
>f
1a2b3
>sum = 6

do表記

f = do x <- outputInteger -- IOな値は必ず <- で束縛された変数経由で渡される。
    putStrLn $ "sum = " ++ show x
2024/11/28(木) 22:37:38.47ID:iYyun2JN
代入をなくそう

n = 1ではなく

n: 1 (nは1である)
n: Nat (nは自然数である)

これを基礎とする
2024/11/28(木) 22:39:47.41ID:iYyun2JN
こうすればパターンマッチなどに統一性がとれるだろう
164デフォルトの名無しさん
垢版 |
2024/11/28(木) 22:59:50.27ID:U97loGz8
map digitToInt だと"1 2 3" = [1, 2, 3] は良いとして、"123" = [1, 2, 3] と1桁ずつになるので改良した

outputInteger = getLine >>= return.sum.map (read.filter isDigit).words

> f
11 22 33 -- Input
sum = 66
> f
1a1 22b k33 -- Input
sum = 66
2024/11/29(金) 08:50:35.19ID:ZHbjuyaH
よそでやれ
2024/11/29(金) 18:22:51.77ID:FvJq/OMC
>>162
n: 1は、nを1で置き換えられるが
n: Natは、n≠Natなので
何か本質的に異なるものに思える
2024/11/29(金) 18:26:10.93ID:FXP1+9fo
具体的なデータ(1とか"Hello"とか)があれば、型が決まるわけでもない
たとえば、、1 + 1は加法モノイドとみれば2だけど、乗法モノイドとみれば1
ただ、前者とみなす慣習が圧倒的に多いに過ぎない
2024/11/29(金) 19:14:30.73ID:lZOQa9Jb
具体型をなくして抽象型だけにするのは?
2024/12/12(木) 18:30:39.23ID:XExKLUf8
Leanでは、Exists(fun x: A => p x)は長いから∃x: A, p xと書くらしいので、ラムダ式のシンタックスはさらに短くなる
2024/12/12(木) 20:50:14.10ID:YVpGcPfJ
命題は型
2024/12/12(木) 22:51:28.02ID:dX7jmuEY
>>144
duck typingもクラスも使わずにinterfaceを使うのが正解
2024/12/13(金) 13:33:11.56ID:ObbUHrIh
クラスのフィールドは全く不要な概念
2024/12/13(金) 21:23:08.37ID:ePsQGGMZ
クラス自体が不要
クラスを排除したモダンなプログラミング言語が多数あることが何よりの証拠
2024/12/19(木) 16:09:31.78ID:RMYWDOZr
クロージャ指向から述語指向へ
2024/12/25(水) 16:41:01.48ID:jsf4a+Fl
継続指向プログラミング
2024/12/28(土) 22:32:57.19ID:U3Qq1irw
T :: ((α -> β) -> α -> (_ -> (_, β)), _ -> _)
T = (S, R)

f :: α -> β
S f :: α -> (_ -> (_, β))
S f a = fn x: (R x, f a)

f :: α -> β, g :: β -> γ
S f :: α -> (_ -> (_, β))
S g :: β -> (_ -> (_, γ))
S g >>= S f a = fn x:
let
(x', b) = S f a x
in
(R x', g b)
2024/12/29(日) 01:19:32.44ID:OIeguool
Category theory for programmers読む
2025/02/04(火) 01:03:51.46ID:63k9bOfa
プログラムのすべての箇所で値が(val: a, cont: a -> r)みたいになってたら、
独立したコンテキスト間で状態を受け渡ししなきゃいけないような仕様変更があっても、

その状態を参照できる所の(state, cont1)をセーブポイントとして保存
で、その状態を共有したい所の(val, cont2)を保存してcont1を呼び出す
stateとvalから新しいvalを作ってcont2を呼び出す

とやればいいのか
レスを投稿する

5ちゃんねるの広告が気に入らない場合は、こちらをクリックしてください。

ニューススポーツなんでも実況