It is well-known that closures and objects are equivalent. So are actors. Which one is the most fundamental?
よく知られたように、クロージャとオブジェクトは等価です。アクターも同様です。どの概念が最も基本的なのでしょうか?
>>104
物理学科の自称秀才がやたらと素粒子論専攻したがるのもこれだよなぁ……
実際に勉強して内容に興味を持てたかどうかではなくて、ラベルで判断してる
20過ぎた大人が将来の進路に関わる選択でそういうことするのは、病的としか言いようがない >>99
ってことは>>31の方法でも菱形継承問題ふつうに発生するやん
Iterable < Callable
__call__ = __next__
Associative < Callable
__call__ = __getattr__
Array < Iterable, Associative
__next__ = piyopiyo
__getattr__ = hogehoge
arr = Array(blahblahblah)
arr() はどっちになるべき? a) 実装継承
b) 多重継承
c) 多段階継承
ができる時点で菱形継承問題は避けられない
Rubyは、クラスは(b)を、モジュールは(c)を諦めることでこの問題を回避している
0110デフォルトの名無しさん2024/03/15(金) 14:37:43.94ID:zsH6n39D
Rubyのrefinementsみたいに、このスコープでは型定義を変えるみたいなのがあればまだマシになんのかな
たとえば、あるブロック内でだけ(Int, Int)をPoint2Dとみなすとか
>>108
・具象型とインタフェースを分ける
具象型→Int, Str, List<T>など
インタフェース→Comparable, Iterableなど
・多重継承したインタフェースで仮想でないメソッドに名前の重複があったらエラーにする
とするしかないのでは 型とインタフェースは分けないと、たとえば
equal(x: Eq, y: Eq) -> bool
とか無意味になる
xとyには具体的な型が同じものが入ってほしいのに、Eqインタフェースを持っている型すべてを許容してしまう
ほんとうにやりたいのは
equal(x: T, y: T) -> bool where T: Eq
ということ
型システムと並行性はむずかしいな
でも、言語がプログラマに好まれるかどうかってそんなとこにないと思うよ
一時期、高機能なタスクランナーやら単体テストフレームワークやらがたくさん出てきたけど、結局はnpm-scriptsとか言語標準のunittestライブラリに収束した
powershellはプログラミング言語としてはbashよりもはるかに高機能だが、誰もあれで書きたいとは思わない
>>108
inheritanceを型に対して行うのが間違いな気がする
Int x Intを、Point2DとRationalのサブクラスとしたとする
Point2DとRationalの両方に + を実装(前者にはベクトルとして、後者には有理数として)したとして、
(1, 2) + (3, 4)
はどうなるか?
それは結局、今(1, 2), (3, 4)をどの型だとみなしているかによるのであって、型Int x Intの与り知らぬところだ >>109
Mixinで多重継承問題回避できる理屈がよくわからんかったけど、今ようやっと理解できたわ >>113
結局Rustのトレイト境界が正解ということか >>109
Javaの場合は、クラスは(b)を、インタフェースは(a)を諦めている ダイヤモンド継承は、コンパイラが検出するのが正しい気がする
構文で回避するには、>>109みたく機能を制限するしかない
RustとHaskellはしてくれる まあ、でもプログラミング言語が人気になるかどうかは
>>114の言うように、処理系の完璧さではなく、実用のニーズに耐え得ることなんだろうな クロージャとオブジェクトが同等なのはわかったが、それよりもさらに強力な言語機能はないのか?
継続
プログラマが直接触らないものとしては、ガベージコレクションとかレキシカルクロージャとかもそうかもね
Eiffel、Delphi、C#なんかは菱形継承してもそれぞれに別名を与えて捌ける機能を持ってるが
オブジェクト指向自体が下火なのもあって、最近のやつはそこまで作り込まれてない感
多重継承は名前がぶつかろうがそれ自体に問題は一切ない
抽象型から具象型への継承で実装継承でないならば区別できる限り問題は生じない
本質的な問題は実装継承であること
特にに具象型から具象型への継承が問題
これは多重かどうかに関係なく問題となる
そもそもOOPにおける継承ってのは、数学的に破綻してるんだよ
>>116で述べているとおり
型定義にサブタイピングの実装方法が入るわけがない 自然数 is a モノイド
と自然にみなす方法は2通りある
その方法は自然数の定義とは関係ない
クラスが欠陥品なのは同意だが
クラスを捨てて型クラスを使えばよい
行列式=1の2次正方行列が、
自分の型はM(2)なのか、GL(2)なのか、SL(2)なのかなんて知らんがな
>>127の問題は型クラスやtraitでも発生するしなあ
C++で没になったconcept_mapのようなものを複数切り替えられる機能が求められる x: T where T: K where K: L where ...
のように高階の型や
fn(x: T) -> Type
のようにパラメータに依存する型などがいくらでも作れたらどんなことができるのだろうか
>>131
具象型Tに対して抽象型Kの制約を課すところまでは普通として
抽象型Kに対して高階抽象型Lの制約を課すメリットが見つからなかった
代替の方法として高階とせずに
抽象型Kに対して同じレベルの抽象型Lの制約を常に課す宣言ができれば十分にみえる >>60
これを一般化したのが依存型やね
これが扱えると数学の証明を型で書ける なんでもラムダ
→なんでもオブジェクト
→なんでも型
全称量化子は関数で
存在量化子はパターンマッチングで
表せるので、一階述語論理もラムダ式で書けそう
書けるの意味がわからんな
書いてどうする?
カリー・ハワード対応とかチューリング完全と関係ある話か?
存在命題とか背理法とか、仮定を仮引数にしたラムダ式を使えば、具体的に証明や値を構成しなくても所望のものを取ってこられるんだな
res = hoge()みたいにただ結果返すのと、
hoge((res) => doSomething())みたいに引数に結果入ってくるのと、何が違うんや
まず、hogeが同期的でない場合は
res = hoge()
とは書けない
async/awaitのような機構が必要になる
またたとえば、エラーの場合は処理を分岐させたいような場合、
hoge(
(res) => doSomething(),
(err) => handleError())
のように拡張できる
ただし、内部でさらに同じようなことをやっているとコールバック地獄になる
>>134
依存型のあるHaskellやLean4はとくにオブジェクト指向という感じはしない >>141
純粋関数型で、(クラスベースの)オブジェクト指向をやる意味は皆無だからな 純関数型言語でなくても
モダンなプログラミング言語
Go、Rust、Zig、Nim、Julia、Elixirなどは
クラスおよびその継承を言語仕様から排除しておりクラスは存在しない
それら各々の言語は全く異なる方針を採っている言語だがクラス排除だけは全てが同じ方針である
クラスとその継承は悪手であるとプログラミング言語界では結論が出ている
だからってduck typingはクラスよりさらに悪いと思うんだ
>>144
だからクラスとダックタイピングを採用しない言語が増えているね P∧Qの導入則は、P -> Q -> P∧Q
これは(P, Q)ならばP∧Qとも読めるし
Pを仮定したとき、QならばP∧Qとも読める
限定継続(reset/shift)の動きが意味わかんない
resetで範囲絞ってる分call/ccより実用的には扱いやすいというのは分かるが、ローカルで見たらcall/ccのほうが直感的に思える
実装の都合では?
フル機能の継続はそこまでのスタック全部を生かし続けないといけないし分岐できないといけないしで
スタック自体をOSの用意してくれるものとは別に自前で構成しないといけないしそうするとABIからなにからつらい
内部で継続渡しに変換してるなら、フルの継続のほうが実装しやすいと思うけど
Schemeの場合、dynamic-windとかも実装しなきゃいかんからより複雑だろうけど
継続渡しはスタック消費をクロージャで置き換えてるわけで、スタックを自前で用意してるのと同じようなもんでは
処理が
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を実行すればいい
で、スタックから継続をpopして実行する関数を別に作って
選択肢がなくなったときはそれを呼べばいい
カプセル化を破壊するのが前提なので、ものすごく気を遣う
call/ccやreset/shiftの型はどうなるの?