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

■ このスレッドは過去ログ倉庫に格納されています
2019/01/29(火) 09:05:47.90ID:gJP/u7IJ
関数型プログラミング言語 Haskell について語るスレです。

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

前スレ
関数型プログラミング言語Haskell Part31
https://mevius.5ch.net/test/read.cgi/tech/1506447188/
2019/02/03(日) 22:45:46.73ID:wI7xL3t+
>>95
左辺から右辺に書き換えるって分かってる?
2019/02/03(日) 22:49:36.42ID:5bolWXfM
>>99

=3 * 2 * 1 * 1
=3 * 2 * 1 * 1 * 1
=3 * 2 * 1 * 1 * 1 * 1
・・・

やっぱり変わんないよ?
何かやってる人には常識だからあえて書いていないとかのお約束ごととかある言語なんじゃないかなぁ・・
パッと見た感じそんなに難しい言語には見えないけど内容に納得できない
2019/02/03(日) 22:50:08.66ID:PKgH5/Eo
>>98
どうでもよくないよ。正しい流れは、
fact 3
= 3 * fact 2
= 3 * 2 * fact 1
= 3 * 2 * 1 * fact 0
= 3 * 2 * 1 * 1
= 6

なのに、>>92によるとあなたは、
fact 3
= 3 * fact 2
= 3 * 2 * fact 1
= 3 * 2 * 1 * fact 0
= 3 * 2 * 1 * 1
= 3 * 2 * 1 * 1 * fact(1-1)
= 3 * 2 * 1 * 1 * 1 * fact(1-1)
= 3 * 2 * 1 * 1 * 1 * 1 * fact(1-1)

であるという。
正しい答え6にたどり着かない原因はあなたが
3 * 2 * 1 * 1
= 3 * 2 * 1 * 1 * fact(1-1)
と変形(?)してしまっているところなのは明らか。
2019/02/03(日) 22:51:43.03ID:t4xt++Qj
>>64
>またfact(1-1)
どうしてそのように推測したのですか?その 1 - 1 ってどこから誘導したのですか?
2019/02/03(日) 22:51:48.54ID:5bolWXfM
>>102
普通にやったけど特に問題なかったよ
2019/02/03(日) 22:53:55.48ID:t4xt++Qj
>>79
>fact 0は1なんだからその次はfact(1)になるでしょ
ちがいますよ。なんども言っていますが「fact 0 は 1 」、っていう言葉が不正確ですね、fact 0 の「何が」 1 なんでしょうか?
2019/02/03(日) 22:54:17.35ID:5bolWXfM
>>104
fact 0 = 1とか定義されちゃってるから変形もなにもあの形にしかならんでしょう

>>105
fact 0の結果が1だからそれはすぐ反映されるので
2019/02/03(日) 22:54:49.82ID:t4xt++Qj
>>86
>fact 0は1なんだから続くじゃない?
fact 0 の「何が」 1 なんですか?そこが他の者と違っている点かと思います
2019/02/03(日) 22:55:58.80ID:t4xt++Qj
>>92
3 * 2 * 1 * 1 * fact(1-1)

その 1 - 1 はどういう理由で 1 - 1 と書いたのですか?
2019/02/03(日) 22:56:02.92ID:5bolWXfM
>>107
不正確と言われても他に言いようがないし
2019/02/03(日) 22:56:26.62ID:o+jOfHnE
Cでこんな感じに書いてあげれば分かるのだろうか。
int fact(int n) {
switch(n) {
case 0: return 1; // fib 0 = 1
default: return n * fact(n-1); // fib n = n * fact (n-1)
}
}
2019/02/03(日) 22:57:55.66ID:o+jOfHnE
あっとボケた。>>112のfibはfactの間違い
2019/02/03(日) 22:58:05.17ID:5bolWXfM
>>110
直前の結果が1なのでfact(n-1)に与えられてfact(1-1)
特に問題ないはずだけどもこれだけなら
2019/02/03(日) 22:58:55.27ID:t4xt++Qj
>>111
あなたは 「fact 0 が 1 」といっていますが、我々は「fact 0 の値が 1」と「fact の引数が 1」とを別のものとして区別しているのです
あなたは区別していますか?あるいは「fact 0 が 1」というけれども fact 0 の何が 1 なんですか?
2019/02/03(日) 22:59:39.94ID:RwDwNYzW
>>114
>直前の結果が1なので

