探検


関数型プログラミング言語Haskell Part34

1デフォルトの名無しさん
垢版 |
2021/12/17(金) 12:57:26.37ID:NPioGyUL
関数型プログラミング言語 Haskell について語るスレです。

Haskell Language(公式サイト)
https://www.haskell.org/
日本Haskellユーザーグループ - Haskell-jp
https://haskell.jp/

前スレ
関数型プログラミング言語Haskell Part33
https://mevius.5ch.net/test/read.cgi/tech/1581326256/
685デフォルトの名無しさん
垢版 |
2025/10/09(木) 19:50:16.02ID:j1OYGPg+
>>684
うん、遅延評価だから基本参照を返してるはず。バード本参照
(なので>>668を書いてみたわけで)

immutableなら

a = [1..4]
b = map (+1) [1..4]
print a
print b

とうコードで

output:
[0,1,2,3,4]
[1,2,3,4,5]

になるはず。
Cで参照を共有すると

[1,2,3,4,5]
[1,2,3,4,5]

という困った表示になってしまう。
というかHaskellでも生のリスト[0..4]とmap (+1) [0..4]は参照を共有してない。
共有してるのは[0..4]だけ。
(むしろ共有してないからこそ「富豪プログラミング」とか言われる)
686デフォルトの名無しさん
垢版 |
2025/10/09(木) 20:01:16.79ID:j1OYGPg+
言ってみればHaskellは新しい参照をどんどん生み出して、不要になった参照はガンガンGCする。
Cはそういうプログラミングには(当たり前だが)向かないし、当たり前にCの方が効率は良い。
人間が書くコードはHaskellみたく数学に近いほど短くなる。
どっちが良いとかじゃなく、何を優先するかという話。
(なのだなぁと、Cでmap関数もどきを書いて再確認した)
2025/10/09(木) 20:33:26.39ID:N3YUsGEr
ループ書こうぜ
2025/10/09(木) 21:58:50.95ID:HS++2zZ0
>>682
「ジェネリック等の抽象化機構を備えた言語であれば〜」のところ全然理解してなかったのな

>>683
言語の仕様上は値渡しだけど実際にわざわざコピーして渡す必要がない状況ならコンパイラが最適化してコピーしないマシンコード(コピーして渡すのと同じ結果になるマシンコード)を生成するという話
異なるレイヤーを混同してることに気づいてくれ

あとHaskellのリストは配列じゃないよ
689デフォルトの名無しさん
垢版 |
2025/10/10(金) 05:32:34.82ID:WzZmvOuY
Haskellを勉強したけど何に使えばいいのか分からない
関数型プログラミングで難しい割に、速度が出ないことがわかっているやっぱり速度は正義だろ
690デフォルトの名無しさん
垢版 |
2025/10/10(金) 07:17:31.85ID:G/tXieG5
>>688
ジェネリックはそのうちC++なりJavaなりで試すけど、まだ試してもいないので…。

最適化の方はもうちょい具体的に教えて欲しいかも。
x = 2 * 100を x = 200にするみたいなのは知ってるけど、あんま詳しくない。
691デフォルトの名無しさん
垢版 |
2025/10/10(金) 07:21:42.77ID:G/tXieG5
>>689
今のHaskellは(中の人がMSに勤め始めてから)C#並みに速くなってるけど、GUIライブラリとか軒並み遅い時代に開発が止まってる…。
しいて言えばYesod使ってWebアプリかな?
Mac(Appleシリコン)版があるからiOSアプリのロジック部分とかも行けそう。
2025/10/10(金) 20:26:02.07ID:OD0KmsJp
【移民】 は努力もせずに日本の豊かさを手に入れる
https://medaka.5ch.net/test/read.cgi/kankon/1759822097/l50
693デフォルトの名無しさん
垢版 |
2025/10/11(土) 22:42:46.58ID:pZv0dAV3
22 template <typename T>
23 vector<T> map(function<T(T)> f, const vector<T> arr){
24 vector<T> temp;
25 for(auto i : arr) temp.push_back(f(i));
26 return temp;
27 }
694デフォルトの名無しさん
垢版 |
2025/10/11(土) 22:43:04.64ID:pZv0dAV3
C++で書いてみた。
今回は値渡しにしたけど、本当に最適化でコピーにならないようにできるのかな…。
そもそもどうやってそれを確認するんだろう?
本当なら参照渡しがほぼ要らなくなるけど。
そして、例によって参照渡しだと>>668やコードこそ書いてないがCで一般的な>>677のカッコ内に書いた(通常、それを避けるために結果を格納するためのポインタを引数で渡す)になる。

