公式
https://www.rust-lang.org/
https://blog.rust-lang.org/
https://github.com/rust-lang/rust
公式ドキュメント
https://www.rust-lang.org/learn
Web上の実行環境
https://play.rust-lang.org
※Rustを学びたい人はまず最初に公式のThe Bookを読むこと
https://doc.rust-lang.org/book/
※Rustを学ぶ際に犯しがちな12の過ち
https://dystroy.org/blog/how-not-to-learn-rust
※Rustのasyncについて知りたければ「async-book」は必読
https://rust-lang.github.io/async-book/
※次スレは原則>>980が立てること
前スレ
Rust part19
https://mevius.5ch.net/test/read.cgi/tech/1673926892/
ワッチョイスレ
プログラミング言語 Rust 4【ワッチョイ】
https://mevius.5ch.net/test/read.cgi/tech/1514107621/
Rust part20
■ このスレッドは過去ログ倉庫に格納されています
2023/03/03(金) 00:45:28.73ID:vTVY069B
770デフォルトの名無しさん
2023/07/19(水) 12:25:20.07ID:YST94QZy いろいろキッツいなぁー
loop-variableはfor-loopのブロックスコープ
u64::powはfn pow(self, exp: u32) -> u64
(u32以上の値をとってもオーバーフローするから)
>「rustは関数呼び出しは基本call by valueで呼び出され、呼び出し時の“値”は基本コピーして渡される、ただしimmutatibleな呼び出しでは関数側が値を変更しないのにコピーするのは無駄なのでコピーされない」
>であってますか?
もちろん間違ってます
loop-variableはfor-loopのブロックスコープ
u64::powはfn pow(self, exp: u32) -> u64
(u32以上の値をとってもオーバーフローするから)
>「rustは関数呼び出しは基本call by valueで呼び出され、呼び出し時の“値”は基本コピーして渡される、ただしimmutatibleな呼び出しでは関数側が値を変更しないのにコピーするのは無駄なのでコピーされない」
>であってますか?
もちろん間違ってます
771デフォルトの名無しさん
2023/07/19(水) 12:29:53.08ID:hsqLjzEB 余りをとっているから繰り返し自乗法を適当に実装すればオーバーフローは回避できる
772デフォルトの名無しさん
2023/07/19(水) 12:30:35.45ID:HXkvqxP4773デフォルトの名無しさん
2023/07/19(水) 12:41:14.04ID:HXkvqxP4 >>771
そうなんですよ
毎回あまり取らないとダメですよね
pの値も間違ってたし
やりたかったのはバッファサイズが1048576の有限体のフーリエ変換のための素数と位数1048576の元zetaを見つける作業でpはすぐ見つけてたんですけどzetaで手こずりました
まだrust慣れてないもので
これで行けました
https://ideone.com/haw9t8
見つけたzetaの候補3つ
4293918721
1557
7183
8874
そうなんですよ
毎回あまり取らないとダメですよね
pの値も間違ってたし
やりたかったのはバッファサイズが1048576の有限体のフーリエ変換のための素数と位数1048576の元zetaを見つける作業でpはすぐ見つけてたんですけどzetaで手こずりました
まだrust慣れてないもので
これで行けました
https://ideone.com/haw9t8
見つけたzetaの候補3つ
4293918721
1557
7183
8874
774デフォルトの名無しさん
2023/07/19(水) 15:49:39.29ID:HXkvqxP4 やはりダメです
型の指定の書き方がわかりません
次のコードです
https://ideone.com/QLw12c
有限体上のFourier変換を書きたいんですけどmutの書き方がらみで怒られます
どうすれば通せますか?
型の指定の書き方がわかりません
次のコードです
https://ideone.com/QLw12c
有限体上のFourier変換を書きたいんですけどmutの書き方がらみで怒られます
どうすれば通せますか?
775デフォルトの名無しさん
2023/07/19(水) 16:22:53.10ID:HXkvqxP4 とりあえずmutを全部につけまくったら通りました
https://ideone.com/EF9EEJ
https://ideone.com/EF9EEJ
776デフォルトの名無しさん
2023/07/19(水) 17:34:17.58ID:g8hXxOtp >>774
>どうすれば通せますか?
The Bookを読んで基本を身につければ通せます。
https://doc.rust-lang.org/book/
まずはplygroundとエラーメッセージの読み方から学ぶことをお勧めいたします。
>どうすれば通せますか?
The Bookを読んで基本を身につければ通せます。
https://doc.rust-lang.org/book/
まずはplygroundとエラーメッセージの読み方から学ぶことをお勧めいたします。
777デフォルトの名無しさん
2023/07/19(水) 17:52:11.79ID:HXkvqxP4 ありがとうございます
コンパイルは無事通ったんですけどstack overflowで実行できませんでしたw
どうせならどでかいのでやってみようと欲張ったらダメでしたw
まぁ縮める分には見つけたpやzetaはそのまま使えるのでまた時間ある日に続きやります
やっぱり新しい言語挑戦するのは時間かかりますね
ついでにひとつお聞きしたいんですけど、今回は「Rustの売りのなるべくstuckでやる」でやってみたんですけど流石にこのサイズはstackにとれないようです
コレ同じ事ヒープでやってもRustコンパイラはフラグメンテーションが怒らないように良きにはからってくれますよね?
コードは>>775です、まだ作りかけですけど
Fourier変換でO(n log n)で掛け算するプログラムの実装の演習の自習中です
コンパイルは無事通ったんですけどstack overflowで実行できませんでしたw
どうせならどでかいのでやってみようと欲張ったらダメでしたw
まぁ縮める分には見つけたpやzetaはそのまま使えるのでまた時間ある日に続きやります
やっぱり新しい言語挑戦するのは時間かかりますね
ついでにひとつお聞きしたいんですけど、今回は「Rustの売りのなるべくstuckでやる」でやってみたんですけど流石にこのサイズはstackにとれないようです
コレ同じ事ヒープでやってもRustコンパイラはフラグメンテーションが怒らないように良きにはからってくれますよね?
コードは>>775です、まだ作りかけですけど
Fourier変換でO(n log n)で掛け算するプログラムの実装の演習の自習中です
778デフォルトの名無しさん
2023/07/19(水) 23:54:55.34ID:6nPpRSza >>758
>> rustは関数呼び出しは基本call by valueで呼び出され、呼び出し時の“値”は基本コピーして渡される
Rustは常にcall by valueでvalueをコピーする
大きなものをコピーされたくないならば
渡すvalueとしてその参照を指定する
すると参照すなわちポインタ値のみがコピーされて渡される
>> ただしimmutatibleな呼び出しでは関数側が値を変更しないのにコピーするのは無駄なのでコピーされない
immutatibleな呼び出しなんて概念はない
immutableな参照を渡すかmutableな参照を渡すかの選択肢はある
そのポインタ値は常にコピーされる
ポインタ値のコピーはどんな速い言語を作っても避けられずそれが最速
ただし例えば数値単体を渡すなら参照(ポインタ値)を渡すよりも速い
>>777
数MBのデータはスタック領域に入らないのでヒープ領域に開始時に確保すればよい
>> rustは関数呼び出しは基本call by valueで呼び出され、呼び出し時の“値”は基本コピーして渡される
Rustは常にcall by valueでvalueをコピーする
大きなものをコピーされたくないならば
渡すvalueとしてその参照を指定する
すると参照すなわちポインタ値のみがコピーされて渡される
>> ただしimmutatibleな呼び出しでは関数側が値を変更しないのにコピーするのは無駄なのでコピーされない
immutatibleな呼び出しなんて概念はない
immutableな参照を渡すかmutableな参照を渡すかの選択肢はある
そのポインタ値は常にコピーされる
ポインタ値のコピーはどんな速い言語を作っても避けられずそれが最速
ただし例えば数値単体を渡すなら参照(ポインタ値)を渡すよりも速い
>>777
数MBのデータはスタック領域に入らないのでヒープ領域に開始時に確保すればよい
779デフォルトの名無しさん
2023/07/20(木) 15:25:39.14ID:6BSTmMYa780デフォルトの名無しさん
2023/07/20(木) 16:14:28.16ID:zz9s86Uo 古典的なcall by valueの定義におけるコピーと
そのCopyとはまた違う話
ついでに言うとRustにおけるcall by valueの定義と
古典的call by valueの定義は違うので要注意
現代では古典的定義でcall by valueかどうかを考えるのはあまり意味がない
そのCopyとはまた違う話
ついでに言うとRustにおけるcall by valueの定義と
古典的call by valueの定義は違うので要注意
現代では古典的定義でcall by valueかどうかを考えるのはあまり意味がない
781デフォルトの名無しさん
2023/07/20(木) 19:56:50.64ID:neDY19sM >>779
そのコピーはビットコピーの話でCopy実装型の話とは別
Copy非実装型でもムーブするとビットコピーされる
そもそもCPUやメモリにムーブなんてものは存在しなくてMOV (MOVE)命令ですらビットコピーが行われる
ただしビットコピーは最適化で消えうる
例えば別の変数にムーブしても最適化でビットコピーは消えうる
サイズの大きな値を関数でムーブ返ししてもRTO (Return Value Optimization)により呼び出し元スタックフレームに直接生成できるならビットコピーは消えうる
サイズの小さい値を関数でムーブ返しするとレジスタ返しとなる等
そのコピーはビットコピーの話でCopy実装型の話とは別
Copy非実装型でもムーブするとビットコピーされる
そもそもCPUやメモリにムーブなんてものは存在しなくてMOV (MOVE)命令ですらビットコピーが行われる
ただしビットコピーは最適化で消えうる
例えば別の変数にムーブしても最適化でビットコピーは消えうる
サイズの大きな値を関数でムーブ返ししてもRTO (Return Value Optimization)により呼び出し元スタックフレームに直接生成できるならビットコピーは消えうる
サイズの小さい値を関数でムーブ返しするとレジスタ返しとなる等
782デフォルトの名無しさん
2023/07/20(木) 22:07:49.98ID:YJW86g9/ call by valueのコピーはビットコピーなんて定義はない
ビットコピーかどうかはimplementation detail
ビットコピーかどうかはimplementation detail
783デフォルトの名無しさん
2023/07/20(木) 22:17:52.36ID:mzA35L2k レジスタかメモリへのビットコピー以外に渡す手段はない
現行のコンピューターでは
現行のコンピューターでは
784デフォルトの名無しさん
2023/07/22(土) 01:08:25.26ID:9fslOp72 メモリ管理について質問です
Rustは「GCをしない言語」を謳っています
一応「GCを心配する必要はない、フラグメンテーションなも起きない、メモリ不足になったらそれはフラグメンテーションではなくて元々のメモリ不足」と言い切れればいいんですけど、実際にはそうではなく、下手なデータ管理をすればフラメンテーションは発生するようです
まぁそりゃそうなんですけど
https://hackernoon.com/ja/Rust%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%A7%E3%83%92%E3%83%BC%E3%83%97%E3%81%AE%E6%96%AD%E7%89%87%E5%8C%96%E3%82%92%E8%A6%8B%E3%81%A4%E3%81%91%E3%81%A6%E5%9B%9E%E9%81%BF%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95
ということはプログラマ極力フラグメンテーションが発生しないように注意したいところですが、しかしRustのアロケータはどういう状況でフラグメンテーションを発生させるか、どうやれば防げるかの資料が見つかりません、なので先のリンクの人は自分で調べてたみたいです
これ誰かご存知の方いますか?
具体的には同じ型のSizedのデータA,を作成して先にAを消し、その後同じ型のCを作った場合、Rustシステムはその時点で開いてる穴のAの抜け穴を利用してそこにCを割り当ててくれるんでしょうか、
それともBが消えるまではAのあった場所も“欠番扱い”になるんでしょうか?
Rustは「GCをしない言語」を謳っています
一応「GCを心配する必要はない、フラグメンテーションなも起きない、メモリ不足になったらそれはフラグメンテーションではなくて元々のメモリ不足」と言い切れればいいんですけど、実際にはそうではなく、下手なデータ管理をすればフラメンテーションは発生するようです
まぁそりゃそうなんですけど
https://hackernoon.com/ja/Rust%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%A7%E3%83%92%E3%83%BC%E3%83%97%E3%81%AE%E6%96%AD%E7%89%87%E5%8C%96%E3%82%92%E8%A6%8B%E3%81%A4%E3%81%91%E3%81%A6%E5%9B%9E%E9%81%BF%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95
ということはプログラマ極力フラグメンテーションが発生しないように注意したいところですが、しかしRustのアロケータはどういう状況でフラグメンテーションを発生させるか、どうやれば防げるかの資料が見つかりません、なので先のリンクの人は自分で調べてたみたいです
これ誰かご存知の方いますか?
具体的には同じ型のSizedのデータA,を作成して先にAを消し、その後同じ型のCを作った場合、Rustシステムはその時点で開いてる穴のAの抜け穴を利用してそこにCを割り当ててくれるんでしょうか、
それともBが消えるまではAのあった場所も“欠番扱い”になるんでしょうか?
785デフォルトの名無しさん
2023/07/22(土) 02:40:42.91ID:htX2UcZa >>784
アロケーションやフラグメンテーションはRustの言語システムの範囲外
例えばOSがない環境も含めてアロケータを自作もできるようになっている
普通にOSなどある環境を使うとRustはそこでの標準のアロケータをそのままグローバルアロケータとして用いる
つまり環境毎に異なるものが使われていてRustとは全く関係がない問題であることがわかる
もちろんRustでは自分でアロケータを変えることもできる
グローバルアロケータを丸ごと変える方法とBoxやVecなどで個別にアロケータを指定する方法がある
使用環境の標準のアロケータで何か問題が起きていると感じたらその例のように別のものと交換して比較してベストなアロケータを選べばよい
もう一つ全く別のアプローチとしてそれらアロケータに頼るのではなくプログラムのレベルでまとまったメモリの割り当て管理する方法もある
この方法は全て自分の制御下におけるため様々な特性のあるクレートがありもちろん自作もできる
アロケーションやフラグメンテーションはRustの言語システムの範囲外
例えばOSがない環境も含めてアロケータを自作もできるようになっている
普通にOSなどある環境を使うとRustはそこでの標準のアロケータをそのままグローバルアロケータとして用いる
つまり環境毎に異なるものが使われていてRustとは全く関係がない問題であることがわかる
もちろんRustでは自分でアロケータを変えることもできる
グローバルアロケータを丸ごと変える方法とBoxやVecなどで個別にアロケータを指定する方法がある
使用環境の標準のアロケータで何か問題が起きていると感じたらその例のように別のものと交換して比較してベストなアロケータを選べばよい
もう一つ全く別のアプローチとしてそれらアロケータに頼るのではなくプログラムのレベルでまとまったメモリの割り当て管理する方法もある
この方法は全て自分の制御下におけるため様々な特性のあるクレートがありもちろん自作もできる
786デフォルトの名無しさん
2023/07/22(土) 02:50:52.30ID:htX2UcZa >>784
後半の質問はもちろん再割り当てしてくれる
どの環境の標準アロケータでもそのような普通のことは当然している
だからアロケータの変更などは何か問題が起きてから考えればいい
質問の挙動ならばアドレスを表示させればわかる
fn main() {
// aを割り当て
let a = foo(123);
println!("a: {:p}", &*a);
// bを割り当て
let b = foo(456);
println!("b: {:p}", &*b);
// aを解放
std::mem::drop(a);
// cを割り当て
let c = foo(789);
println!("c: {:p}", &*c);
// aとcは同じアドレスになっている
}
fn foo(init: i32) -> Box<[i32; 1000]> {
std::boxed::Box::new([init; 1000])
}
後半の質問はもちろん再割り当てしてくれる
どの環境の標準アロケータでもそのような普通のことは当然している
だからアロケータの変更などは何か問題が起きてから考えればいい
質問の挙動ならばアドレスを表示させればわかる
fn main() {
// aを割り当て
let a = foo(123);
println!("a: {:p}", &*a);
// bを割り当て
let b = foo(456);
println!("b: {:p}", &*b);
// aを解放
std::mem::drop(a);
// cを割り当て
let c = foo(789);
println!("c: {:p}", &*c);
// aとcは同じアドレスになっている
}
fn foo(init: i32) -> Box<[i32; 1000]> {
std::boxed::Box::new([init; 1000])
}
787デフォルトの名無しさん
2023/07/22(土) 08:56:00.85ID:40PxJ+ku やはりそうですね
Rustはヒープエリアのメモリ管理は言語システムでは提供しない、その性能については規定しない立場なんですね
なので先の質問のような場合「Rustでは必ずうまいことやってくれる」とは言えず「コンパイラ××、実行環境××で実測したらうまく行った」程度しか言えず、同じソースを別の環境に持ってやったらダメだったもありうるんですね
結局ヒープを使わざるを得ない場合には「自分でメモリ割り当てをうまいことやる」しかないんですね
今やってる例だとスタックには入らないって怒られるし、ヒープ使うなら、うまくいくかはやってみるまでわからないというのはちょっと面白くないなぁ
Rustはヒープエリアのメモリ管理は言語システムでは提供しない、その性能については規定しない立場なんですね
なので先の質問のような場合「Rustでは必ずうまいことやってくれる」とは言えず「コンパイラ××、実行環境××で実測したらうまく行った」程度しか言えず、同じソースを別の環境に持ってやったらダメだったもありうるんですね
結局ヒープを使わざるを得ない場合には「自分でメモリ割り当てをうまいことやる」しかないんですね
今やってる例だとスタックには入らないって怒られるし、ヒープ使うなら、うまくいくかはやってみるまでわからないというのはちょっと面白くないなぁ
788デフォルトの名無しさん
2023/07/22(土) 09:24:29.44ID:htX2UcZa >>787
OS環境などが提供するアロケータ(=Rustのデフォルトのアロケータ)をそのまま使う時だけ環境依存になる
これはRustに限らずそれをそのまま使う全てのプログラミング言語で起こるためRustの問題ではない
しかもRustは次のように解決策がある言語だ
アロケータ含めて同じソースを持っていってそれを使うならば動作も同じになるので大丈夫
例えば先ほどのケースのようにjemallocをアロケータとして指定して使えば環境依存ではなくなる
よほど特殊なケースでの特殊な効率化を目指さない限り自分でアロケータを書く必要はない
OS環境などが提供するアロケータ(=Rustのデフォルトのアロケータ)をそのまま使う時だけ環境依存になる
これはRustに限らずそれをそのまま使う全てのプログラミング言語で起こるためRustの問題ではない
しかもRustは次のように解決策がある言語だ
アロケータ含めて同じソースを持っていってそれを使うならば動作も同じになるので大丈夫
例えば先ほどのケースのようにjemallocをアロケータとして指定して使えば環境依存ではなくなる
よほど特殊なケースでの特殊な効率化を目指さない限り自分でアロケータを書く必要はない
789デフォルトの名無しさん
2023/07/22(土) 09:54:09.20ID:JFG0S3Tm まぁそうですね
Rustにしたら今までのプログラミング言語で常に問題視されてたアロケーション問題が魔法のように解決するなどという事があるはずはないですね
Rustにしたら今までのプログラミング言語で常に問題視されてたアロケーション問題が魔法のように解決するなどという事があるはずはないですね
790デフォルトの名無しさん
2023/07/22(土) 09:59:59.87ID:htX2UcZa 何を問題にしているのか明確にせよ
Rustはアロケータすら自由に入れ替えられる
つまり理論上可能なことはRustならば解決できる
Rustはアロケータすら自由に入れ替えられる
つまり理論上可能なことはRustならば解決できる
791デフォルトの名無しさん
2023/07/22(土) 10:40:08.11ID:S6pKsqQS 複オジーww
792デフォルトの名無しさん
2023/07/22(土) 10:45:39.31ID:xU//sEEH 問題は普通のプログラミング言語の“メモリ割り当て問題”です
別にRust特有の問題ではなく、どんなプログラミング言語でも発生する問題ですよ
Rustではどういう戦略で当たってるのかなと
もちろんこの戦略に関して“どんな場合でもうまくいくまほうのような解決策”などありません、そして多くの場合この処理は大変重たい処理でとても重大な問題を引き起こします
画像処理、動画処理、AIの機械学習の処理などで大きなデータの割り当て、更新、消去は処理中かなり頻繁に起こり、データサイズによってはフラグメンテーションが大きな問題になる事などしょっちゅうです
結局プログラマはほとんどの場合自前でアロケーション問題を解決させられるわけでそこにもはや“言語のデフォルトに任せておけばいける”幻想は抱いてません
しかしRustはどうしてるんだろうと、もしRustでやれといわれた場合があったと妄想して自分にそれができるようにしときたいなと思って自習中なんです、まぁ絶対なさそうですが
今まで色々資料読んだ範囲内だと感覚的には「Rustはメモリ管理に関しては言語内部的には頑張らない、外部環境で処理するか、可読性を犠牲にガチャガチャしろ」というスタンスで提供されてる感じはしてます
別にRust特有の問題ではなく、どんなプログラミング言語でも発生する問題ですよ
Rustではどういう戦略で当たってるのかなと
もちろんこの戦略に関して“どんな場合でもうまくいくまほうのような解決策”などありません、そして多くの場合この処理は大変重たい処理でとても重大な問題を引き起こします
画像処理、動画処理、AIの機械学習の処理などで大きなデータの割り当て、更新、消去は処理中かなり頻繁に起こり、データサイズによってはフラグメンテーションが大きな問題になる事などしょっちゅうです
結局プログラマはほとんどの場合自前でアロケーション問題を解決させられるわけでそこにもはや“言語のデフォルトに任せておけばいける”幻想は抱いてません
しかしRustはどうしてるんだろうと、もしRustでやれといわれた場合があったと妄想して自分にそれができるようにしときたいなと思って自習中なんです、まぁ絶対なさそうですが
今まで色々資料読んだ範囲内だと感覚的には「Rustはメモリ管理に関しては言語内部的には頑張らない、外部環境で処理するか、可読性を犠牲にガチャガチャしろ」というスタンスで提供されてる感じはしてます
793デフォルトの名無しさん
2023/07/22(土) 11:31:54.16ID:l0FUWY0y794デフォルトの名無しさん
2023/07/22(土) 11:35:08.26ID:nQhdUCcc この人はそういう人なので適当に切り上げることをおすすめします
795デフォルトの名無しさん
2023/07/22(土) 11:38:03.03ID:xU//sEEH まぁ無理です
できないことをできると言い張るのはもはや学問ではなく信仰です
できないことをできると言い張るのはもはや学問ではなく信仰です
796デフォルトの名無しさん
2023/07/22(土) 11:49:43.86ID:YLqzZrt5 A造る
B造る
A消す
C造る
AのサイズよりCのサイズが小さいとき
A-Cのサイズ分のフラグメントが発生
B造る
A消す
C造る
AのサイズよりCのサイズが小さいとき
A-Cのサイズ分のフラグメントが発生
797デフォルトの名無しさん
2023/07/22(土) 12:06:07.26ID:24bvSiNd >>792
>> 今まで色々資料読んだ範囲内だと感覚的には「Rustはメモリ管理に関しては言語内部的には頑張らない、外部環境で処理するか、可読性を犠牲にガチャガチャしろ」というスタンスで提供されてる感じはしてます
メモリ管理の階層の違いを理解できていなさそうだが
メモリアロケータの話ならばRustはC++と同様に交換自由でライブラリ選択可能
可読性を犠牲にガチャガチャする必要はなくRustでは#[global_allocator]で指定するだけで交換可能
>> 今まで色々資料読んだ範囲内だと感覚的には「Rustはメモリ管理に関しては言語内部的には頑張らない、外部環境で処理するか、可読性を犠牲にガチャガチャしろ」というスタンスで提供されてる感じはしてます
メモリ管理の階層の違いを理解できていなさそうだが
メモリアロケータの話ならばRustはC++と同様に交換自由でライブラリ選択可能
可読性を犠牲にガチャガチャする必要はなくRustでは#[global_allocator]で指定するだけで交換可能
798デフォルトの名無しさん
2023/07/22(土) 13:41:17.13ID:7Mz5wCRP 理解できてなかったらしい
もういいや
もういいや
799デフォルトの名無しさん
2023/07/22(土) 13:57:51.76ID:u4m8T/// >>792はC言語でたとえるとmallocを使ったメモリ管理とmallocの中のメモリ管理の違いをわかっていない初心者かな
800デフォルトの名無しさん
2023/07/22(土) 13:58:55.74ID:NWfMWzFP そうです
初心者でした
お騒がせして申し訳ありませんでした
初心者でした
お騒がせして申し訳ありませんでした
801デフォルトの名無しさん
2023/07/22(土) 14:25:05.31ID:AxAuiZIS802デフォルトの名無しさん
2023/07/22(土) 14:42:32.24ID:QLIAp4G5 >>801
そんなに単純じゃないよ。
確保しようとする大きさによって違う領域から割り当てるような実装も普通。
順序良く割り当てるわけではなく、
そのときの状況によって効率的になるように采配する。
仮に断片化を意図的に起こしてでも総合的に断片化の確率を減らすような
戦略を持っているのかもしれないし、
よほど深刻な場合を除いて使う側はアロケータの中なんぞ忘れておくのが吉。
そんなに単純じゃないよ。
確保しようとする大きさによって違う領域から割り当てるような実装も普通。
順序良く割り当てるわけではなく、
そのときの状況によって効率的になるように采配する。
仮に断片化を意図的に起こしてでも総合的に断片化の確率を減らすような
戦略を持っているのかもしれないし、
よほど深刻な場合を除いて使う側はアロケータの中なんぞ忘れておくのが吉。
803デフォルトの名無しさん
2023/07/22(土) 14:54:17.36ID:NWfMWzFP もちろん発生しますよ
どんな場合でも最高次数にうまくいく魔法のような戦略なんてありません
なのでケースバイケースで場合に応じて戦略を使い分けなければならない
しかしOSの実行環境なんかのアロケーターはプログラムの内部情報を何一つ持ってないから「開きメモリのリストを持っておいて最初に見つかったスキマにアサインする、足りなくなったらGC」以外に戦略の採りようがない、だから従来のプログラミング言語は自分でGCするわけです、少なくともコンパイラはコンパイルする時点でどれくらいの頻度でどれくらいのサイズのアロケーション要求が発生するかある程度情報が得られるからそれを利用してよりよい割り当て戦略をとれるチャンスがあるからです、なんならその情報をコンパイラに教えるnotificationをつけられるように設計する事もできる
しかしそれとて限界がある、だからRustはもうそれすらやらない、アロケーションは自分でやれ、そのためのツールはある程度は言語内部で用意する、ダメなら言語外部のツール使え、という「無理してやってもどうせ“最適”には程遠いからやらない」んでしょう
逆に言えばRustでプログラム組むとき、特にでかいデータの作成、廃棄を繰り返すような場合はプログラマはかなり練度が必要になるんでしょう
立ち位置としてそれくらいの事がこなせるユーザーをプログラマとして想定してるという事です
学習コストが高いんじゃなくてそもそもプログラマに要求されてる水準が高めなんですね
どんな場合でも最高次数にうまくいく魔法のような戦略なんてありません
なのでケースバイケースで場合に応じて戦略を使い分けなければならない
しかしOSの実行環境なんかのアロケーターはプログラムの内部情報を何一つ持ってないから「開きメモリのリストを持っておいて最初に見つかったスキマにアサインする、足りなくなったらGC」以外に戦略の採りようがない、だから従来のプログラミング言語は自分でGCするわけです、少なくともコンパイラはコンパイルする時点でどれくらいの頻度でどれくらいのサイズのアロケーション要求が発生するかある程度情報が得られるからそれを利用してよりよい割り当て戦略をとれるチャンスがあるからです、なんならその情報をコンパイラに教えるnotificationをつけられるように設計する事もできる
しかしそれとて限界がある、だからRustはもうそれすらやらない、アロケーションは自分でやれ、そのためのツールはある程度は言語内部で用意する、ダメなら言語外部のツール使え、という「無理してやってもどうせ“最適”には程遠いからやらない」んでしょう
逆に言えばRustでプログラム組むとき、特にでかいデータの作成、廃棄を繰り返すような場合はプログラマはかなり練度が必要になるんでしょう
立ち位置としてそれくらいの事がこなせるユーザーをプログラマとして想定してるという事です
学習コストが高いんじゃなくてそもそもプログラマに要求されてる水準が高めなんですね
804デフォルトの名無しさん
2023/07/22(土) 16:19:13.40ID:2BLjTz4O >>803
間違い多いな
まず一般的にGCはフラグメンテーションを解決しない
特にマークアンドスイープ方式のGCや参照カウント方式のGCはフラグメンテーションは放置で関与しない
Rustについての記述は間違いだらけでなんとも言いようがない
言語外部のツール使えとはトンデモすぎて何を言ってるのかもわからない
フラグメンテーションを起こし得るメモリアロケーターについてRustはC/C++と同じ立場で同じものを使う
C/C++/Rust共通の話として同じようにjemallocなど別のメモリアロケーターを使うことができる
Rustだけ特別な方法をとったり特別な性質をもったりはしておらずフラグメンテーションについてもC/C++と同じ
間違い多いな
まず一般的にGCはフラグメンテーションを解決しない
特にマークアンドスイープ方式のGCや参照カウント方式のGCはフラグメンテーションは放置で関与しない
Rustについての記述は間違いだらけでなんとも言いようがない
言語外部のツール使えとはトンデモすぎて何を言ってるのかもわからない
フラグメンテーションを起こし得るメモリアロケーターについてRustはC/C++と同じ立場で同じものを使う
C/C++/Rust共通の話として同じようにjemallocなど別のメモリアロケーターを使うことができる
Rustだけ特別な方法をとったり特別な性質をもったりはしておらずフラグメンテーションについてもC/C++と同じ
805デフォルトの名無しさん
2023/07/22(土) 16:41:16.06ID:NWfMWzFP 素人なものですいません
スレ汚しすいませんでした
スレ汚しすいませんでした
806デフォルトの名無しさん
2023/07/22(土) 17:02:30.53ID:NRmzieuj >まず一般的にGCはフラグメンテーションを解決しない
マーク&スウィープ方式は一般的にコンパクションもやってるぞ
マーク&スウィープ方式は一般的にコンパクションもやってるぞ
807デフォルトの名無しさん
2023/07/22(土) 17:07:41.36ID:2BLjTz4O808デフォルトの名無しさん
2023/07/22(土) 17:59:22.96ID:QLIAp4G5809デフォルトの名無しさん
2023/07/22(土) 18:05:22.75ID:YLqzZrt5 そういえば君らのメモリ管理の会話でLinkedListの使い道思い出したわ
Rustやその他の言語側じゃなくてOS側のメモリ管理にLinkedList使われてるわ
Rustやその他の言語側じゃなくてOS側のメモリ管理にLinkedList使われてるわ
810デフォルトの名無しさん
2023/07/22(土) 18:42:28.71ID:2BLjTz4O811デフォルトの名無しさん
2023/07/22(土) 19:01:55.55ID:TsQs+vXV812デフォルトの名無しさん
2023/07/22(土) 19:18:33.46ID:2BLjTz4O >>811
compactionをする前にマークアンドスイープGC自体は既に終わっていて独立した別の行為
実際にそれら言語では世代別GCが行われていていて新入り若手のオブジェクトはコピーGCを行なうが古いオブジェクトはマークアンドスイープのみで再配置しない方法が一般的
compactionをする前にマークアンドスイープGC自体は既に終わっていて独立した別の行為
実際にそれら言語では世代別GCが行われていていて新入り若手のオブジェクトはコピーGCを行なうが古いオブジェクトはマークアンドスイープのみで再配置しない方法が一般的
813デフォルトの名無しさん
2023/07/22(土) 19:31:27.25ID:nB6v7J6K 隔離スレ行けアスペジジー
814デフォルトの名無しさん
2023/07/22(土) 20:04:44.58ID:2BLjTz4O 再配置はデータコピーとそこへのポインタ全て書き換えでコストが大きすぎるから可能な限り避けるのが正しい
世代別GCで若手オブジェクトだけに限ってコピーGCの対象にするのも若手の大半は一時的利用でコピーしなくて済むため
Rustではそんなコストをかけないだけでなくヒープ確保解放のコストすら減らすことと一石二鳥で解決する方法も取られている
例えばbumpalo crateはまとまった領域を持って追記していくだけで個別の解放コストゼロ(=何もしない)と個別の確保コストも最小(=追記のみor足りないとまとまったお代わり)のアリーナアロケータ
つまり未使用領域の再利用をしないことで管理不要となり最高速になるとともにまとめて一気に最高速で返す
具体的にはサーバーまたはバッチ処理で各対象固有データのみそこから確保してその対象を終える時に破棄
これはフラグメンテーションを防ぐのに非常に効果的な方法
世代別GCで若手オブジェクトだけに限ってコピーGCの対象にするのも若手の大半は一時的利用でコピーしなくて済むため
Rustではそんなコストをかけないだけでなくヒープ確保解放のコストすら減らすことと一石二鳥で解決する方法も取られている
例えばbumpalo crateはまとまった領域を持って追記していくだけで個別の解放コストゼロ(=何もしない)と個別の確保コストも最小(=追記のみor足りないとまとまったお代わり)のアリーナアロケータ
つまり未使用領域の再利用をしないことで管理不要となり最高速になるとともにまとめて一気に最高速で返す
具体的にはサーバーまたはバッチ処理で各対象固有データのみそこから確保してその対象を終える時に破棄
これはフラグメンテーションを防ぐのに非常に効果的な方法
815デフォルトの名無しさん
2023/07/22(土) 21:33:49.24ID:kHWj4RWJ まーた複オジが知ったかぶりして無知晒してるw
初心者かなww
初心者かなww
816デフォルトの名無しさん
2023/07/22(土) 22:04:25.70ID:kdu4dn9d Rust使うくらいならJavaかC#で良いのでは?
817デフォルトの名無しさん
2023/07/22(土) 22:08:51.83ID:wR/xGD2g RustとC#だとどっちがいいの?
818デフォルトの名無しさん
2023/07/23(日) 02:44:41.28ID:lmJrnSr9 >>814
GCのないRustが速いわけだ
GCのないRustが速いわけだ
819デフォルトの名無しさん
2023/07/23(日) 11:09:10.60ID:kMNWXVHy >>814
C/C++でも同じアルゴリズムのアロケータあるで
C/C++でも同じアルゴリズムのアロケータあるで
820デフォルトの名無しさん
2023/07/23(日) 11:10:16.97ID:dOw1chPf >>816
🤮
🤮
821デフォルトの名無しさん
2023/07/25(火) 06:32:45.09ID:7X7HwnNv >>819
言語に関係なくそこへ行き着くんだよな
もちろん通常はフラグメンテーションなんか気にせずに普通にコードを書けばよく
稼働時間の長いプロセスでフラグメンテーションが実際に起きた時の解決策の一つ
言語に関係なくそこへ行き着くんだよな
もちろん通常はフラグメンテーションなんか気にせずに普通にコードを書けばよく
稼働時間の長いプロセスでフラグメンテーションが実際に起きた時の解決策の一つ
822デフォルトの名無しさん
2023/07/27(木) 13:16:19.02ID:/bGsBsBb play-rustのコードのコピペのやり方教えて下さい
具体的にはお題スレの
https://play.rust-lang.org/?version=stable&mode=release&edition=2021&gist=f627f3a5de4a0c467f015a8b1527c141
のコードコピペする方法がわかりません
よろしくお願いします
具体的にはお題スレの
https://play.rust-lang.org/?version=stable&mode=release&edition=2021&gist=f627f3a5de4a0c467f015a8b1527c141
のコードコピペする方法がわかりません
よろしくお願いします
823デフォルトの名無しさん
2023/07/27(木) 14:04:04.46ID:90/I2Z5n rustは型推論をしてくれると聞いたのですけど、結果どういう型になったか調べる方法はありますか?
Haskellのghciの:tに当たるやつです
例えはghci内で
prelude> let f n = sum [ x^n | x<- [1..5] ]
として
prelude> :t f
とすれば
( Num a, Integral b ) => b -> a
のように返してくれます
rustでコンパイラの型推論の結果どういう型に決定したのか調べる方法はありますか?
Haskellのghciの:tに当たるやつです
例えはghci内で
prelude> let f n = sum [ x^n | x<- [1..5] ]
として
prelude> :t f
とすれば
( Num a, Integral b ) => b -> a
のように返してくれます
rustでコンパイラの型推論の結果どういう型に決定したのか調べる方法はありますか?
824デフォルトの名無しさん
2023/07/27(木) 14:28:57.60ID:p+3LvAw4 >>823
LSP 対応のエディタ (VSCode など) を使ってるならそのへんにカーソルを合わせるだけで型は見れるよ。
LSP 対応のエディタ (VSCode など) を使ってるならそのへんにカーソルを合わせるだけで型は見れるよ。
825デフォルトの名無しさん
2023/07/27(木) 21:59:53.82ID:x4QyUuiY >>823
安直な方法としては関数の戻り型なら -> i32と嘘の型宣言を指定すれば型不一致で正しい具体型をコンパイルエラーに表示してくれる
プログラムで表示したいならこれ
fn get_type<T>(_: T) -> &'static str {
std::any::type_name::<T>()
}
安直な方法としては関数の戻り型なら -> i32と嘘の型宣言を指定すれば型不一致で正しい具体型をコンパイルエラーに表示してくれる
プログラムで表示したいならこれ
fn get_type<T>(_: T) -> &'static str {
std::any::type_name::<T>()
}
826デフォルトの名無しさん
2023/07/27(木) 23:11:30.70ID:sTDTKxns827デフォルトの名無しさん
2023/07/27(木) 23:12:33.60ID:paov2RlH rustの型推論って曖昧なことを許容したっけ?
すべて一意にならないとならないと思ってたけど
すべて一意にならないとならないと思ってたけど
828デフォルトの名無しさん
2023/07/28(金) 19:39:32.86ID:4cjf/6GX >>827
正しい
ジェネリックであってもパラメタは各々で必ず一意に静的に確定せねばならず
impl Traitで型宣言しても各々で一意に具体的な型に静的に確定する
特にそれが関数の引数ならば生成コードは単相化される
ただしdyn Traitはそれらが静的ではなく実行時のオブジェクト生成毎に個別に一意の具体的な型に確定する点で異なる
コンパイル時の静的な生成コードは複数の型で共有となるためvtableを持って対処している
正しい
ジェネリックであってもパラメタは各々で必ず一意に静的に確定せねばならず
impl Traitで型宣言しても各々で一意に具体的な型に静的に確定する
特にそれが関数の引数ならば生成コードは単相化される
ただしdyn Traitはそれらが静的ではなく実行時のオブジェクト生成毎に個別に一意の具体的な型に確定する点で異なる
コンパイル時の静的な生成コードは複数の型で共有となるためvtableを持って対処している
829デフォルトの名無しさん
2023/07/29(土) 16:54:29.41ID:Nh9kevR9 なるほど
Rustは最終的にコンパイルが終わって型が完全に推論が終わって単相型が決定した状態でしかわからないのかな
当然get_typeで得られるstrは推論終わって単相型が割り当てられた後の型しかわからないんやな
Rustは最終的にコンパイルが終わって型が完全に推論が終わって単相型が決定した状態でしかわからないのかな
当然get_typeで得られるstrは推論終わって単相型が割り当てられた後の型しかわからないんやな
830デフォルトの名無しさん
2023/07/29(土) 18:53:43.03ID:nTghkNr5 コードを書いた時点で型は決まるし書いた人は型を把握できる
ジェネリックな関数だとしても型パラメタ以外の部分は確定している
その関数を呼び出す側が最後のピースとして型パラメタを指定して完全確定する
ジェネリックな関数だとしても型パラメタ以外の部分は確定している
その関数を呼び出す側が最後のピースとして型パラメタを指定して完全確定する
831デフォルトの名無しさん
2023/07/29(土) 19:01:27.37ID:mkN3FcGi そうなんよねぇ
ML型型理論ならexpression毎に最も一般的な型が決まる
Haskellは型を指定しない場合自動的にその最も一般的な型を確定させてghciとかで調べられる
今のところ上がってる方法ではRustではそれに該当する方法はなさそう
ML型型理論ならexpression毎に最も一般的な型が決まる
Haskellは型を指定しない場合自動的にその最も一般的な型を確定させてghciとかで調べられる
今のところ上がってる方法ではRustではそれに該当する方法はなさそう
832デフォルトの名無しさん
2023/07/29(土) 19:02:57.30ID:mkN3FcGi イヤまだvscideとかのやつは試してないな
これならできるんかな?
これならできるんかな?
833デフォルトの名無しさん
2023/07/29(土) 20:36:12.76ID:JeVM9tS2 こいつダメだわ
ある意味複オジ2世
ある意味複オジ2世
834デフォルトの名無しさん
2023/07/29(土) 21:40:33.16ID:EPaDIYai >>829
> Rustは最終的にコンパイルが終わって型が完全に推論が終わって単相型が決定した状態でしかわからないのかな
いやもうrustは変数宣言時に定義した型の変更を許さないのよ(基本的に)
だから型推論は変数宣言時のものを利用したり、関数の場合は返値、手打ちの数字の場合はデフォルトの型に決め打ちされて型推論されるわけ
いちいち型を調べる必要がない
ジェネリックに関しても基本的に場合分け
> Rustは最終的にコンパイルが終わって型が完全に推論が終わって単相型が決定した状態でしかわからないのかな
いやもうrustは変数宣言時に定義した型の変更を許さないのよ(基本的に)
だから型推論は変数宣言時のものを利用したり、関数の場合は返値、手打ちの数字の場合はデフォルトの型に決め打ちされて型推論されるわけ
いちいち型を調べる必要がない
ジェネリックに関しても基本的に場合分け
835デフォルトの名無しさん
2023/07/29(土) 21:44:15.48ID:EPaDIYai pythonとかjavascriptとか勝手に型を変更する(ような振る舞いをする→変更するとは言ってない)
言語なんてサイテーだと個人的には思う
言語なんてサイテーだと個人的には思う
836デフォルトの名無しさん
2023/07/29(土) 22:05:07.65ID:2dUASh9D837デフォルトの名無しさん
2023/07/29(土) 22:10:13.37ID:2dUASh9D ごめん、誤字った
rustの型システムはMLじゃないの?
いわゆる型の全体と命題論理の全体を一対一に対応させる
で、その命題論理の目モデルを探す事=単相型を決定する事がMLの型推論システムで、Rustもそれ採用してるんだと思ってるんだけど
で単相型が割り当てられる“命題”に対応してるものが多相型と呼ぶんだと教えてもらった事あるけど
rustの型システムはMLじゃないの?
いわゆる型の全体と命題論理の全体を一対一に対応させる
で、その命題論理の目モデルを探す事=単相型を決定する事がMLの型推論システムで、Rustもそれ採用してるんだと思ってるんだけど
で単相型が割り当てられる“命題”に対応してるものが多相型と呼ぶんだと教えてもらった事あるけど
838デフォルトの名無しさん
2023/07/29(土) 22:19:51.45ID:381IW7f/ も少し書くなら基本的にrustもhaskellも型システムは基本的な原理は同じじゃないのって話
それを説明する用語としてRust特定の説明の仕方をしてるのかもしれないけど説明の仕方や用語の使い方を変えたところでどっちもカリーハワード理論に基づく型システムじゃない?
それを説明する用語としてRust特定の説明の仕方をしてるのかもしれないけど説明の仕方や用語の使い方を変えたところでどっちもカリーハワード理論に基づく型システムじゃない?
839デフォルトの名無しさん
2023/07/29(土) 22:51:50.32ID:381IW7f/ もし同じならHaskellと同じく例えば
mysum [] = 0
mysum (a:as) = a + ( mysum as )
なら Haskell ならmysumの型は
( Num a ) => [ a ] -> a
と推論されます
RustでもML型システムである限り少なくとも内部的には同じような型が割り当てられてるはずだと思うんですけど
もちろんこれら推論された型を全部総合して実装時には特定の単相型が割り当てられます
この辺のメカニズムはHaskellもRustも同じじゃないんでしょうか?
mysum [] = 0
mysum (a:as) = a + ( mysum as )
なら Haskell ならmysumの型は
( Num a ) => [ a ] -> a
と推論されます
RustでもML型システムである限り少なくとも内部的には同じような型が割り当てられてるはずだと思うんですけど
もちろんこれら推論された型を全部総合して実装時には特定の単相型が割り当てられます
この辺のメカニズムはHaskellもRustも同じじゃないんでしょうか?
840デフォルトの名無しさん
2023/07/29(土) 23:06:20.41ID:MBm8IaU2 まずRustの数値リテラルはHaskellと違って多相な型を持たないです
841デフォルトの名無しさん
2023/07/29(土) 23:25:14.79ID:I6XWshKt >>839
分かってる気になっておかしなことを書く癖を直したほうがいいと思うが…
分かってる気になっておかしなことを書く癖を直したほうがいいと思うが…
842デフォルトの名無しさん
2023/07/29(土) 23:36:28.14ID:I6XWshKt 人間としての推論機構が間違っている
基礎を勉強してルールとしてそれを覚えてから
それを基に推論を行わないと意味がないと知るべき
基礎を勉強してルールとしてそれを覚えてから
それを基に推論を行わないと意味がないと知るべき
843デフォルトの名無しさん
2023/07/29(土) 23:51:52.56ID:nTghkNr5 >>831
最も一般的な型ではダメでRustは唯一に確定しなければならない
Rustは関数(メソッド)の引数も返り値も型宣言が必須だけど
そこでの型はジェネリックで型パラメータを持つものも多く
その型パラメータのトレイト境界などによる制約とそのトレイト実装をする型が複数あることから複数解も生じる
複数解がありうるならばコンパイルエラーとなり明示的な型指定を求められる
唯一の例外が数値リテラルの利用により数値型までは確定している時でそれが整数ならば自動的にi32型に解決される
最も一般的な型ではダメでRustは唯一に確定しなければならない
Rustは関数(メソッド)の引数も返り値も型宣言が必須だけど
そこでの型はジェネリックで型パラメータを持つものも多く
その型パラメータのトレイト境界などによる制約とそのトレイト実装をする型が複数あることから複数解も生じる
複数解がありうるならばコンパイルエラーとなり明示的な型指定を求められる
唯一の例外が数値リテラルの利用により数値型までは確定している時でそれが整数ならば自動的にi32型に解決される
844デフォルトの名無しさん
2023/07/30(日) 00:16:28.33ID:psEFm3Dt >>840
その説明はよくrustの解説本にあるけど多分字面通りの意味にとってはいけないんじゃないかと
だってプログラム全体を見なければ型なんか決められるはずない
ML型の型システムである限りHaskellのexpressionから定まる最も一般的な多相型持ってると思う、でなければML型型システムと呼べない
さっきあげたmysumなんかその典型、あのmusumはnum classに属するすべての型で使うことができる、もしこのような多相型を持たない理論ならすべての足し算を持つクラス全てにほとんど同じsumを定義させられることになる、それを避けられるのがML型システムの1番の売りなんだから
てか上の例のmysumに相当する書き方Rustでもできるんでしょ?
無理なん?
その説明はよくrustの解説本にあるけど多分字面通りの意味にとってはいけないんじゃないかと
だってプログラム全体を見なければ型なんか決められるはずない
ML型の型システムである限りHaskellのexpressionから定まる最も一般的な多相型持ってると思う、でなければML型型システムと呼べない
さっきあげたmysumなんかその典型、あのmusumはnum classに属するすべての型で使うことができる、もしこのような多相型を持たない理論ならすべての足し算を持つクラス全てにほとんど同じsumを定義させられることになる、それを避けられるのがML型システムの1番の売りなんだから
てか上の例のmysumに相当する書き方Rustでもできるんでしょ?
無理なん?
845デフォルトの名無しさん
2023/07/30(日) 00:18:56.60ID:psEFm3Dt ML型システムと呼べないは言い過ぎかな?
まぁ型宣言省略しても型推論してくれるならML型型システムと呼べなくはないけど、でも流石にさっきのmysumみたいな記述は許されてるんじゃないの?
まぁ型宣言省略しても型推論してくれるならML型型システムと呼べなくはないけど、でも流石にさっきのmysumみたいな記述は許されてるんじゃないの?
846デフォルトの名無しさん
2023/07/30(日) 00:19:43.44ID:dT6HJfPv ハスケル!
ハスケル!
ハスケル!
その毎度のハスケルおじさんに構うのは止めとけよ
Rubyおじさんと変わらないんだからさあ
自覚のない荒らしだよ
ハスケル!
ハスケル!
その毎度のハスケルおじさんに構うのは止めとけよ
Rubyおじさんと変わらないんだからさあ
自覚のない荒らしだよ
847デフォルトの名無しさん
2023/07/30(日) 00:19:47.09ID:psEFm3Dt848デフォルトの名無しさん
2023/07/30(日) 00:21:02.70ID:dT6HJfPv Haskellおじさんは自分の思いをここに書かないと死んじゃうの?
なんでRustをRustとして扱いたくないの?
なんでRustをRustとして扱いたくないの?
849デフォルトの名無しさん
2023/07/30(日) 00:21:05.69ID:psEFm3Dt850デフォルトの名無しさん
2023/07/30(日) 00:22:04.96ID:dT6HJfPv ハスケルおじさんは壁に向かってハスケルハスケル行ってればいいのに
851デフォルトの名無しさん
2023/07/30(日) 00:24:01.50ID:dT6HJfPv マクロしらんの?
852デフォルトの名無しさん
2023/07/30(日) 00:24:09.72ID:psEFm3Dt >>848
すでに習得した言語の対比して新しい言語に挑戦するのは当たり前やろ?
Haskellの型システム理解するのにどれだけの時間をかけて教科書を読み、論文を読み、プログラミングを組んでみたか、その資産を使いたいとおもうのがそんなに悪いんか?
黙っといてくれよ
すでに習得した言語の対比して新しい言語に挑戦するのは当たり前やろ?
Haskellの型システム理解するのにどれだけの時間をかけて教科書を読み、論文を読み、プログラミングを組んでみたか、その資産を使いたいとおもうのがそんなに悪いんか?
黙っといてくれよ
853デフォルトの名無しさん
2023/07/30(日) 00:24:40.66ID:dT6HJfPv854デフォルトの名無しさん
2023/07/30(日) 00:26:23.01ID:dT6HJfPv 論文読まないとプログラム言語が理解できないんだから困ったやつだろ
推論システムが変
推論システムが変
855デフォルトの名無しさん
2023/07/30(日) 00:29:41.31ID:dT6HJfPv まずは"真面目にRust学習"しろ
そして習得しろ
そして疑問を解決しろ
そして習得しろ
そして疑問を解決しろ
856デフォルトの名無しさん
2023/07/30(日) 00:32:06.97ID:psEFm3Dt >>854
すまんけどオレは論文なんか読まなくても理解できるような天才じゃないんだよ
君は論文なんぞ読まなくても何もかもわかる天才なのかもしれんけど世の中そんな天才ばかりじゃないんだよ
オレみたいに寝食忘れて努力に努力を重ねてやっと話しが分かる鈍才もいるんだよ
鈍才が悪あがきするの邪魔せんでくれ
すまんけどオレは論文なんか読まなくても理解できるような天才じゃないんだよ
君は論文なんぞ読まなくても何もかもわかる天才なのかもしれんけど世の中そんな天才ばかりじゃないんだよ
オレみたいに寝食忘れて努力に努力を重ねてやっと話しが分かる鈍才もいるんだよ
鈍才が悪あがきするの邪魔せんでくれ
857デフォルトの名無しさん
2023/07/30(日) 00:33:26.30ID:psEFm3Dt858デフォルトの名無しさん
2023/07/30(日) 02:16:35.97ID:ArPWIRVu 大先生3人に共通するのは
自分は分かってるという根拠のない思い込みと
何度指摘されても全く反省せず同じことを繰り返す傍迷惑な行動
自分は分かってるという根拠のない思い込みと
何度指摘されても全く反省せず同じことを繰り返す傍迷惑な行動
859デフォルトの名無しさん
2023/07/30(日) 02:39:34.14ID:g1ghpAt+ >>847
consセルを使った簡易なリスト操作表記をRustは言語仕様レベルではサポートしていない
だからそのHaskellのmysumをその表現のまま移植するのは本質的ではないため
意味だけを重視してリストをイテレータで表現し再帰定義している点を尊重すると
use std::ops::Add;
use num::Zero;
fn mysum<T>(mut iter: impl Iterator<Item = T>) -> T
where
T: Zero + Add<Output = T>,
{
match iter.next() {
Some(n) => n + mysum(iter),
None => T::zero(),
}
}
一例としてこのようにmysumはジェネリックに書ける
mysumに最低限必要なトレイト境界(Zero + Add)のみを課している
もちろんこの関数だけで以下のように機能して計算結果も合う
assert_eq!(15, mysum([1, 2, 3, 4, 5].into_iter()));
consセルを使った簡易なリスト操作表記をRustは言語仕様レベルではサポートしていない
だからそのHaskellのmysumをその表現のまま移植するのは本質的ではないため
意味だけを重視してリストをイテレータで表現し再帰定義している点を尊重すると
use std::ops::Add;
use num::Zero;
fn mysum<T>(mut iter: impl Iterator<Item = T>) -> T
where
T: Zero + Add<Output = T>,
{
match iter.next() {
Some(n) => n + mysum(iter),
None => T::zero(),
}
}
一例としてこのようにmysumはジェネリックに書ける
mysumに最低限必要なトレイト境界(Zero + Add)のみを課している
もちろんこの関数だけで以下のように機能して計算結果も合う
assert_eq!(15, mysum([1, 2, 3, 4, 5].into_iter()));
860デフォルトの名無しさん
2023/07/30(日) 02:43:03.72ID:g1ghpAt+ >>859のmysumでトレイト境界はZeroとAddさえ満たしていれば通常の数値でなくても構わないので
例えば以下のようなHoge型を定義して必要なトレイト境界(ZeroとAdd)を実装すると
#[derive(PartialEq, Debug)]
struct Hoge(usize);
impl Zero for Hoge {
fn zero() -> Self { Hoge(0) }
fn is_zero(&self) -> bool { self.0 == 0 }
}
impl Add for Hoge {
type Output = Self;
fn add(self, rhs: Self) -> Self {
Hoge((1 << (self.0.trailing_ones() + rhs.0.trailing_ones())) - 1)
}
}
先程と同じように「15 = 1 + 2 + 3 + 4 + 5」をHoge型で表現することで
Hogeについてもmysum()は以下のようにきちんと計算できていることがわかる
assert_eq!(Hoge(0b111111111111111), mysum([Hoge(0b1), Hoge(0b11), Hoge(0b111), Hoge(0b1111), Hoge(0b11111)].into_iter()));
Haskellに全く詳しくないので逆に質問というか教えてほしい
このHoge型をHaskellで定義(実装)するにはどのようなコードになるのか?
そしてこのHoge型に対してもHaskell版>>839のmysumで使えるようにするにはどうするのか?
たぶん型クラスNumの代わりに型クラスZeroとAddを指定するだけで済むのだろうけど
もしHaskellに型クラスZeroやAddがなければそれを定義する形になるのだろうか?
よろしくお願いします
例えば以下のようなHoge型を定義して必要なトレイト境界(ZeroとAdd)を実装すると
#[derive(PartialEq, Debug)]
struct Hoge(usize);
impl Zero for Hoge {
fn zero() -> Self { Hoge(0) }
fn is_zero(&self) -> bool { self.0 == 0 }
}
impl Add for Hoge {
type Output = Self;
fn add(self, rhs: Self) -> Self {
Hoge((1 << (self.0.trailing_ones() + rhs.0.trailing_ones())) - 1)
}
}
先程と同じように「15 = 1 + 2 + 3 + 4 + 5」をHoge型で表現することで
Hogeについてもmysum()は以下のようにきちんと計算できていることがわかる
assert_eq!(Hoge(0b111111111111111), mysum([Hoge(0b1), Hoge(0b11), Hoge(0b111), Hoge(0b1111), Hoge(0b11111)].into_iter()));
Haskellに全く詳しくないので逆に質問というか教えてほしい
このHoge型をHaskellで定義(実装)するにはどのようなコードになるのか?
そしてこのHoge型に対してもHaskell版>>839のmysumで使えるようにするにはどうするのか?
たぶん型クラスNumの代わりに型クラスZeroとAddを指定するだけで済むのだろうけど
もしHaskellに型クラスZeroやAddがなければそれを定義する形になるのだろうか?
よろしくお願いします
861デフォルトの名無しさん
2023/07/30(日) 10:57:59.43ID:TSIasAnA >>860
Haskellではこうなります
https://ideone.com/PKy694
mysum [] = 0
mysum ( a : as ) = a + ( mysum as )
hogePlus a 0 = a
hogePlus a b | even b = 2 * (hogePlus a ( div b 2 ) )
hogePlus a b = 1 + 2 * (hogePlus a ( div b 2 ) )
data Hoge = H Integer deriving Show
instance Num Hoge where
( H x ) + ( H y ) = H ( hogePlus x y )
fromInteger = H
main = do
print $ mysum [ 1..5 ]
print $ hogePlus 3 7
print $ mysum [ H 1, H 3, H 7, H 15, H 31 ]
Haskellではこうなります
https://ideone.com/PKy694
mysum [] = 0
mysum ( a : as ) = a + ( mysum as )
hogePlus a 0 = a
hogePlus a b | even b = 2 * (hogePlus a ( div b 2 ) )
hogePlus a b = 1 + 2 * (hogePlus a ( div b 2 ) )
data Hoge = H Integer deriving Show
instance Num Hoge where
( H x ) + ( H y ) = H ( hogePlus x y )
fromInteger = H
main = do
print $ mysum [ 1..5 ]
print $ hogePlus 3 7
print $ mysum [ H 1, H 3, H 7, H 15, H 31 ]
862デフォルトの名無しさん
2023/07/30(日) 10:58:19.77ID:TSIasAnA この例だとmysumの型は
mysum :: ( Num a ) => [ a ] -> a
と推論されます
すなわちmysumは
aがNum class に属する型aに対して[a]型の値に対してa型の値を返す関数の型
です
よってmysumをある型Hogeで利用するにはHogeにNumインスタンスを導入しなければなりません、すなわちRustでは
impl Num for Hoge { ... }
のように書く部分です( >> 860 のAdd,Zeroを実装してる部分に該当します)
本来はNumのminimal complete definition全部実装するべきでHaskell1990までは“定義が揃ってない”とおこられましたが。2010以降は必要な分だけ実装すれば良い、ただし実行時エラーは覚悟しろという風に変更されてるようです(未確認、コンパイラがエラー吐かなくなったので)
mysum :: ( Num a ) => [ a ] -> a
と推論されます
すなわちmysumは
aがNum class に属する型aに対して[a]型の値に対してa型の値を返す関数の型
です
よってmysumをある型Hogeで利用するにはHogeにNumインスタンスを導入しなければなりません、すなわちRustでは
impl Num for Hoge { ... }
のように書く部分です( >> 860 のAdd,Zeroを実装してる部分に該当します)
本来はNumのminimal complete definition全部実装するべきでHaskell1990までは“定義が揃ってない”とおこられましたが。2010以降は必要な分だけ実装すれば良い、ただし実行時エラーは覚悟しろという風に変更されてるようです(未確認、コンパイラがエラー吐かなくなったので)
863デフォルトの名無しさん
2023/07/30(日) 12:33:59.93ID:g1ghpAt+ >>861
RustのAddトレイト実装によって足し算(a + b)のみを他の型でも自由に使えるようにできる機能をHaskellは持っていないということ?
そのためHaskellではやむを得ない代替処置としてHoge型を型クラスNumへ入れてしまうことで解決したということ?
例えばRustではStringについてもAddトレイト実装があり
let s = String::from("abc");
assert_eq!(s + "xyz", String::from("abcxyz"));
といったこともできます
同様に自作の型に対しても足し算のみの実装が可能です
Haskellではこのようなケースでもオーバースペック気味にNumを使うしかないのでしょうか?
RustのAddトレイト実装によって足し算(a + b)のみを他の型でも自由に使えるようにできる機能をHaskellは持っていないということ?
そのためHaskellではやむを得ない代替処置としてHoge型を型クラスNumへ入れてしまうことで解決したということ?
例えばRustではStringについてもAddトレイト実装があり
let s = String::from("abc");
assert_eq!(s + "xyz", String::from("abcxyz"));
といったこともできます
同様に自作の型に対しても足し算のみの実装が可能です
Haskellではこのようなケースでもオーバースペック気味にNumを使うしかないのでしょうか?
864デフォルトの名無しさん
2023/07/30(日) 12:37:15.22ID:g1ghpAt+ >>862
Haskellでは実行時エラーを覚悟しろという点は非常に困りますね
今回のケースも無理やりにNumへ入れてしまったのに足し算しか実装していないから引き算や掛け算などで実行時エラーとなるわけですよね
ちなみにRustのnumクレートでは
trait Num: Zero + One + NumOps + PartialEq とトレイト境界があり
impl NumOps for T where T: Add + Sub + Mul + Div + Rem {} の実装があります
つまり自作の型で使う場合は全ての演算を実装した上で更に加えて
impl Num for Foo とするとようやくNumになれます
したがってRustでは不備があればコンパイル時エラーとなり安心して安全に使うことができます
Haskellでは実行時エラーを覚悟しろという点は非常に困りますね
今回のケースも無理やりにNumへ入れてしまったのに足し算しか実装していないから引き算や掛け算などで実行時エラーとなるわけですよね
ちなみにRustのnumクレートでは
trait Num: Zero + One + NumOps + PartialEq とトレイト境界があり
impl NumOps for T where T: Add + Sub + Mul + Div + Rem {} の実装があります
つまり自作の型で使う場合は全ての演算を実装した上で更に加えて
impl Num for Foo とするとようやくNumになれます
したがってRustでは不備があればコンパイル時エラーとなり安心して安全に使うことができます
865デフォルトの名無しさん
2023/07/30(日) 12:47:58.55ID:wjjxPYUe そろそろ隔離スレ行ってろカスども
866デフォルトの名無しさん
2023/07/30(日) 14:02:34.57ID:iwDEPHME Haskell 的には演算子オーバーロードを目的として型クラスを使うことはしない。
Num な性質を持つ値の操作として + という名前の演算子もあるというだけで、
演算子として + を使いたいから型クラスの実装を定義するということはしないってこと。
それに、 Num はいくつかの演算子を使えるというだけではなく
それらの演算子の関係で満たさなければいけない性質があるので個々の演算子 (に結び付く型クラス) として分解できない。
https://hackage.haskell.org/package/base-4.18.0.0/docs/Prelude.html#t:Num
価値観が違う。
なんせ Haskell では記号を組み合わせていくらでも演算子を作ることが出来て
たとえば <$> とか >>= とかいう変な演算子を必要なだけ作れるので少ない演算子を取り合う必要がない。
Num の性質の中で + を使うってのと、
なんらかの足し算っぽい操作は別の名前で定義されているべきだし、
Haskell ではそれで困らない。
価値観が違う。
Num な性質を持つ値の操作として + という名前の演算子もあるというだけで、
演算子として + を使いたいから型クラスの実装を定義するということはしないってこと。
それに、 Num はいくつかの演算子を使えるというだけではなく
それらの演算子の関係で満たさなければいけない性質があるので個々の演算子 (に結び付く型クラス) として分解できない。
https://hackage.haskell.org/package/base-4.18.0.0/docs/Prelude.html#t:Num
価値観が違う。
なんせ Haskell では記号を組み合わせていくらでも演算子を作ることが出来て
たとえば <$> とか >>= とかいう変な演算子を必要なだけ作れるので少ない演算子を取り合う必要がない。
Num の性質の中で + を使うってのと、
なんらかの足し算っぽい操作は別の名前で定義されているべきだし、
Haskell ではそれで困らない。
価値観が違う。
867デフォルトの名無しさん
2023/07/30(日) 18:06:30.12ID:mgfeU+D6 新設の見慣れぬ演算子の種類を勝手に増やして各々が異なる意味付けすることは可読性を下げるのみで百害あって一利無し
>>862
コンパイラがエラーを吐かずに実行時エラーとなるのはマズいな
Haskellの価値観はよくない
>>862
コンパイラがエラーを吐かずに実行時エラーとなるのはマズいな
Haskellの価値観はよくない
868デフォルトの名無しさん
2023/07/30(日) 19:58:32.75ID:Llc746TG すいません、筆が滑りました
もちろんコンパイル時にエラー吐きます
以前のHaskellだと例えそのプログラムで使われてない場合でも実装しないとエラー吐いてました
しょうがないのでwhere句に使いもしないのに
_ * _ = undefined
signum _ = undefined
....
を書いてました
流石に無意味すぎて使わないのは書かなくて良いことになったようです
使ってるのに未実装はもちろんコンパイラが見つけてくれます
もちろんコンパイル時にエラー吐きます
以前のHaskellだと例えそのプログラムで使われてない場合でも実装しないとエラー吐いてました
しょうがないのでwhere句に使いもしないのに
_ * _ = undefined
signum _ = undefined
....
を書いてました
流石に無意味すぎて使わないのは書かなくて良いことになったようです
使ってるのに未実装はもちろんコンパイラが見つけてくれます
869デフォルトの名無しさん
2023/07/30(日) 20:06:02.24ID:iwDEPHME どうでもいいけど signum という名前を見るとヴォルケンリッターを連想してしまう……
870デフォルトの名無しさん
2023/07/31(月) 08:16:09.72ID:G+nEO2Oo どうでもいいなら・・・煽りたくなるな
■ このスレッドは過去ログ倉庫に格納されています
ニュース
- 中国「国連安保理の許可なしに日本攻撃可能」 Xで旧敵国条項に言及… ★7 [BFU★]
- 中国「国連安保理の許可なしに日本攻撃可能」 Xで旧敵国条項に言及… ★8 [BFU★]
- 【千葉】コンビニに尿入りペットボトル並べた疑い、26歳男「むしゃくしゃして」…購入した客が飲もうとしたところ臭いに違和感 [ぐれ★]
- 高市首相が異例の“買春行為の罰則化の検討”に言及…世界では“買う側”に罰則を科すのが先進国のスタンダード ★2 [樽悶★]
- 植田日銀総裁 「円安進行が物価高を起こしている」 ★4 [お断り★]
- 中国官製報道「日本経済はもう持たない」にネット民ツッコミ「ニュースだけ見てたら日本はもう百回くらい爆発してる」 [1ゲットロボ★]
- 1か月前の石破前首相、今は戦前か戦後かと聞かれ「戦前にしないようにするのが我々政治家の仕事」 [931948549]
- 【画像】高市の経済政策、凄すぎるwww [237216734]
- 現役JKのお茶会スレ( ¨̮ )︎︎𖠚ᐝ158
- (*´ω`*)明日の映画なんだけど人数分チケット取っといて!( ・᷄ὢ・᷅ )わかった!みんなで映画行くの楽しみ!
- 【ガチ正論】一般人「中国に規制制裁されて、『中国ムカつく』じゃなくて矛先が『許さんぞ高市』になってる奴、頭おかしいの?」 ★2 [153490809]
- カービィのエアライダーやってるけど泣ける