ここはOK

>fact(n-1)に与えられてfact(1-1)

ここが間違い。与えられるfact(n-1)がもう存在しない
2019/02/03(日) 22:59:45.17ID:t4xt++Qj
>>114
結果は結果、引数は引数です
結果を引数に入れたり、引数を結果にいれたりしていないのですよ
2019/02/03(日) 23:01:37.23ID:5bolWXfM
>>112
なっ
まさかそういう意味なの?

fact 0 = 1
fact n = n * fact(n - 1)

のどちらかしか評価されないとか見ただけじゃわからないって!!
あーそういうことかー
2019/02/03(日) 23:01:49.80ID:PKgH5/Eo
>>108
> fact 0 = 1とか定義されちゃってるから変形もなにもあの形にしかならんでしょう

いいえその形には絶対になりません。
「fact 0 = 1とか定義されちゃってるから」
= 3 * 2 * 1 * fact 0

= 3 * 2 * 1 * 1
になります。うん、これはいい。次。
「fact 0 = 1とか定義されちゃってるから」
= 3 * 2 * 1 * 1

= 3 * 2 * 1 * 1 * fact(1-1)
になります?いいえ、なりません。勝手に足した「 * fact(1-1)」どっから出てきたんだ。

3 * 2 * 1 * 1は6です。
2019/02/03(日) 23:03:02.44ID:RwDwNYzW
理解できたようで良かったけど、結局は
>>57 がわかってなかったということだなあ
2019/02/03(日) 23:03:24.76ID:5bolWXfM
これは説明書きに書いておいて欲しかったなー
これじゃわかりようがないわ
2019/02/03(日) 23:03:29.59ID:PKgH5/Eo
>>118
よかったね。君へのレスで「パターンマッチ」を検索してごらん
2019/02/03(日) 23:03:47.98ID:t4xt++Qj
>>118
そこでしたか!
うーん、それは見抜けなかったですね、いろいろしつこい質問をしてごめんなさい
2019/02/03(日) 23:04:21.15ID:RwDwNYzW
>>121
普通に数学の手法なので、数学を勉強しようか
(ちなみに、君以外は全員ふつうにわかってるぞ)
2019/02/03(日) 23:04:27.74ID:5bolWXfM
完全解決してスッキリ
みんな時間とらせてしまってごめん
そしてありがとう
2019/02/03(日) 23:06:11.09ID:RwDwNYzW
>>125 がんばれよー
127デフォルトの名無しさん
垢版 |
2019/02/03(日) 23:06:13.09ID:9SI0qp6C
fact 0 = 1 は、fact 0 = fact (fact 0)ではありません。
2019/02/03(日) 23:06:37.09ID:PKgH5/Eo
>>120
>>60
> もちろんそのように考えてる
って書いてるけどそのように考えてなかったよね…
2019/02/03(日) 23:11:25.99ID:RwDwNYzW
>>122 が言っている「パターンマッチ」を彼が調べてくれるといいね
130デフォルトの名無しさん
垢版 |
2019/02/04(月) 07:18:20.69ID:eX/1kX5o
>>92
だから、fact 1-1になった後、fact 0になるだろ?
そしたらfact 0 = 1になるんだよ。
数学の数学的帰納法ググれ。

fact 0 = 1

これはfactの引数が0なら強制的に1になると言ってる。

fact n = n * fact (n - 1)

これはfact nを解くには引数のnに、nより1つ小さい数をfactに渡したものを掛けたものと等しいと言っている。
(そして最終的にfact 0で1が返って全体の値が求まる)