コードにするとこう。
(Haskellerなのでmapにしたけど、C++だとmapって連想配列なのね。失敗した…)

void map(vector<int>* input, vector<int>* output);

配列と比べて長さを引数に渡さないで良くなるのと、realocしなくても長さを変更できる点が進化しているが。
2026/02/12(木) 15:09:07.80ID:8VIuq8kI
圏論勉強してるけどAIに聞いたらこれがわかるやつほぼいないらしいな
でも地道にべんきょうしてみるか
2026/02/12(木) 15:10:09.62ID:8VIuq8kI
モナドのところまで理解するのは司法試験より難しいらしい
やばすぎでしょ
2026/02/12(木) 15:25:52.98ID:igQHzWRb
ブンゲン先生の新書で簡単
2026/02/12(木) 15:26:40.57ID:igQHzWRb
量子力学よか簡単でしょ
2026/02/12(木) 16:22:45.68ID:C8S6S9gb
訳ねぇだろ
それが本当なら今頃俺は医者か弁護士様だw
2026/02/12(木) 16:23:59.31ID:igQHzWRb
え、違うんだ
2026/02/23(月) 02:32:32.96ID:5fN0Omve
Bartosz Milewskiとかがミスリードしてわけわからん理論になったけど、
AI台頭でAIに聞くと論点が全然違うことが判明してきてから最近是正されつつある。
2026/02/23(月) 02:38:41.28ID:5fN0Omve
本質的には、値と計算を区別するためのもの。圏論は計算を定式化するにあたって使っただけ。
2026/02/23(月) 04:08:40.30ID:tP2zP9Hz
ブンゲン先生の本にあったやつだ
処理のことを関手といいます。というように書いてあった
int32でもint16でも同じ事やりたいだけなんだってさ
2026/02/23(月) 05:35:15.36ID:Zy3Qt1Sz
ブンゲンなんかより
斉藤毅の「数学原論」読め
2026/02/23(月) 05:56:13.03ID:pMi++7H7
モナドは汚物入れ
2026/02/23(月) 13:37:09.12ID:tP2zP9Hz
ブルバキの原論はよく見るね
2026/02/23(月) 18:26:05.97ID:Egzyn5SF
箱×箱=箱これがモナドなんよね
2026/02/23(月) 18:27:35.79ID:Egzyn5SF
箱の中身×箱の中身=箱の中身がモノイドなんよ
2026/02/23(月) 18:30:43.45ID:QgZgq8V1
なるほど、数学使うと過度に難しく聞こえるから、損だよね
2026/02/23(月) 19:34:28.91ID:+7rrIRrl
何を以て理解とするのかだよな
ワタシC++チョットワカル だと司法試験受かるレベルの勉強が必須
2026/02/23(月) 19:46:15.09ID:7E+WLbMD
箱×箱の中身=箱は?
2026/02/24(火) 19:16:37.78ID:re0YLQ3H
>>711
AIに聞いたらいいよ。箱=計算ということらしい。計算している中で計算しても、計算していることに変わりはないから計算 計算 a→計算 aということなんだろう。
=============================
Gemini の回答
Eugenio Moggiが1989年に提案した概念の核心は、「値(Value)」と「計算(Computation)」を型レベルで厳密に区別したことにあります。

あなたが仰る通り、これは単なる圏論の抽象的な話ではなく、「プログラムが実際に何を行うか」という振る舞いを数学的に記述するための画期的なアイデアでした。

1. 「値」と「計算」の分離
純粋関数型プログラミングの世界では、通常、関数は「入力 A を受け取って出力 B を返す」という単純な写像として扱われます。しかし、実際のプログラミングには「副作用(例外、状態更新、入出力など)」が伴います。
Moggiはここに着目しました。
値 (A): 単なるデータ(例:Int の 10)。
計算 (T(A)): 「A という型の値を返すが、その過程で何らかの効果(Effect)を伴うアクション」。
この T(モナド)を導入することで、「計算のプロセスそのもの」を一つの値として扱えるようにしたのがMoggiの功績です。

2. f:A→T(B) という視点
Moggi以前の圏論的なモナドの説明は T:C→C という自己関手の性質に終始しがちでした。しかし、プログラミングにおいて重要なのは、**「純粋な値 A を受け取り、副作用を伴う計算 T(B) を返す関数」**です。
これがまさに**クライスリ射(Kleisli arrow)**です。Moggiは、この形式を使うことで、言語のセマンティクス(意味論)を壊さずに以下のような「計算のバリエーション」を統一的に扱えることを示しました。
例外処理: T(A)=A∪{error}
状態保持: T(A)=S→(A×S)
非決定性: T(A)=List(A)

3. なぜこれが「計算の概念」なのか
Moggiの提案が「計算の概念」と呼ばれる理由は、モナドの演算(unit と bind)がプログラムの制御フローを規定するからです。
unit (return): 純粋な値を「何もしない計算」の中に閉じ込める。
bind (>>=): ある計算の結果を次の計算へと「繋ぐ(シーケンシャルに実行する)」。
つまり、モナドとは**「計算をどう組み合わせるか(Composition of computations)」というルールの体系**そのものなのです。
2026/02/24(火) 21:04:46.64ID:OnRDT7lQ
お前らが分からん分からんと苦悶しているのはな
実はモナドの働きではなく
そのモナドの働きの数学的概念を使った実装法なんだよ

それをキチンと理解したければ
Hask圏何なりの計算の
数学的モデルを理解するしか無い
714デフォルトの名無しさん
垢版 |
2026/02/24(火) 21:11:49.83ID:re0YLQ3H
Hask圏は正式な用語ではないから勧めるのは良くない。
計算の数学的モデルといっても、すごい直観的アイディアに基づいているし、なにか厳密な数学的根拠があって
計算 計算 a -> 計算 a
みたいにしたわけじゃないと思う。
エミュレータの中でエミュレータ動かしても、結局エミュレータの動作に還元できるはずだ、みたいな直観的アイディアに基づいていると理解してる。
2026/02/24(火) 21:12:34.07ID:r5WIjeg9
ハスキー犬
2026/02/24(火) 21:22:44.64ID:vc3yz2go
>>712
俺が聞きたかったのは
a -> 計算 a -> 計算a
のことだったんだが通じなかったか
2026/02/24(火) 21:31:53.40ID:re0YLQ3H
>>716
なんだ。大きいこと言って、よくわかってないんじゃない?
a -> 計算 b
のことならプログラムの数学的モデルと言うべきじゃないか。
計算を伴う関数みたいなものと考えれば、計算の概念のモデルが先では?
そんなこと論文には書いてないけどね。
2026/02/25(水) 16:04:02.19ID:yKGm4nBM
>>716
箱の中身->箱、を箱に入れると箱->箱×箱で箱×箱=箱だから箱->箱なんよ
2026/02/25(水) 16:30:13.57ID:yKGm4nBM
b->箱 cを箱に入れるて箱b->箱×箱cという矢印を作るらしい
そしてa->箱b 、箱 b->箱×箱cこの2つの箱を圏論の矢印の結合でつなげると
a->箱×箱cなって箱×箱=箱だからa->箱 cになるっぽい
2026/02/25(水) 20:44:57.37ID:icHlXo2I
箱 a だったら、箱の中身aが単なる値(value)
箱込みの箱 aが計算(computation)
値と計算とすごい似ているけれど違いがある。
値(value)には、副作用とか、非決定計算とか、例外とかそういうプログラムに必要な概念の入り込む余地がない。
値みたいだけれど副作用等の概念も含んでいる、値っぽい概念が必要。それが計算(computation)。