fact 3
= 3 * fact (3 - 1)
= 3 * fact 2
= 3 * 2 * fact (2 - 1)
= 3 * 2 * fact 1
= 3 * 2 * 1 * fact (1 - 1)
= 3 * 2 * 1 * fact 0
= 3 * 2 * 1 * 1 ― fact 0 = 1より
= 6
131デフォルトの名無しさん
垢版 |
2019/02/04(月) 07:24:43.06ID:eX/1kX5o
ただし、fact 0の様な特殊な条件を上に書く必要がある(Haskellに限らず、どの言語も)
132デフォルトの名無しさん
垢版 |
2019/02/04(月) 07:30:26.48ID:eX/1kX5o
スタック消費しない末尾再帰とか、まだ先があるのに先が思いやられる。。。
(末尾再帰も最近じゃCやJavaScriptでも効くらしい。実質ループだから使った事ないけど)
2019/02/04(月) 11:21:38.86ID:66n6O4Xc
遅延評価や並行並列がデフォルトの言語ならばスタック消費しないのは当たり前である
2019/02/04(月) 11:34:48.97ID:nZpfKraZ
へっ?
2019/02/04(月) 11:56:25.98ID:66n6O4Xc
人間の読解力なんて順調に行っても1日1行程度でしかない
2019/02/04(月) 22:09:21.20ID:fVmYxPyX
>>133
代わりにスペースリークするけどな
2019/02/05(火) 00:47:55.71ID:YW+7XZmL
リストや配列には複数の要素がある
オブジェクトにも複数のメンバーがある
その一部が不要になってもメモリは全部残る
ここまでは言語に依存しない
2019/02/05(火) 02:19:00.11
数日ぶりに覗いたらすっごいスレ伸びてる
2019/02/05(火) 03:02:15.20ID:/sjztfrr
ごいごいすー!
2019/02/05(火) 05:35:54.03ID:H17BJwTV
>>9,112,118 だけ読めばおk
2019/02/11(月) 10:04:55.57ID:3SqS2rDH
HaskelでWindowsアプリケーション作りたいですけどできるんですか?
2019/02/11(月) 22:30:07.24ID:njsDRqJy
問題は、何十年か前にそれができた人のコードを今コンパイルできるか
今できた人のコードを何十年後にコンパイルできるか
それができるのがC/C++で
他の言語はそれを不可能にして新しい言語を普及させたい
2019/02/15(金) 14:13:18.51ID:ZHz1cA+u
さようなら遅延評価 2019-02-15
https://kazu-yamamoto.hatenablog.jp/entry/2019/02/15/115630

Haskellがとっつきにくい原因の一つに遅延評価がある。入門書では、無限リストと遅延
評価がことさら強調される。しかし、Haskellを業務で使ってみると、遅延評価が煩わしく
なってくる。遅延評価なしでもほとんどのことは実現できるし、メモリーの使用量は推測
できないし、あまりいいことはない。(中略)

、GHC 8.0 では、言語拡張 Strict と StrictData が提供された。この二つを使えば、
デフォルトの評価戦略が正格評価となる。
つまり、以下のコードの評価戦略は遅延評価だが、Strict と StrictData を用いると
正格評価となる。(中略)

Strict と StrictData をもう少しく知りたい人はStrict Haskellを読んでほしい。

純粋関数型データ構造を読んだ諸君、Haskellではデフォルトが遅延評価だからイマイチ
例題をうまく実装できないと思ったことだろう。でも、今なら簡単にできるのだ!(後略)
2019/02/15(金) 14:59:49.72ID:h0RhILR4
ムグググググググ
2019/02/15(金) 16:33:48.53ID:iAmk1lDo
xcodeで使えないのが致命的なんだよな・・
リンクはできるがUIがらみのコードは書けないわけで
2019/02/16(土) 07:21:27.63ID:6iOnrs/B
スレを読み直してて気づいたけど、>>60ってこういう意味で言ってたのね

もちろんそのように(>>57の前半のように)考えてる
fact 0 = 1の結果はすぐ(fact n = n * fact(n - 1)に)反映されるんじゃないの?
2019/02/16(土) 09:09:45.75ID:pHmZSgK3
もういいだろう ただ単に基本的文法すら知らない子じゃん
2019/02/16(土) 13:13:23.08ID:aQjbCKoN
とっつきにくいも聞き飽きたな
パワハラ上司に同じこと言えるのかと
本当にとっつきにくい相手はそういう輩だ
2019/02/16(土) 13:16:38.83ID:CJGMkJvN
ややこしいことをややこしい方法で簡単にするのがhaskell
2019/02/16(土) 14:01:52.10ID:aQjbCKoN
Pythonのように型を書かないやつはゴミクズ
とかいうハラスメントが一番の問題だから遅延評価は誤差の範囲内
151デフォルトの名無しさん
垢版 |
2019/02/17(日) 00:52:21.04ID:jxnSJIL4
一回しか変数に代入しない場合は副作用になりますか?
YES か NOでお答えください。