と言うようなくだりが本来あるんだけれど、そこら辺を全部吹っ飛ばして圏論の話をいきなりして操作がこうだ
と言う話しかしないからわかりようがないんだよ。
2026/02/26(木) 19:31:47.55ID:tkkm5x6+
プログラミングHaskell(第1版)の93ページの「return (f v1 v2 ... vn)」の中の fは、「p >>= f」の fとは別ですよね
後者は「¥v1 -> … return (f v1 v2 ... vn)」に当たると思いますが、違うでしょうか
2026/02/26(木) 21:08:41.03ID:S2Rtjefz
一番簡単なのはクライスリの中ではa->箱bとc->箱 の繋げるルールはa->箱b ×b->箱c=a->箱cと覚えておくことだよね
そうすれば矢印をつなげたあと、aを入力すれば箱の中にcが入ったものが出てくると考えられるんだね
2026/02/27(金) 20:18:01.55ID:aKwrq+6y
それはルールだけの話じゃん。そもそも箱 a ってなによ?
言っておくけどこれは圏論だけからは出てこない。
でも、なぜか圏論だけから結論出そうとする人ばっかりだからわからなくなる。

改めて聞くが、
a -> 箱 b
のa と箱 bはなんで区別しないといけないのか説明できんの?
2026/02/27(金) 22:10:10.15ID:ddTPUhro
箱は計算前の式だと思えばいい、その式を計算すると箱の中身が出てくる
2026/02/27(金) 23:01:12.71ID:aKwrq+6y
答えになってない。
それだと箱 -> a にすりゃええじゃん。
2026/02/28(土) 07:47:49.78ID:F2S5VRAK
箱 a->aというのが計算だよ
計算する前に矢印を繋げて一つの箱にするのがa->箱 b
2026/02/28(土) 10:16:52.91ID:1v+Zw++9
IOモナドの場合
aを取り出せるところまで(IO a)を計算しないと(a -> IO b)を適用できないから
計算に伴う副作用の順序が保証される
その結果の(IO b)に(b -> IO c)を適用する場合も同様で
(a -> IO b) ⇒ (b -> IO c)の実行順序が保証される

遅延評価で(x)の計算を保留したまま(x -> y)を適用できる形だと
(x -> y)の副作用が(x)の副作用より先に発生する可能性がある
2026/02/28(土) 12:36:32.60ID:ezBOM/F6
僕の考えるモナドについて話したいだけですね。
標準的なモナド概念の理解にたどり着きたいという話じゃなかったようだ。
2026/02/28(土) 15:35:20.67ID:ZjUJrBLg
結局>>707-708は意味が無かったってことかな?
2026/02/28(土) 16:59:12.06ID:F2S5VRAK
標準的なモナドは圏論を勉強しないとわからないに決まってるんだよ
圏論を理解しないでモナドだけ理解する非公式な方法を考えてる
2026/02/28(土) 17:00:40.79ID:gHDYF8Vg
いいね。解析は分かるけど代数苦手なのよね
2026/03/02(月) 15:43:18.83ID:zdTnYiWN
圏論あんま関係ないけどな。
計算概念を定式化したいってだけだし。
2026/03/02(月) 15:47:05.14ID:m2I3zU/G
今Cで仕事してる人達が使って行くんだからキモイ数学を駆使しないで高校か高専教育で理解できるようにたのむ
2026/03/02(月) 16:44:55.64ID:zdTnYiWN
なにを頼んでんの?
2026/03/02(月) 16:56:34.67ID:+AsXSf7r
啓蒙活動だよ。よろしく
2026/03/02(月) 17:00:37.94ID:i1U/9/JM
まぁHaskellで圏論こねくり回しても役に立たんからね
2026/03/02(月) 17:04:52.69ID:+AsXSf7r
OOPはある程度うまくいって、グローバル変数使いまくりコードはだいぶ減ったから、Haskell関連でもそんな効果がある概念が出てくるのではないかと思っている
2026/03/02(月) 17:24:58.03ID:zdTnYiWN
int f(int n){ puts("hello");
return n +2; }
という関数があるとき
3
というデータと
f(1)
という関数適用の結果は同じ3を与える。
だけれどもf(1)は計算結果として3を与えるだけで、3というデータというわけではない。出自が違うしhelloと出力する分差がある。
なので3と同一視してしまうのはマズイ。
3:int
f(1):計算 int
と区別する。名称としても3の方は値(value)
f(1)の方は計算(computation)と呼ぶことにする。