JavaScriptで言えばこういうコードです。
const a = foo(), b = bar(a), c = baz(b);
(const変数は再代入ができません)
152デフォルトの名無しさん
垢版 |
2019/02/17(日) 00:52:52.45ID:KFkN1Yft
Haskellスレの皆さんこんにちは✨😃❗
突然ですがこのたびWeb制作板JavaScript質問スレにて、スレ民の総意により、
[1,2,3].map(v => (v += 2, v * v));
のv += 2は副作用ではない。
と決定しました!
ありがとう!ありがとう!
2019/02/17(日) 00:55:14.71ID:jxnSJIL4
>>152は再代入と(再代入しない)代入の違いがわからず
代入は副作用であると言い張っているマヌケが
再代入の例を出し、代入は副作用であると
結論づけようとしているだけなので無視してください。
154デフォルトの名無しさん
垢版 |
2019/02/17(日) 01:04:11.22ID:KFkN1Yft
>>153
?別の方と勘違いされているのでは??
話はシンプル。質問をして、その答えを得た。以下が全てです。この質問と答えに、前後の文脈など関係ありますか??

904 Name_Not_Found sage 2019/02/17(日) 00:42:09.09 ID:???
>>901
悪いけど以下の(ア)に入るのは1か2か答えてくれる?1か2の一文字書くだけだから出来るよね?
[1,2,3].map(v => (v += 2, v * v));
のv += 2は(ア)である
1. 副作用である
2. 副作用ではない

907 Name_Not_Found sage 2019/02/17(日) 00:44:40.52 ID:???
>>904
Wikipediaの2つの成立条件を考えれば、2. は迷惑だろ

908 907 sage typo 2019/02/17(日) 00:45:33.97 ID:???
× 2. は迷惑だろ
〇 2. であることは明白だろ
2019/02/17(日) 01:06:42.19ID:jxnSJIL4
あの?Haskellスレを荒らさないでくれますか?
関係ない話はJavaScriptスレに戻ってください
156デフォルトの名無しさん
垢版 |
2019/02/17(日) 01:13:02.79ID:KFkN1Yft
>>155
おや?
>>151を書き込んだのはどなたですか?w
何か都合の悪いことでもあったのですか?w
大慌てで>>151を張りに来たようですが?w
2019/02/17(日) 01:15:49.49ID:jxnSJIL4
>>151は単なる質問です。
158デフォルトの名無しさん
垢版 |
2019/02/17(日) 01:25:17.93ID:KFkN1Yft
フフッw
2019/02/17(日) 01:47:05.17ID:bP6HzLuJ
うるせ〜〜〜〜一生代入してろ
160デフォルトの名無しさん
垢版 |
2019/02/17(日) 03:04:30.74ID:lVDDSVXk
Haskellスレ民の方々どうも!
Web制作板JavaScript質問スレにて、
https://en.wikipedia.org/wiki/Side_effect_(computer_science)
の以下の文章について…
> One common demonstration of side effect behavior is that of the assignment operator in C++.
副作用の振る舞いの一般的なデモとしては、C++の代入演算子があります。
> For example, assignment returns the right operand and has the side effect of assigning that value to a variable.
例えば代入は右オペランドを返し、かつそれと同じ値を変数に代入するという副作用を持ちます。


スレ民の叡智を結集した結果、

・C++の代入演算子は副作用があるが、JavaScriptの代入演算子は副作用がない

・[1,2,3].map(v => (v += 2, v * v));
のv += 2は主作用を使っているのであって、副作用など使っていない!