モナドはこういう区別をとりあえず認められるかどうか。計算結果としてのデータと単なるデータを区別すると言うことが重要なんだがOK?これが認められればすぐ分かる
2026/03/02(月) 18:36:01.12ID:nktAT8k9
わかってなさそう
2026/03/02(月) 18:59:57.06ID:tWwuztZJ
モナーなんてZ世代は知らない
2026/03/02(月) 19:20:21.63ID:zdTnYiWN
具体的にはどこが?計算とかいう概念持ち出すところ?
それだともう根本的だよね
2026/03/02(月) 19:41:30.44ID:nktAT8k9
チャーチロッサーの話ならモナド持ち必要がない
2026/03/02(月) 19:59:33.68ID:zdTnYiWN
チャーチロッサーの定理の話なんてしてないが
2026/03/03(火) 20:09:29.90ID:AsM/jRKA
プログラミングのモナドにおいて、値(value)と計算(computation)はどのように区別されますか。
=================
Eugenio Moggiの理論における「値(Value)」と「計算(Computation)」の区別は、**「型(Type)」というレンズを通して明確に線引き**されています。
一言で言えば、**「それ自体が何であるか(静的)」**と**「それが何を引き起こすか(動的)」**の違いです。
### 1. 値(Value):
値とは、プログラムの中で「純粋なデータ」として扱われるものです。
* **性質:** それ自体に副作用はなく、評価した瞬間にその中身が確定しています。
* **型としての表現:** 単なる型 で表されます(例:`Int`, `String`, `Bool`)。
* **例:** 数値の `10` や、文字列の `"Hello"`。これらはどこで使われても、それ自体がプログラムの状態を変えたり、エラーを投げたりすることはありません。
### 2. 計算(Computation):
計算とは、「最終的に型 の値を返すが、その過程で**何らかの付随的な効果(Effect)**を伴うプロセス」を指します。
* **性質:** 実行されるまで結果がわからなかったり、実行中にログを出力したり、失敗したりする「振る舞い」を含んでいます。
* **型としての表現:** モナド を被せた型 で表されます。
* **例:** * `Maybe Int`: 「`Int` を返すが、失敗するかもしれない」という計算。
* `IO String`: 「`String` を返すが、外部世界との入出力を伴う」という計算。
### 3. 両者の境界線:Monadの役割
Moggiはこの「値」と「計算」をバラバラにするのではなく、モナドの2つの基本操作によってこれらを厳密に、かつ安全に繋ぎ合わせました。
#### @ 値を計算に昇格させる (`unit` / `return`)
純粋な値を、「何の効果も伴わない、ただ値を返すだけの計算」の中に閉じ込めます。
> 例:`10` という値を、`Just 10`(Maybeモナドにおける計算)にする。
#### A 計算と計算を繋ぐ (`bind` / `>>=`)
「ある計算の結果(値)」を「次の計算」へと引き渡します。このとき、計算のプロセス(副作用)が連鎖していきます
ここが肝心なのですが、`bind` は **「計算 の中から値 を取り出して、次の計算を生成する関数 に渡す」** という役割を担っています。
745デフォルトの名無しさん
垢版 |
2026/03/04(水) 01:58:00.48ID:XOqqy6En
wikipediaにもT Aは計算した値って書いてあるじゃん
>>738 が言ってる通りだよ

プログラム(program)の数学的モデルを見つけ出す過程において、Moggi は圏論と表示的意味論の観点からプログラムは圏の射、型は圏の対象とみなすことができ[5]、さらに直感的解釈として、関数が値を取り値を返すものであるのに対しプログラムが値を取り計算した 値を返す[6]、すなわち引数の型と返り値の型の間にはなにか違いがあり単純な射の合成ができない、と考えた。

集合写像(関数):値 →       値
プログラム   :値 → "計算した" 値
2026/03/04(水) 05:27:21.48ID:7OJSzV14
計算について書いてないやん。"計算した"ってなんやねん
2026/03/04(水) 05:45:10.64ID:SVNV5ClQ
(1) 計算Pを行った結果値vを得た。
(2) 値v。

この二つは全然ちがう。
なんかゴニョゴニョやってvが出たと、単なる値vでは情報量が違う。
両者は区別されて当然。この違いを定義する形式的枠組と考えれば良い。
2026/03/04(水) 05:58:42.41ID:7OJSzV14
haskellでは、値に純粋関数適用するというゴニャゴニャしたことしても値のままだがな。
fが純粋関数だったら
f 5
も値にしてる。
2026/03/04(水) 06:03:40.92ID:7OJSzV14
そういう微妙に説明しきれないところがあったので、Haskellerには全く受け入れられなかった。
でもそういう区別があると認めればモナドはすぐ出る。
なんか説明できんかなと、圏論の基礎をパラパラめくって形だけ見ただけでも出てくるかもしれない
圏論が必要っていうのもこういうレベル
2026/03/04(水) 06:35:37.11ID:GN6HcWHi
アセンブリで考えた方が楽だったりしないか。CPU決めないといけないけど
2026/03/04(水) 09:18:26.50ID:jKWw5dKe
区別するより
値vで同一視するのが好きな人が多いからw
2026/03/04(水) 11:14:51.99ID:7OJSzV14
同一視も何も、誰も区別してなかったんだからそんな認識ないと思うよ
2026/03/04(水) 22:21:48.44ID:Ksw16q/0
-- I v = (v)

return v = I v
(>>=) (I x) f = f x

みたいに何の意味もないIも定義上はモナドにならんの?
モナド則は満たしてそうだけど
2026/03/05(木) 04:36:01.77ID:zXMZ2FD1
恒等モナドか。論文にはなんも書いてなかったと思う。
クライスリ射 a -> I b をどう解釈するかになるんじゃね。知らんけど。
計算効果が何もない純粋関数と同じと解釈すれば、なにも計算効果がないモナドと解釈はできる。
「恒等」モナドだから、他モナドと組み合わせるとき、つまりモナド変換子とかを導入するときぐらいしか意味なさそうだけど。
755デフォルトの名無しさん
垢版 |
2026/03/08(日) 22:34:48.83ID:Mtbhf7w9
モジュール性のためにモナドを導入したんじゃないの?
756デフォルトの名無しさん
垢版 |
2026/03/08(日) 22:36:23.08ID:Mtbhf7w9
副作用のある計算を合成するためにモナドを導入したんじゃないの?
2026/03/08(日) 22:52:32.88ID:d+H6OQjC
純粋関数と必要なIOなんかの副作用を両立させるためでしょ?
2026/03/08(日) 23:06:18.80ID:ZuaiB7hd
臭い物に蓋をするためです
2026/04/03(金) 14:37:07.77ID:oQP8bHaE
ライプニッツが導入した概念は単子(モナド)と呼ばれた。その書籍は「単子論」という。
次に、その単子が圏論に利用された。これは関数から「関手」へと概念を広める。
三段階目、その圏論での定義を使って、プログラミング言語の世界での単子が広く使われるようになった。
そのひとつが、Haskellでのモナドだ。
そういう経緯であることから、整理すると、圏論での定義と似ているが、別物であることにも注意する必要がある。
理論上は等価でも、実装上は等価に出来ない問題だ。
レスを投稿する


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