と決定しました!
パチパチパチ〜
ありがとー!!
2019/02/17(日) 13:09:25.08ID:C3KvaR2D
初期化と代入の違いはC++でさんざんやったやつだろ
C++には遅延評価がないから余裕じゃないのか
162デフォルトの名無しさん
垢版 |
2019/02/17(日) 17:34:05.11ID:HZyuZSmb
runSTという魔法がある
2019/02/20(水) 10:51:29.01ID:FaK+gznk
Cのマクロ
#define fact(n) (((n)==0)?1:(n)*(fact((n)-1))
これだったら一見まともに見えて
実は無限ループする罠

fact(0)は
((0==0)?1:(0)*((((0)-1)==0)?1:((0)-1)*(....
となって無限ループ。
(ややこしいんで括弧の数とか間違って
るかもしれないけど)

C++でインライン関数で定義した場合は
論理式短絡評価で動くかもしれんが
2019/02/20(水) 11:35:48.52ID:FaK+gznk
再帰を含む関数がインライン展開されることを
期待するほうが間違いだったか...
2019/02/20(水) 11:43:51.95ID:KVaXFVJv
スレチ
166デフォルトの名無しさん
垢版 |
2019/02/20(水) 16:55:25.36ID:xw22aw45
テンプレートメタプログラミングでもしてろクソ
2019/02/22(金) 10:09:30.67ID:ioyynd1U
花粉の時期に入るとみんなこれやり始めるよね
2019/02/22(金) 19:18:12.74ID:ioyynd1U
だめだわからん

fold_left :: (a -> b -> a) -> a -> [b] -> a
fold_left _ a [] = a
fold_left f a (x:xs) = fold_left f (f a x) xs

リストが a1 a2 a3のとき

folder_left f (f a a1) [a2 a3]
になることはわかる

その先の展開が何時間考えてもわからん
f(f(f(a,a1),a2),a3)になるってゆーんだが
イメージに繋がらない

お前らこんな難解なの本当に使いこなせてるの?
ここまでわかりにくいと有用なのか疑わしく思えて来る
2019/02/22(金) 19:43:58.95ID:LKaW/yz7
>>168
foldlなんて単なるループみたいなもんだし
今どきJavaでもやるくらい

分かるまでは変に抽象化しないで、具体例で考えるといいよ

folder_left f a [a1 a2 a3]
じゃなくて
folder_left (+) 0 [1, 2, 3]
で考えるとか
そしたら
folder_left f (f a a1) [a2, a3]は
folder_left (+) ((+) 0 1) [2, 3]になる

要は最初に
int sum = 0
for(int a : xs) sum = sum + a

と書くのと変わらない
sumへの蓄積を、変数への再代入ではなく次の関数への引数として書いてるだけ

どちらかというと、いわゆる関数型っぽいのはこういうのよりfoldrでリスト作ったりするときの方かな
2019/02/22(金) 19:47:35.11ID:ioyynd1U
>>169
まったくわからない
例題載ってるとこにも似たようなことは書いてあるんだけども

ループで書くならすぐ終わる話だけど
ややこしすぎてイメージがつかめない
イメージがつかめたらその時点で理解終了なんだけど
2019/02/22(金) 19:51:15.80ID:ioyynd1U
a2とa3が分離されそうなことはわかるんだけども

folder_left f (f a a1) [a2 a3]
      ^^^^

こいつがどこ行くのっていうのと
どこをどうやったら()で括られることになるのかイメージできない
2019/02/22(金) 20:17:22.94ID:LKaW/yz7
>>171
folder_left f (f a a1) [a2, a3]
になるところまではわかるんだよね?
そしたらまず括弧の中から先に計算するのはどの言語も普通だよね
だから先に(f a a1)の答えが出る
fは引数を2つとる関数だから、答えを出すのに支障はないよね
ここで(f a a1)の計算結果をz1としようか
そしたら上の式は
folder_left f z1 [a2, a3]になるよね?
そうすると、f、z1、[a2, a3]の3つの引数を使って、folder_leftがまた呼び出されるのがわかる?ここが再帰ね
folder_leftの定義は2つあるけど、[a2 a3]は空リスト([])じゃないから、下の
folder_left f a (x:xs)の方が呼ばれるよね?
ここでaはz1、xはa2、xsは [a3]だよね
だからベタで書くと
folder_left f (f z1 a2) [a3]になるよね?
同じように括弧の中が先に計算されるから、(f z1 a2)をz2としようか
そしたら
folder_left f z2 [a3]となる
また全く同じようにfolder_leftを呼び出すと、次は
folder_left f (f z2 a3) []となる
そして同じように(f z2 a3)をz3とすると、
folder_left f z3 []と書ける
ここでまたまたfolder_leftを呼び出してるわけだけど、最後のリストが空リストだよね
だからfolder_leftの2つの定義の内、上の方のfolder_left _ a [] = aが呼ばれる
上から順に呼び出し条件を見てるからね
ここでaはz3のことだから、最終的にz3が答えになる
じゃあz3が何かっていうと、(f z2 a3)だよね。そしてz2が何かっていうと、(f z1 a2)だよね
つまりz3は(f (f z1 a2) a3)のことだ
そして最後にz1は(f a a1)だから、結局
z3 == f (f (f a a1) a2) a3となる
これでどうだ
2019/02/22(金) 20:22:50.89ID:ioyynd1U
>>172
()の中って完全に展開されるまで実行されないものと思ってた
例題もそんな書き方だったし

これならわかる!
ありがとう
2019/02/22(金) 20:30:54.11ID:LKaW/yz7
>>173
そこらへんは評価戦略の話であって別件だね
再帰の本質ではないよ
Haskellといえば遅延評価みたいなところがあるから混乱しやすいけどね

上で言うならz3こと(f (f (f a a1) a2) a3)を、最後までこの形で持って行って、最後にまとめて計算するのが遅延評価
上で書いたみたく適宜評価していくのが正格評価
Haskellだとfolder_leftは二種類あって、
遅延評価版がfoldl
正格評価版がfoldl'
ぶっちゃけ左畳み込みに関してはfoldlを使うことはない
全部foldl'でいい
2019/02/23(土) 00:41:48.52ID:RiBir1w3
カリー化関数の意図がわからん

sum_of :: (Integer -> Integer, Integer, Integer) -> Integer
sum_of (f, n, m)
| n > m = 0
| otherwise = f n + sum_of (f, n + 1, m)

これはわかる

sum_of' :: (Integer -> Integer) -> Integer -> Integer -> Integer
sum_of' f n m
| n > m = 0
| otherwise = f n + sum_of' f (n + 1) m

どう見ても書き換えただけにしか見えないんだけどこれ意味あって書いてるのかな
カリー化って引数可変で動作する関数を定義するためのものって理解したけど
後者にはそんな意図が含まれてるように見えない
2019/02/23(土) 02:34:37.24ID:hS0A7KKk
>>175
やってるのは数式で書くと Σ[i=n..m] f(i) か
再帰をちょっと具体的に書き下さないと何のsumかわからんかった

それで多分やりたいのは
こういう風に個別の総和関数が手軽に作れますよみたいな話だと思う
タプルで定義されてるとこういう風にはいかない
(書けないことはないけどめんどくさい)

sumOfTwice :: Integer -> Integer -> Integer
sumOfTwice = sum_of (*2)

ここで(*2)とかできるのも
(*) :: Integer -> Integer -> Integer
がカリー化されてるおかげ
こういうのを部分適用と言って可変長引数とは異なる概念
2019/02/23(土) 02:59:05.43ID:RiBir1w3
>>176
(*2)の意味わからなくて前後調べたら演算子をカリー化できるとかあって
やっと意味わかったありがとう

しかも例題の先の先の方に有効な利用法書いてあったけど
なんかどうもサイトの進め方と合わないなー・・変えるかー
こんなこと書いてもなんか意味あんのだから何なんみたいな悶々パターンが多すぎる

とても簡単ですとか書いてあったら相当難しいフラグ確定
考え方が違うんだろうな
2019/02/23(土) 06:50:54.90ID:T/+XuHA6
考え方を変えるのが関数型を学ぶ一番の目的だと思うけど、
合わないなら関数型あきらめればいいじゃん。
うちは論理型言語に全く馴染めなくて、それに時間使うのやめた。
2019/02/23(土) 10:50:43.56ID:7gjHPQsv
そうじゃない
人を信じるのをあきらめて嘘を嘘と批判する
とても簡単ですと言った奴は嘘つきのクズであると
2019/02/23(土) 13:04:48.43ID:RiBir1w3
しかしいいサイト全然ないなどうしたもんか
お前らどうやって習得したのよこんな難解な言語
2019/02/23(土) 13:35:58.14ID:7gjHPQsv
例えばC#とF#の考え方は変わらないし
考え方を変えるというのも嘘だな

嘘に気付くのに1日かかるやつと5年以上かかるやつの差は大きい
2019/02/23(土) 14:01:38.38ID:E9HQXzXo
>嘘に気付くのに

ひどい世の中だな
2019/02/23(土) 17:11:04.23ID:RiBir1w3
Prelude> let foo n = ¥x -> x * n
Prelude> :t foo
foo :: Num a => a -> a -> a
Prelude> let foo10 = foo 10
Prelude> :t foo10
foo10 :: Integer -> Integer
Prelude> foo10 10
100
Prelude> foo10 20
200

Prelude> let foo100 = foo 100
Prelude> foo100 10
1000
Prelude> foo100 20
2000

Prelude> let foo5 = foo 5
Prelude> foo5 10
50
Prelude> foo5 20
100

Prelude> :t foo (1.234 :: Double)
foo (1.234 :: Double) :: Double -> Double
2019/02/23(土) 17:12:26.05ID:RiBir1w3
>>183のクロージャの説明がさっぱりわからない

関数を生成する関数を簡単に作ることができるって言ってるんだけど
やってることは定義を繰り返してるだけでちっとも生成してない
どういう意味で関数を生成したって言ってるんだろ・・
Stringで関数生成してevalで評価しましただったらわかるんだけど、これ違うよね
それともhaskellの場合は関数定義は関数生成としているのか・・わからん
一体これは何が言いたいのか・・

実はどうでもいいことで気にしなくてもいいなら納得するんだけども
2019/02/23(土) 17:31:29.38ID:YUL1Jv8G
前スレに比べて明らかに初心者が多いのは何故だ
186デフォルトの名無しさん
垢版 |
2019/02/23(土) 17:37:12.35ID:5fn4St+r
またHaskellのせいにしてるの?
以下は同等のJavaScriptだけど。
let foo = n => x => x * n;
let foo10 = foo(10);
foo10(10);
//=> 100
foo10(20);
//=> 200
let foo100 = foo(100);
foo100(10);
//=> 1000
foo100(20);
//=> 2000
let foo5 = foo(5);
foo5(10);
//=> 50
foo5(20);
//=> 100

てか何の言語なら知ってるんだっけ?
2019/02/23(土) 17:46:51.51ID:RiBir1w3
>>186
そうじゃなくてこれ関数定義だけで生成なんかしてないよね?って話
ぱっと見パスしてもいいようなどうでもいいことにも見える
そうであれば次に行く

どうもHaskellは納得いかないことがあまりにも多いんだ
文化の違いなのか考え方の違いなのかわからんけど

CかObj-CかSmalltalk-80/VisualWorksで
188デフォルトの名無しさん
垢版 |
2019/02/23(土) 17:59:11.82ID:5fn4St+r
Cは実行時関数生成能力ないから仕方ないけど…

let foo10 = foo 10
は関数を返す関数fooに10を渡して、
関数(¥x -> x * 10)を得て(これが、ここが「生成」)
それにfoo10って名前を付けてるって理解は無理?
あなたこれまでに¥x -> x * 10って関数定義した覚えある?書いた覚えがあるのは¥x -> x * nでしょ?
まあ次行け次。
2019/02/23(土) 18:05:45.67ID:RiBir1w3
>>188
foo10は結局のところ ¥x->x*n を呼び出してるだけじゃないの?
¥x->x*10って関数を生成してないよね?

そういうことではない?
2019/02/23(土) 18:08:48.44ID:7gjHPQsv
C++だったらtemplate引数として渡したら定義で、コンストラクタに渡したら生成
静的と動的がわかるのが前提だからわからないならpythonかjavascriptから始めるべき
2019/02/23(土) 18:12:36.80ID:RiBir1w3
>>190
PythonならBlenderで頂点やマテリアル抽出するときに必須だったから使ったことあるけど
インデント縛りで胃が溶けそうだった
正直もうやりたくない・・
192デフォルトの名無しさん
垢版 |
2019/02/23(土) 18:18:49.99ID:5fn4St+r
>>189
> foo10は結局のところ ¥x->x*n を呼び出してるだけじゃないの?

Prelude> foo10 10
100
とかのこと言ってるんなら
let foo10 = foo 10
で生成した関数(¥x -> x * 10)を呼び出してるつまり
(¥x -> x * 10) 10
100

> ¥x->x*10って関数を生成してないよね?

してるよ
let foo10 = foo 10 の foo 10の部分で。
(生成のタイミングは今回置いとくとして)
2019/02/23(土) 18:28:43.67ID:RiBir1w3
>>192
わかった!
無名関数で定義されてるからできるってことかー
納得できたありがとう

次行ってみる
2019/02/23(土) 18:29:48.03ID:7gjHPQsv
templateとコンストラクタとメソッドの考え方
関数と関数と関数の考え方
変わったのは見た目だけ
2019/02/23(土) 18:33:42.53ID:RiBir1w3
>>194
C++は全く知らないのでそっちはなんとも
2019/02/23(土) 18:51:02.51ID:RiBir1w3
早速詰まった何を言ってるのかわからん

一般に、関数を呼び出す場合、関数を評価するための環境は空リストです。
最初に、引数がこの環境に追加されます。let で定義される局所変数もこの環境に追加されます。
もしも、環境に該当する変数が存在しない場合は大域変数を参照します。

たとえば、foo 5 と呼び出すと環境は次のようになります。

foo 5 ==> 環境 : [(n, 5)]

ghciで実行

Prelude> let foo n = ¥x -> x * n
Prelude> foo 5

<interactive>:2:1: error:
• No instance for (Show (Integer -> Integer))
arising from a use of ‘print’
(maybe you haven't applied a function to enough arguments?)
• In a stmt of an interactive GHCi command: print it
Prelude>

そりゃそうだよねぇ・・
なんなんだろう何が言いたいのかさっぱりわからない
本当にこんな説明でみんな理解してったの?
2019/02/23(土) 19:26:38.79ID:hS0A7KKk
>>196
そこクロージャの説明のとこでしょ? 読み飛ばしていいと思うよ

手元にHaskellの入門書何冊かあるけど目次や索引にクロージャ無いし
純粋関数型言語でありデフォルトで関数がカリー化されているHaskellに
クロージャとかいう概念は別に要らないと思う
部分適用便利だねってことがわかればおk
2019/02/23(土) 19:34:16.40ID:RiBir1w3
>>197
そっかわかったありがとう!
関数の合成もすぐわかったのでさらに次行ってみる
2019/02/23(土) 20:14:35.45ID:RiBir1w3
データ型の定義まで来た
なんというかやっぱりこのサイトこれからhaskell入門の人にはどうでもいい余計なこと書きすぎなんじゃ・・
と思った
2019/02/23(土) 21:08:00.52ID:RiBir1w3
do構文がIO型だからこのように書ける・・というのがどうもしっくりこないけど
都合上こうするしかなかったってだけの話で特別な意味はないのかな

calc :: IO ()
calc = do
putStr "Input Integer1 > "
x <- readLn :: IO Integer
putStr "Input Integer2 > "
y <- readLn :: IO Integer
let a = x + y
b = x - y
c = x * y
d = x `div` y
n1 = show x
n2 = show y
putStrLn (n1 ++ "+" ++ n2 ++ "=" ++ show a)
putStrLn (n1 ++ "-" ++ n2 ++ "=" ++ show b)
putStrLn (n1 ++ "*" ++ n2 ++ "=" ++ show c)
putStrLn (n1 ++ "/" ++ n2 ++ "=" ++ show d)
2019/02/23(土) 21:24:41.95ID:24PtBhaW
>>200
いちいち躓いたところで立ち止まらない
これは別に関数型がどうとかに限った話じゃなく、未知のジャンルの勉強の話
まず思考を殺して30回読み返す
学ぶは真似ぶから始まる
■ このスレッドは過去ログ倉庫に格納されています
5ちゃんねるの広告が気に入らない場合は、こちらをクリックしてください。

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