4 デフォルトの名無しさん 2019/01/31(木) 07:01:01.92
手続き型でゴリゴリやってきた人にとって関数型は マラソンの選手に、匍匐前進と水泳で近道するよう強制しているかのようです
>>4 手前味噌ですが、Haskell入門以前と言う電子書籍をAmazonでご購入下さい。 まさに貴方のような方に関数脳を作ってもらうための本です^^ 初心者がHaskellでオンライン問題集みたいなの解いてんだけど Haskellでやるとこういうの楽しくてええな
8 デフォルトの名無しさん 2019/02/02(土) 00:12:37.55
CPS書き換えドリル 次の英文を○○構文を用いて同じ意味の英文に書き換えなさい的な
haskell紹介してるブログとか色々あるけどどこも肝心要のところがすっぽり抜けててイライラするな・・ 例えば fact 0 = 1 fact n = n * fact(n - 1) これ無限ループになっちゃって終わらないでしょ終端条件も書いてないし。 fact 3を展開すると 3 * ( 2 * ( 1 * ( 1 * ……… 0を入力すれば1になるってことはこの先ずーっと1が繰り返されるだけだし。 同じ値が2度続いたら処理を止めるとか変な仕組みでも入ってるのかねー
>>9 >無限ループになっちゃって終わらないでしょ終端条件も書いてないし。 いえいえ、終端条件が >fact 0 = 1 です、n ∈ N たる n からはじまって 0 で終わる、と読みます fact 3 = 3 * fact 2 = 3 * 2 * fact 1 = 3 * 2 * 1 * fact 0 = 3 * 2 * 1 * 1 で止まります. >>9 恥ずかしいぞ >fact 0 = 1 で、これ以上再帰してないじゃん >>12 それじゃ納得できないんだけども 終わるから大丈夫仕様ですってもやっとするから >>9 で書いたように1が無限に続いちゃうと思うんだけどな 0が入力されたら1を返すってことだから 1 - 1でまた繰り返しちゃうよね そもそもどの値が来たら終わるか全く記述がないよね そういうところも納得できないっていうかおかしい >>14 あの説明で納得するようならここ来てないから あれだとブログの説明と何も変わらない まさか1かtrueを返したら問答無用で終わる仕様だったりするのかねー >>13 ああ 言っている意味は分かったけど 続かねーぞ よく考えてみ 恥ずかしい思いするだろうけど っていうか、>>11 のひとが書いてるじゃん fact 1 = 1 * fact 0 = 1 * 1 で終了だろ これ納得できないとしたら、別のところで引っかかっている パターンマッチを理解していないとか >>15 バカで思い込みが激しいって最悪だぞ?どっちかにしろ。 >>16 それじゃ終わらない 終了条件が書いていないから なんどもいうように * 1がずーっと続くようにしか見えない だからこの例題見たときにイライラしてたんだよね 前提となってる仕様があるけど説明省いたとかそれ系かなと >>13 では逆に質問しましょうか、そこから両者が部分的にでも合意できるポイントを探ることにしましょう >>9 >fact 0 = 1 >fact n = n * fact(n - 1) これをあなたはどのように解釈したかを、もう少し詳しめに記述していただくことは可能でしょうか、私の記述は今は >>13 が精一杯ですが、あなたの返答をみて改善できる点はないか検討したいと思います >>15 ほとんど同じ説明だが… 関数の定義が fact 0 = 1 fact n = n * fact(n - 1) となっている。 このとき、左辺が右辺に置き換えられる (簡約という) つまり fact 3 は 3 * fact 2 に置き換えられる そして fact 2 は 2 * fact 1 に置き換えられる そして fact 1 は 1 * fact 0 に置き換えられる ひとつめの関数の定義により、fact 0 は 1 に置き換えられるので 置き換えはここでとまる 以上をまとめると fact 3 = 3 * fact 2 = 3 * 2 * fact 1 = 3 * 2 * 1 * fact 0 = 3 * 2 * 1 * 1 = 6 >>15 fact 0で問答無用で終わる仕組みですが。。。 >>11 以上にやさしい説明はないと思われ。 普通の言語(ここで >>18 終了条件は >fact 0 = 1 です。関数 fact の引数が 0 なら、1 を関数の値として返し、fact の求値作業は終了します。 fact への入力が 1 でないならば >fact n = n * fact(n - 1) の定義をつかって、最初の入力 n よりも小さい値 n - 1 (< n) を使った関数定義がつかえるように変換します >>19 理解したのは>>9 の通りで 仮定として1かtrueを返したら再帰は止まる仕様になってると推測してる >>20 だからfact(1)で無限に続いちゃうよね 1 - 1で fact 0をevalしてまたfact(1)になる そこで終了条件が必要だけど何にも書いてないから記述通りならずーっと続く としか見えないんだよね いやだから fact 1 で1が出てくる でまた、fact 1になって永遠に続くとかの勝手な思い込みでしょ あるいは、 fact 0 =1 になるから、また fact 1 -1 になると思ってるとか だから、永遠に1が続くと勘違いしちゃっている
>>22 ということはやっぱり1を返したら必ず再帰は止まる仕様であってるのかな? だったらすっきりするんだけども >>23 >1 - 1で fact 0をevalしてまたfact(1)になる ならねーよ そこが恥ずかしいところだ 途中で。。。 まあいい。 Pythonでも再帰出来る。 特別な話じゃない。 def fact(n): if n == 0: return 1 else: return (n * fact(n - 1))
>>23 >>>20 >だからfact(1)で無限に続いちゃうよね >1 - 1で fact 0をevalしてまたfact(1)になる >そこで終了条件が必要だけど何にも書いてないから記述通りならずーっと続く そうはならない fact 1 = 1 * fact 0 に簡約される そして fact 0 = 1 であって fact 0 = 0 * fact(0 - 1) とは絶対にならないからここで終わる 高校数学がわかるなら、漸化式と同じだと思えばよい >>23 >1 - 1で fact 0をevalしてまたfact(1)になる >fact 0 = 1 というのは、関数 fact のうち fact(0) (引数が 0) のときの値は 1 である、と確定的な記述をしています。ここで答えが決まったので、さらに答えを求めるための関数適用作業には入りません、それはそういう意味です どうして eval したあと fact(1) になる、と判断したのでしょうか? fact(0) = 1 の 1 というのは fact() の値であって、fact の引数ではなく、また fact の引数になりうる記述は 「fact 0 = 1」という記述の中には見つからないのですが >fact n = n * fact (n - 1) この記述のなかには、たとえば 引数が 7 だとすると「 fact 8 を fact 7 の値をつかって表現する」ということですから、fact 8 を eval する「途中で」 fact 7 を eval しようとする、ということは書かれています >>25 「1 を返したら」とまるのではなく fact 0 = 1 と fact の求値が、この行で確定しているから、止まるのです。 fact 0 = 100 という定義であっても、とまりますよ >>28 いやいやfact(1)の評価は0なんだし fact 0の定義があるからまた1 どう考えても続くんだよね そもそも再起から脱出するためのコードがどこにもないから怪しいとも踏んでる 何か前提となってる仕様がありそうだ >>29 やっぱりそうなんだ そういう重要なことは早めに説明書きしといてくれないと大混乱だわ まースッキリしたありがと そういう仕様なら色々めんどくさいな・・・ >>33 >いやいやfact(1)の評価は0なんだし 違う どこにそんなことが書かれている? >>33 >いやいやfact(1)の評価は0なんだし ここが違っています。 fact(1) の評価は 1 * fact(0) であって、 0 じゃないです fact(0) の値が具体的になにかは、fact(0) を意識しはじめた時点では分からないのですよ >>33 おもろいな だんだんネタに思えてきた fact nの定義をよく見ろ fact 0 = 1 で再帰していないじゃん ここで止まるだろ 普通に考えれば 他の言語も一緒だろ ただそれをパターンマッチでやってるだけ >>34 えーと、すまん、「どんな場合でも」再帰は1を返したら終了すると考えているのなら それは大間違いだ >>33 fact 1の評価は1 * fact 0 fact 0のみが再帰してない。(基底部) 再帰は再帰部と基底部が必ず最低1個ずつ存在する。 >>23 >>>19 >理解したのは>>9 の通りで >仮定として1かtrueを返したら再帰は止まる仕様になってると推測してる この推測が間違っているので、いったん忘れて素直にプログラムを読んでみよう >>35 教えてもらったからもう大丈夫だよ 1で再起が止まる仕様なら納得だし >>36 fact(1)を入力したら 1-1を評価するから fact 0 特に問題ないよ 1で止まる仕様らしいからそれを前提にコード考えないといかんのか・・ ややこしいことになるねこれ >>39 どーゆーこと もうそれで覚えちゃったんだけども・・ >>42 >1で再起が止まる仕様なら納得だし 理解が不十分じゃないかと危惧します、その台詞「1 で再起がとまる」という言葉ですが、「何が」 1 で再起が止まる、と考えているのですか? あなたの発言は、いちいち「何が」「どうだ」の「何が」が欠けているので不安です >>44 覚える、という言葉はこういうときに使うものではないと思いますよ もういちど繰り返すが、 >>41 に書いたように 「仮定として1かtrueを返したら再帰は止まる仕様になってると推測している」 が大間違いだ >>45 それだと>>9 の通りで揺らがない >>46 この記述だと無限に *1が続くわけだから なにか終了条件が必要なわけで 1を返したら再帰が止まる仕様ならなるほど納得 >>42 >fact(1)を入力したら 1-1を評価する どうしてそう考えたのですか?そのような記述がどこに書かれていたのか説明いただけませんか? >>50 > この記述だと無限に *1が続くわけだから 何で?続かないが。ちゃんと読め。 >>48 大混乱してきた 1で再帰は必ず止まるんでないならさらにわからなくなるんだけども >>51 わかるじゃん fact 0で1が出てきたら、また、勝手に再帰させて fact 1に戻っちゃう 勝手に脳内変換させちゃってる >>51 fact(1)はfact(n-1)によってfact(0)になるよね 実は式自体が予想外の評価するってことなのかな? いやまさかね・・ >>50 >この記述だと無限に *1が続くわけだから あなたの理解になにが足りないのかがわかるような気がしてきました。 「fact の引数が 1 である」と「fact の求値が 1 である」とを区別していないようですね この二つは厳然として異なります fact 0 = 1 は、fact(0) の「求値が」1 である、といっているのです fact n = n * fact (n - 1) は、たとえば fact 8 = 8 * fact 7 fact 7 = 7 * fact 6 fact 6 = 6 * fact 5 fact 5 = 5 * fact 4 fact 4 = 4 * fact 3 fact 3 = 3 * fact 2 fact 2 = 2 * fact 1 という記述を纏めて表現しているのであり、これは fact n の「求値」は fact (n - 1) という、もともとの引数 n とは違う n - 1 という引数を使った fact の求値で定義しているのです もしかすると、だけど fact 0 = 1 を実行した直後に fact 1 = 1 * fact 0 が続くと考えている? もうしそうだとしたらそこが間違いで fact 0 = 1 fact n = n * fact(n - 1) はそのどちらかしか実行されない
>>53 >1で再帰は必ず止まるんでない 「何が」 1 で再帰が止まる、と考えているのですか? 「何が」の部分を答えてください >>54 >fact 0で1が出てきたら、 何が 1 となるのか、そこをはっきり書いてください、「出てきたら」っていいますが、「何が」 1 と出てきたら、なんでしょうか? >また、勝手に再帰させて 何が 1 となるのか、0 となるのか、そこをはっきりさせないことには、それ以降の思考は不可能ですよ、あなたには「また勝手に再帰させて」とかいうことを考える段階ではありません >>56 ごめん意味不明わからん >>57 もちろんそのように考えてる fact 0 = 1の結果はすぐ反映されるんじゃないの? >>59 いや 俺は本人じゃないから あくまでも、彼の脳内を勝手に想像しただけ 1がつづくケースを考えただけ そのものでは無いかもしれないけど、どちらにしようが似たようなケースでしょ >>60 ああ、良かった >fact 0 = 1の結果はすぐ反映されるんじゃないの? そうだよ。そして fact 0 は 1 を返すから、もう再帰呼出しは起こらないよね? fact 3 = 3 * fact 2 = 3 * 2 * fact 1 = 3 * 2 * 1 * fact 0 = 3 * 2 * 1 * 1 = 6 >>63 いやいや終了条件が何も書かれてないから結局は続くよ どのみちfact 0が1となるならまたfact(1-1)でfact(0)でしょ 間違ってないはずなんだけど何か使ってる人には常識的なお約束事とかあるのかな >>60 >fact 0 = 1の結果はすぐ反映されるんじゃないの? ようするにそこでとまる 数学の階乗だから fact nの引数は再帰する度に-1される。 どこかで、factの引数が0になったら、それ以上は再帰しない 難しい話じゃないし、他の言語で再帰理解していたら、分かるはず 自分で落ち着いて考えてごらん >>65 いやただのカウンターだったとしても止まらないし やっぱりおかしいとは思う 何か前提がありそうな気はする >>64 fact 3 = 3 * fact 2 = 3 * 2 * fact 1 = 3 * 2 * 1 * fact 0 -- fact 0が・・ = 3 * 2 * 1 * 1 -- 1になる。factもうないのにここから何が続くの? = 6 >どのみちfact 0が1となるならまたfact(1-1)でfact(0)でしょ fact 1 = 1 * fact (1-1) = 1 * fact 0 となるけど、これは fact 1 の時の処理だね fact 0 の場合は 1 を返すだけだから、fact(1-1) という処理はもう出てこないよ 今の話は fact 3 = 3 * fact 2 = 3 * 2 * fact 1 = 3 * 2 * 1 * fact 0 = 3 * 2 * 1 * 1 = 6 のうち 3 * 2 * 1 * fact 0 が 3 * 2 * 1 * 1 に変化するところだよ
>>66 だとすると文法自体理解していない あるいは関数自体 もっと、詳しく書くと >どのみちfact 0が1となるならまたfact(1-1)でfact(0)でしょ 定義を見てごらん fact 0 = 1 でこれは、=の右にfactが無いからこれで再帰はしないで、ここで終了 fact n = n * fact n-1 で=の右にfactがあるから再帰する >>67 = 3 * 2 * 1 * 1 = 3 * 2 * 1 * 1 * fact( 1 - 1 ) = 3 * 2 * 1 * 1 * 1 * fact ( 1 - 1) どこまでも続くじゃない・・ >>70 中学校の数学でそうはならないってことは習うから、学校の数学でそこまで勉強してからプログラミングに手を出しても遅くないのでは? >>69 fact 0 = 1で終了するというのが納得いってない もしそうであれば1を返せば再帰は終了すると仮定したんだ そもそもfact 0 = 1ってマクロ定義みたいなもんだし 直ちに評価されて式に代入されるよね >>73 他の言語で再帰ってのは理解しているの? fact 0 = 1で=の右にfactが無いから、再帰は終了 だから、終了条件は書かれている。 もしこれが理解できないのなら、関数定義とか、パターンマッチとかもっと基本的なことに 戻らないと理解できないと思う >>72 プログラミング言語は数学じゃないから 再帰から脱出するならそのためのコードは絶対必要なはずなんだ それがないってことは仕掛けがあるはずで その仮定が1を返せば再帰から脱出できるという考え でも違うらしいから大混乱してる >>73 fact 0 = 1 で「終了する」というのが間違い fact 0 = 1 では、fact 0 が 1を返す(正確に言うと1に簡約する) ということしか定義していない ただ、もうfact関数を呼び出していないので、再帰呼出しはここで止まる そして fact 0 = 1 がマクロ定義ということも勘違いなので忘れよう >>67 が解説してくれた fact 3 = 3 * fact 2 = 3 * 2 * fact 1 = 3 * 2 * 1 * fact 0 -- fact 0が・・ = 3 * 2 * 1 * 1 -- 1になる。factもうないのにここから何が続くの? = 6 >>74 Cで再帰させるなら終了条件にヒットしたらフラグたててreturnで戻ってく 関数定義の仕方ならサッと見たけど特に疑問はなかったよ パターンマッチっていってもマクロ定義みたいなもんだし特にどうということも >>75 上に書いたけど、漸化式は理解している? 同じ書き方をします Haskellは数学を基盤としているので、数学的な記述方法でプログラムが書けます 「再帰から脱出するならそのためのコードは絶対必要なはずなんだ」とあるけど、 もう書かれているよ fact 0 = 1 って >>76 いやだから・・ fact 0は1なんだからその次はfact(1)になるでしょ 何も間違ってないと思うんだけど。 >fact 0は1なんだからその次はfact(1)になるでしょ その次はもうないよ
>>78 それは終了条件じゃないよね 何が正解なのかさらに混乱して来た >>81 君の言い方に合わせると「終了条件」と考えてよい 正しく説明すると >>40 になる >>42 1で止まる仕様と言うか。。。 掛け算だから1を返すだけ(掛けても変わらない数)で、足し算なら0を返すよ。 sum1toN 0 = 0 sum1toN n = n + sum1toN (n - 1) >>81 終了条件だよ。 >>27 のPythonコードで言うと if n == 0: return 1 の部分と同じだよ。 >>83 だから・・ fact 0は1なんだから続くじゃない? 延々と再帰するようにしか見えない この人の脳内だと、 fact 0 = 1 が fact 0 = fact 1 になってるんじゃないだろうか
>>85 PythonやJavaは知らないのでなんとも この人 77で書いてるけど、文法まともに読んでないんだよ Haskell 文法自体は一見綺麗で簡単そうに見えるけど 実際には、理解するのが非常に難しい(今回の再帰のとこじゃないんだけど) 適当に文法流し読みして理解しようとするのが 間違っている もっとも、階乗の再帰は、他の人の説明で理解できるだろうと思うが
>>86 fact 0は1なんだから、 fact 3 = 3 * fact 2 = 3 * 2 * fact 1 = 3 * 2 * 1 * fact 0 -- fact 0が・・ = 3 * 2 * 1 * 1 -- 1になる。factもうないのにここから何が続くの? = 6 はい!ここで一旦休憩!君に問題。 3 * 2 * 1 * 1はいくつだ? うーん、C言語だと int fact(int n) { if (n == 0) return 1; else return n * fact (n - 1); } と書くのと同じなんだけどねえ
>>90 だから =3 * 2 * 1 * 1 * fact(1-1) =3 * 2 * 1 * 1 * 1*fact(1-1) =3 * 2 * 1 * 1 * 1*1*fact(1-1) という具合にいつまでもfactは続くよ だから色々納得いかないことあるんだけど >>92 この1行目はどこから出てきたの? =3 * 2 * 1 * 1 * fact(1-1) この辺を脳内でテキトーに処理してるからわからないんだよ fact 3 のところから地道に書きながら置き換えてみな >>94 それで地道にやったら >>9 になったよ あれ以外どうしろと・・ >>92 算数のテストで 3 * 2 * 1 * 1は?って問題に、 3 * 2 * 1 * 1 * fact(1-1)って答えるの? それは算数でも数学でもプログラミング言語でも間違いだよ。 算数でも数学でもプログラミング言語でも答えは6だよ。 >>95 そうなのか。C言語はやったことがあるようだけど >>91 は理解できてる? >>96 そこはどうでもいいところだから書かなかった >>95 ああ、>>9 みたいに一気に展開するのではなくて、 fact 3 = のところからひとつずつ地道に置き換えてみた? もしやってないなら、今すぐやってみよう >>97 あれでいいんだけど似たような制御構造がないよね haskellのコードは全く別物に見える >>95 左辺から右辺に書き換えるって分かってる? >>99 =3 * 2 * 1 * 1 =3 * 2 * 1 * 1 * 1 =3 * 2 * 1 * 1 * 1 * 1 ・・・ やっぱり変わんないよ? 何かやってる人には常識だからあえて書いていないとかのお約束ごととかある言語なんじゃないかなぁ・・ パッと見た感じそんなに難しい言語には見えないけど内容に納得できない >>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) と変形(?)してしまっているところなのは明らか。 >>64 >またfact(1-1) どうしてそのように推測したのですか?その 1 - 1 ってどこから誘導したのですか? >>79 >fact 0は1なんだからその次はfact(1)になるでしょ ちがいますよ。なんども言っていますが「fact 0 は 1 」、っていう言葉が不正確ですね、fact 0 の「何が」 1 なんでしょうか? >>104 fact 0 = 1とか定義されちゃってるから変形もなにもあの形にしかならんでしょう >>105 fact 0の結果が1だからそれはすぐ反映されるので >>86 >fact 0は1なんだから続くじゃない? fact 0 の「何が」 1 なんですか?そこが他の者と違っている点かと思います >>92 3 * 2 * 1 * 1 * fact(1-1) その 1 - 1 はどういう理由で 1 - 1 と書いたのですか? >>107 不正確と言われても他に言いようがないし 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) } }
あっとボケた。>>112 のfibはfactの間違い >>110 直前の結果が1なのでfact(n-1)に与えられてfact(1-1) 特に問題ないはずだけどもこれだけなら >>111 あなたは 「fact 0 が 1 」といっていますが、我々は「fact 0 の値が 1」と「fact の引数が 1」とを別のものとして区別しているのです あなたは区別していますか?あるいは「fact 0 が 1」というけれども fact 0 の何が 1 なんですか? >>114 >直前の結果が1なので ここはOK >fact(n-1)に与えられてfact(1-1) ここが間違い。与えられるfact(n-1)がもう存在しない >>114 結果は結果、引数は引数です 結果を引数に入れたり、引数を結果にいれたりしていないのですよ >>112 なっ まさかそういう意味なの? fact 0 = 1 fact n = n * fact(n - 1) のどちらかしか評価されないとか見ただけじゃわからないって!! あーそういうことかー >>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です。 理解できたようで良かったけど、結局は >>57 がわかってなかったということだなあ これは説明書きに書いておいて欲しかったなー これじゃわかりようがないわ
>>118 よかったね。君へのレスで「パターンマッチ」を検索してごらん >>118 そこでしたか! うーん、それは見抜けなかったですね、いろいろしつこい質問をしてごめんなさい >>121 普通に数学の手法なので、数学を勉強しようか (ちなみに、君以外は全員ふつうにわかってるぞ) 完全解決してスッキリ みんな時間とらせてしまってごめん そしてありがとう
fact 0 = 1 は、fact 0 = fact (fact 0)ではありません。
>>120 >>60 で > もちろんそのように考えてる って書いてるけどそのように考えてなかったよね… >>122 が言っている「パターンマッチ」を彼が調べてくれるといいね >>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 ただし、fact 0の様な特殊な条件を上に書く必要がある(Haskellに限らず、どの言語も)
スタック消費しない末尾再帰とか、まだ先があるのに先が思いやられる。。。 (末尾再帰も最近じゃCやJavaScriptでも効くらしい。実質ループだから使った事ないけど)
遅延評価や並行並列がデフォルトの言語ならばスタック消費しないのは当たり前である
人間の読解力なんて順調に行っても1日1行程度でしかない
リストや配列には複数の要素がある オブジェクトにも複数のメンバーがある その一部が不要になってもメモリは全部残る ここまでは言語に依存しない
138 デフォルトの名無しさん 2019/02/05(火) 02:19:00.11
数日ぶりに覗いたらすっごいスレ伸びてる
HaskelでWindowsアプリケーション作りたいですけどできるんですか?
問題は、何十年か前にそれができた人のコードを今コンパイルできるか 今できた人のコードを何十年後にコンパイルできるか それができるのがC/C++で 他の言語はそれを不可能にして新しい言語を普及させたい
さようなら遅延評価 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ではデフォルトが遅延評価だからイマイチ 例題をうまく実装できないと思ったことだろう。でも、今なら簡単にできるのだ!(後略) xcodeで使えないのが致命的なんだよな・・ リンクはできるがUIがらみのコードは書けないわけで
スレを読み直してて気づいたけど、>>60 ってこういう意味で言ってたのね もちろんそのように(>>57 の前半のように)考えてる fact 0 = 1の結果はすぐ(fact n = n * fact(n - 1)に)反映されるんじゃないの? もういいだろう ただ単に基本的文法すら知らない子じゃん
とっつきにくいも聞き飽きたな パワハラ上司に同じこと言えるのかと 本当にとっつきにくい相手はそういう輩だ
ややこしいことをややこしい方法で簡単にするのがhaskell
Pythonのように型を書かないやつはゴミクズ とかいうハラスメントが一番の問題だから遅延評価は誤差の範囲内
一回しか変数に代入しない場合は副作用になりますか? YES か NOでお答えください。 JavaScriptで言えばこういうコードです。 const a = foo(), b = bar(a), c = baz(b); (const変数は再代入ができません)
Haskellスレの皆さんこんにちは✨😃❗ 突然ですがこのたびWeb制作板JavaScript質問スレにて、スレ民の総意により、 [1,2,3].map(v => (v += 2, v * v)); のv += 2は副作用ではない。 と決定しました! ありがとう!ありがとう!
>>152 は再代入と(再代入しない)代入の違いがわからず 代入は副作用であると言い張っているマヌケが 再代入の例を出し、代入は副作用であると 結論づけようとしているだけなので無視してください。 >>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. であることは明白だろ あの?Haskellスレを荒らさないでくれますか? 関係ない話はJavaScriptスレに戻ってください
>>155 おや? >>151 を書き込んだのはどなたですか?w 何か都合の悪いことでもあったのですか?w 大慌てで>>151 を張りに来たようですが?w 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は主作用を使っているのであって、副作用など使っていない! と決定しました! パチパチパチ〜 ありがとー!! 初期化と代入の違いはC++でさんざんやったやつだろ C++には遅延評価がないから余裕じゃないのか
Cのマクロ #define fact(n) (((n)==0)?1:(n)*(fact((n)-1)) これだったら一見まともに見えて 実は無限ループする罠 fact(0)は ((0==0)?1:(0)*((((0)-1)==0)?1:((0)-1)*(.... となって無限ループ。 (ややこしいんで括弧の数とか間違って るかもしれないけど) C++でインライン関数で定義した場合は 論理式短絡評価で動くかもしれんが
再帰を含む関数がインライン展開されることを 期待するほうが間違いだったか...
だめだわからん 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)になるってゆーんだが イメージに繋がらない お前らこんな難解なの本当に使いこなせてるの? ここまでわかりにくいと有用なのか疑わしく思えて来る
>>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でリスト作ったりするときの方かな >>169 まったくわからない 例題載ってるとこにも似たようなことは書いてあるんだけども ループで書くならすぐ終わる話だけど ややこしすぎてイメージがつかめない イメージがつかめたらその時点で理解終了なんだけど a2とa3が分離されそうなことはわかるんだけども folder_left f (f a a1) [a2 a3] ^^^^ こいつがどこ行くのっていうのと どこをどうやったら()で括られることになるのかイメージできない
>>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となる これでどうだ >>172 ()の中って完全に展開されるまで実行されないものと思ってた 例題もそんな書き方だったし これならわかる! ありがとう >>173 そこらへんは評価戦略の話であって別件だね 再帰の本質ではないよ Haskellといえば遅延評価みたいなところがあるから混乱しやすいけどね 上で言うならz3こと(f (f (f a a1) a2) a3)を、最後までこの形で持って行って、最後にまとめて計算するのが遅延評価 上で書いたみたく適宜評価していくのが正格評価 Haskellだとfolder_leftは二種類あって、 遅延評価版がfoldl 正格評価版がfoldl' ぶっちゃけ左畳み込みに関してはfoldlを使うことはない 全部foldl'でいい カリー化関数の意図がわからん 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 どう見ても書き換えただけにしか見えないんだけどこれ意味あって書いてるのかな カリー化って引数可変で動作する関数を定義するためのものって理解したけど 後者にはそんな意図が含まれてるように見えない
>>175 やってるのは数式で書くと Σ[i=n..m] f(i) か 再帰をちょっと具体的に書き下さないと何のsumかわからんかった それで多分やりたいのは こういう風に個別の総和関数が手軽に作れますよみたいな話だと思う タプルで定義されてるとこういう風にはいかない (書けないことはないけどめんどくさい) sumOfTwice :: Integer -> Integer -> Integer sumOfTwice = sum_of (*2) ここで(*2)とかできるのも (*) :: Integer -> Integer -> Integer がカリー化されてるおかげ こういうのを部分適用と言って可変長引数とは異なる概念 >>176 (*2)の意味わからなくて前後調べたら演算子をカリー化できるとかあって やっと意味わかったありがとう しかも例題の先の先の方に有効な利用法書いてあったけど なんかどうもサイトの進め方と合わないなー・・変えるかー こんなこと書いてもなんか意味あんのだから何なんみたいな悶々パターンが多すぎる とても簡単ですとか書いてあったら相当難しいフラグ確定 考え方が違うんだろうな 考え方を変えるのが関数型を学ぶ一番の目的だと思うけど、 合わないなら関数型あきらめればいいじゃん。 うちは論理型言語に全く馴染めなくて、それに時間使うのやめた。
そうじゃない 人を信じるのをあきらめて嘘を嘘と批判する とても簡単ですと言った奴は嘘つきのクズであると
しかしいいサイト全然ないなどうしたもんか お前らどうやって習得したのよこんな難解な言語
例えばC#とF#の考え方は変わらないし 考え方を変えるというのも嘘だな 嘘に気付くのに1日かかるやつと5年以上かかるやつの差は大きい
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
>>183 のクロージャの説明がさっぱりわからない 関数を生成する関数を簡単に作ることができるって言ってるんだけど やってることは定義を繰り返してるだけでちっとも生成してない どういう意味で関数を生成したって言ってるんだろ・・ Stringで関数生成してevalで評価しましただったらわかるんだけど、これ違うよね それともhaskellの場合は関数定義は関数生成としているのか・・わからん 一体これは何が言いたいのか・・ 実はどうでもいいことで気にしなくてもいいなら納得するんだけども また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 てか何の言語なら知ってるんだっけ?
>>186 そうじゃなくてこれ関数定義だけで生成なんかしてないよね?って話 ぱっと見パスしてもいいようなどうでもいいことにも見える そうであれば次に行く どうもHaskellは納得いかないことがあまりにも多いんだ 文化の違いなのか考え方の違いなのかわからんけど CかObj-CかSmalltalk-80/VisualWorksで Cは実行時関数生成能力ないから仕方ないけど… let foo10 = foo 10 は関数を返す関数fooに10を渡して、 関数(¥x -> x * 10)を得て(これが、ここが「生成」) それにfoo10って名前を付けてるって理解は無理? あなたこれまでに¥x -> x * 10って関数定義した覚えある?書いた覚えがあるのは¥x -> x * nでしょ? まあ次行け次。
>>188 foo10は結局のところ ¥x->x*n を呼び出してるだけじゃないの? ¥x->x*10って関数を生成してないよね? そういうことではない? C++だったらtemplate引数として渡したら定義で、コンストラクタに渡したら生成 静的と動的がわかるのが前提だからわからないならpythonかjavascriptから始めるべき
>>190 PythonならBlenderで頂点やマテリアル抽出するときに必須だったから使ったことあるけど インデント縛りで胃が溶けそうだった 正直もうやりたくない・・ >>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の部分で。 (生成のタイミングは今回置いとくとして) >>192 わかった! 無名関数で定義されてるからできるってことかー 納得できたありがとう 次行ってみる templateとコンストラクタとメソッドの考え方 関数と関数と関数の考え方 変わったのは見た目だけ
>>194 C++は全く知らないのでそっちはなんとも 早速詰まった何を言ってるのかわからん 一般に、関数を呼び出す場合、関数を評価するための環境は空リストです。 最初に、引数がこの環境に追加されます。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> そりゃそうだよねぇ・・ なんなんだろう何が言いたいのかさっぱりわからない 本当にこんな説明でみんな理解してったの?
>>196 そこクロージャの説明のとこでしょ? 読み飛ばしていいと思うよ 手元にHaskellの入門書何冊かあるけど目次や索引にクロージャ無いし 純粋関数型言語でありデフォルトで関数がカリー化されているHaskellに クロージャとかいう概念は別に要らないと思う 部分適用便利だねってことがわかればおk >>197 そっかわかったありがとう! 関数の合成もすぐわかったのでさらに次行ってみる データ型の定義まで来た なんというかやっぱりこのサイトこれからhaskell入門の人にはどうでもいい余計なこと書きすぎなんじゃ・・ と思った
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)
>>200 いちいち躓いたところで立ち止まらない これは別に関数型がどうとかに限った話じゃなく、未知のジャンルの勉強の話 まず思考を殺して30回読み返す 学ぶは真似ぶから始まる >>202 じゃあモナドとflatMapを理解しきってからdo構文に進んでください それ以外にないです 読んでいるサイトが悪いのではないかなあ すごいH本とか HaskellではなくてOcamlだけど浅井『プログラミングの基礎』とかを読んだ方が 良いレベルだと思う
最終的に>>=演算子オーバーロードを理解する頃には難易度がC++と同じ
>>205 そういうことなら先に進んでもよさそう リンク先の見たら変換可能なこともわかった ありがとう! haskellのGUIは何が主流なの gtkじゃネイティブUIに見えないからqtahとか? もしくはhaskellではGUIを扱わないとか?
趣味でやってるが Threepenny 使ってる 簡単に組み合わせられるようになるかなと Elm も学習中
書籍「Thinking with Types」の第1章をサンプルPDF版で読んでいるのですが、 19ページ目の Exercise 1.4-i でつまずいています。 数式 (a^b)^c と a^(b*c) が等しいことを Curry-Howard isomorphism を使って証明する問題ですが、 これは、 to :: (b -> c -> a) -> (b, c) -> a from :: ((b, c) -> a) -> b -> c -> a という型の Haskell の関数を見つけよ、と言うことですよね。 しかし、問題文に書かれている to . from = id from . to = id の意味が分かりません。 to . from の型も from . to の型も共に id の型とは等しくないと思うのですが・・・
to :: (b -> c -> a) -> ((b, c) -> a) from :: ((b, c) -> a) -> (b -> c -> a)
Haskellにはファーストクラス多相関数がないから idの型は単相なんだろう 単相のidという名前の同音異義語がちょっと多すぎるだけ
>>209 思い出して今日発売のelm本、買おうかなと思ったら尼で売り切れててワロた。 下記の2つの関数の rank について 関数 f は rank 2、関数 g は rank 3 で合ってる? f :: a -> (forall b. b -> c) g :: a -> (forall b. b -> c) -> d
>>212 やっと意味が分かりました。 ありがとうございした。 条件を満たす限り畳み込むfoldWhileみたいな関数がないのはなぜ? scanとtakeWhileで出来なくもないけど無駄なリストが生成されちゃうよね
scanした後はlast.takeWhileとかだと思いますがfusionされるので作られません
>>217 ありがとうございます fusion調べてみます haskell入門ほぼ読んだけどちょっと物足りなくてもうすこしhaskell勉強したい欲がある(目的は競プロとか月並みにaiとか) なんかええ本ある? 数学の高速なライブラリとか圏論、モナドの解説あるやつで(数学は拒絶反応しない) get programming with haskellとか並行並列とか多少気になってるけどどう?
初心者を抜けた後、実践へ進みたいのなら幾つか勧められる本はある。 しかし、更なる勉強がしたいのなら、勧められる本はない。 初心者用か、初心者を抜けたばかりの者にはまだ難しい本しかない。 特に君の目的(競プロやAI)に叶う本は今のところ皆無だ。 なので、ネットを漁れ。 あと質問がやや曖昧で、何を求めているのか分からん。 数学の高速なライブラリの何を求めてる? それを自作できる知識なのか? 活用する知識なのか? もしくは、仕組みが知りたい具体的なライブラリでもあるのか? 圏論やモナドにしても然り。 それらの何が知りたいのか具体的に言ってみ。
>>220 具体的には数学書のような理論本ですね 今のところ全然数学臭さがないので(コンピュータとは乖離してるかもしれないけど) 速度に関しては、命令型の書き方でないのでどうすれば速度が出る書き方が出来るかが一番興味あります ai,競プロはやるとしたときの足掛かりが気になりました このみっつのどれかが掘り下げられれば幸いです。 THUNKとかWHNFとかだろうけど 俺もここら辺の本とかあるなら読んでみたい
>>221 「数学書のような理論本」 悪いが意味が分からん。 具体的に「何が知りたいのか」を言ってくれ。 理論と言うのが大雑派すぎる。 速度を上げる方法を学びたいのなら、 ・Haskell High Performance Programming ・関数プログラミング 珠玉のアルゴリズムデザイン この2つが正にうってつけだが、 「Haskell入門をほぼ読んだ」段階では挫折しそう。 AI や競プロは前レスでも言ったが本は無い。 AI は reinforcement leaning や deep leaning など技術範囲を絞ったワードと haskell を組み合わせたキーワードでネット検索。 競プロは実際の競技で提出されたソースをたくさん読んで真似しろ。 >>223 どうもありがとうございます。図書館で覗いてみます 具体的には、数学との関わりを体系だって書いてる書籍を探してましたが、そりゃ個々のキーワードで探す方が手っ取り早くて色々漁れますわな 競プロにHaskellはどうなんだ…? 良くわからんけどSTモナド使いまくる感じになるのかな あるいは珠玉のアルゴリズムを理解仕切った超人達の集まりなのか
>>221 ,223 珠玉のアルゴリズムデザインへの入門としては同じ著者の 『Haskellによる関数プログラミングの思考法』 (旧版名は『関数プログラミング入門 ―Haskellで学ぶ原理と技法―』) がいいと思う 他の入門書よりは数学色が強いし 等式変形によって効率を改善していく運算も割と丁寧に扱っていると思う あとは『純粋関数型データ構造』とかも参考になるかも? ただ競プロならSTRefとかSTUArrayとかに習熟するほうが 手っ取り早いし有力かも >>225 >>226 例えば AtCoder の参加者のコードを見てみると分かるが、 STモナドなんて使ってるヤツはいない。 そもそも、haskell に慣れたら、STモナドなんて使いにくいだけだろ。 競プロみたいな短く速いコードを書く必要があるなら尚更。 珠玉本を理解しきった者かどうかは知らんが、 極端に短いコードで解いてくるヤツは、 どちらかといえば数学の知識が豊富なんじゃないかな。 問題文を数学の世界に落とし込む事に長けているように見える。 コンテストにもよるが、競技プログラミングは 個人的にはアルゴリズム力よりも数学力がより大事だと思ってる。 例えば Project Euler の高番号問題をシンプルに解けるヤツは競技も強そう。 >>226 >>227 どうもありがとうございます。StateとかSTは内部処理はよくわからないけど便利なので使い方おぼえておきたいとこですね >>229 それでも理解したいのなら質問すればいい instance head ってよく聞くけど、 これは instance 宣言のどの部分のこと? 例えば次の宣言の場合 instance (Foo a) => Bar (Baz a b) | a -> b where ・(Foo a) ・Bar (Baz a b) ・Bar (Baz a b) | a -> b ・instance キーワードと where キーワードの間の全部 ・その他 どれ?
>>231 すまん、instance 宣言に関数従属は無いよな。 改めて、 instance (Foo a) => Bar (Baz a) where この例だとどこが instance head なんだ? >>231 自己解決した。 instance head は => より右側かつ where より左側の部分だった。 スレ汚してすまない。 HaskellのGUI(Gtk2hs)でカウンター作ってみた。 import Graphics.UI.Gtk main = do initGUI window <- windowNew set window [windowTitle := "counter", containerBorderWidth := 10] mainbox <- vBoxNew True 5 containerAdd window mainbox label <- labelNewWithMnemonic "0" boxPackStart mainbox label PackNatural 0 countbtn <- buttonNewWithLabel "Count" clrbtn <- buttonNewWithLabel "Clear" boxPackStart mainbox countbtn PackNatural 0 boxPackEnd mainbox clrbtn PackNatural 0 widgetShowAll window onClicked countbtn (labelGetLabel label >>= \n -> labelSetText label (show (1 + (read n)))) onClicked clrbtn (labelSetText label "0") onDestroy window mainQuit mainGUI
label <- labelNewWithMnemonic "0" boxPackStart mainbox label PackNatural 0 countbtn <- buttonNewWithLabel "Count" clrbtn <- buttonNewWithLabel "Clear" boxPackStart mainbox countbtn PackNatural 0 boxPackEnd mainbox clrbtn PackNatural 0 widgetShowAll window onClicked countbtn (labelGetLabel label >>= \n -> labelSetText label (show (1 + (read n)))) onClicked clrbtn (labelSetText label "0") onDestroy window mainQuit mainGUI
boxPackStart mainbox countbtn PackNatural 0 boxPackEnd mainbox clrbtn PackNatural 0 widgetShowAll window onClicked countbtn (labelGetLabel label >>= \n -> labelSetText label (show (1 + (read n)))) onClicked clrbtn (labelSetText label "0") onDestroy window mainQuit mainGUI
コマンドラインでエンターを押すごとに数字が増えていく(Ctrl+C押すまで止まらない) Haskellコード main = mapM_ (\n -> print n >> getLine) [0..] out: 0 1 2 3 4
急にどしたんww gtk2hsのドキュメントがHackageから消えてるのは気のせい?
無限ポップアップ上げるやつ現れないとは高尚なスレ リストで遅延評価使うのがなかなかハスケルっぽい
一応、カウンターみたいなのは純粋関数型言語には作れない言われてたから、作ってみた。 確かにi++みたいな事は出来ないが、違う方法で参照透明性を確保しつつ実現出来ると実感。 (個人的にHaskellには副作用はあると考えているが、参照透明性は崩れないとも考えている)
そりゃ副作用はあるよ。 じゃなきゃIO処理できない。 haskell の特徴は純粋な関数から副作用のある関数を呼べないこと。
うい。 そう言う仕組みになってるくせに、IOな関数も扱いとしては純粋な関数と同じ扱いなのが気に入ってます。 (型に気をつけていれば自然とそうなるし、普通にprint関数と純粋関数を関数合成出来るのが好き)
純粋関数型言語でカウンタが作れないというのは、 同じ関数を呼び出した結果がカウントアップされるような関数のこと。 pythonで書くとこんな感じ。 >>> def create_counter(): n = 0 def counter(): nonlocal n n += 1 return n return counter >>> counter = create_counter() >>> counter() 1 >>> counter() 2
>>244 そうなんですが、純粋関数型言語の場合、その関数を何回呼び出したのかカウントする関数を作るみたいな視点の切り替えで対処するのではと。 つまり自身のファイルを読み込んで自身(counter関数)を a = counter b = counter a = 1 b = 2 に置き換える関数なら作れます。 欲しいのは結果であり、動作ではなく結果が同じなら良いと言う解釈です。 終了やカウントクリアに対応してみた。 import System.Exit main = do putStrLn "quit code is 'q', count clear code 'c'" mapM_ (\n -> print n >> getLine >>= f) [0..] f "quit" = exitWith ExitSuccess f "clear" = main f _ = return ()
副作用もカウンタもGUIもHaskellでできる (Haskellで作れるとは言っていない)
まあ要はcounter関数はswap関数と同じですよ。 手続き型言語ではソートや繰り返しに必須ですが、関数型言語で各種ソート作る時にswap関数は使った事がない。 木を見て森を見ずというか、counter関数を何に使うの?って話で、カウンターとしての用途なら再帰関数の引数でf (x + 1)とか渡せば良いだけですし。 loop10 n | n > 10 = return () loop10 n = print n >> getLine >> loop10 (n + 1)
つまりHaskell(というかElm?)で無限アラート書いとけば捕まらなかった?
Haskellの再帰は場合によってはヒープを使うから 10^9回ぐらい閉じる奴がいたらサイバーテロとして扱われてたかもしれない
そこは気を付けなきゃだけど(と言うか、スタックは兎も角ヒープ使うってreverseみたいにリスト溜め込むとかだけで、手続き型言語でもあり得る場面に限られそうだが)、 むしろモナドな再帰(IOはもちろん、リスト->リストな再帰も)がループになると言うのは、 手続き型言語よりも再帰でスタック使うケースが少ないと言う魅力もある。 (ここは手続き型言語が末尾再帰最適化に対応しても追いつけない所) >>246 の通り、mainを再帰的に呼び出してもループになると言うのは知る限り手続き型言語では見たことない。 main変数が他の言語で言うmain関数的な動きをしているのも、圏論的には変数は引数無しの関数と見做せるから。 main変数を評価しようとすると束縛されたプログラムが動き出す。 n = 1 ― 変数であり、常に1を返す引数無しの関数 いやGHCが与えるスタックはヒープなんだよ Cのコールスタックみたいな固定領域じゃなくてね それもデフォルトで最大メモリの8割というデカさだから うっかり非末尾再帰を放っておこうものならスワップ地獄に陥る
非末尾再帰を末尾再帰に自動変換するのって技術的に不可能? 末尾再帰ってなんか無理やり感あるよね
フィボナッチを再帰で書くと定義がそのまま動く感動が味わえるのに末尾再帰に書き直すととたんに台無しになるよねw
ヒープにあろうがスタックにあろうが末尾再帰に意識して書けばまず解決する問題だね。 ghciやrunghcみたいなスクリプト形式だと最適化(部分的な正格評価)が不十分で sum’ n [] = n sum’ n (x:xs) = sum’ (n + x) xs という末尾再帰があった場合、 sum’ 0 [1,2,3] = sum’ (0 + 1) [2,3] = sum’ ((0 + 1)+ 2) [3] = sum’ (((0 + 1)+ 2)+ 3) [] みたいに(遅延評価のせいで)結果を入れる変数の方でスタック消費するけども、コンパイラ(ghc)の方はこの問題は無い。
>>254 別に数列(リスト)から取り出す形にすれば末尾再帰にする必要ないでしょ。 main = print $ fibs!!3 ― 0から数えて3番目 where fibs = 0:1:zipWith (+) fibs (tail fibs) foldlの正格評価版 foldl’みたいにzipWithの正格評価版作って差し替えると高速化する。 (このネタ書いてたブログの人はzipWith’を標準で入れてて欲しいって書いてた) zipWith’ f (x:xs) (y:ys) = seq a $ a:zipWith f xs ys where a = f x y zipWith’ _ _ _ = [] >>256 定義そのままで書きたいって話であって末尾再帰だからダメとは言ってないでござるよ 「感動」はダメとは言わないが意味がわからないと言いたい
自然に書くなら数学の定義通り書くよね でも今のコンピュータの制約上仕方なく末尾再帰にしないといけないよね 自然に書ける日は来ないのかなあってある種当たり前の感覚だと思うけど
コンピューターの制約で変えねばならないならば定義に問題がある 定義は可能な限り一般に適用可能でなければならない よって定義を変えればよい
感情をそのまま言語化できるなら犬や猫も言葉を話せることになる 実際には感情と言語は一致しないので感情をそのまま言語化することはない
何か噛み合ってないな 自然な感覚に近い表現ができるほうが可読性高いよねくらいの話でしかないはずなのに 今何の話になってるんだ??
言葉を話さない動物やAIには言語の制約がない ゆえに動物やAIは人間を超える可能性がある 壮大な詭弁だ
末尾再帰=ループ 分岐が発生するとこの関係が崩れる
何か変なとこに手出しちゃったみたいですね もうやめときます スレ汚し失礼しました
可読性で思い出したが ソースを読まなくても使ってみればわかることは読まない方がいい 読んだときの自然な感覚なんかよりも、そもそも読まないのが最も自然
可読性をあげるためだけに型に別名つけるのってどうなの type Description = Text みたいなやつ
読むコストを下げるためだけにギャンブル ○○のコストは安いというのが本当か嘘かを賭ける 賭けないのが最も安いと思わないか
>>259 一応、末尾再帰も式変形した定義通りなんだけどね。 fib3 0 a _ = a fib3 n a b = fib3 (n - 1) b (b + a) n = フィボナッチ数のn番目(fib n) a = fib nの時のフィボナッチ数 b = fib (n + 1) の時のフィボナッチ数 fib3 nはfib3 (n - 1)のbがaになり、b(fib3 (n + 1))はfib3 (n - 1)のb(fib3 n) と a(fib3 (n - 1))を足したものである。 >>269 賭けない、は具体的には何? 型シノニムを使わないということ? >>271 使うのは自由だが可読性の勉強等はしないということ >>272 悩んでないでスタイルを決め打ちして自分が自然だと思える書き方で行く、みたいな感じですか そんな言葉は使う必要がねーんだ 書き方は決まってないのにもうすでに書き終わってるからだ
やっぱりHaskellは常人向けではないんですね Ocamlやります
そういえば言語も決まってなかったな 常人は言語を決めないとプログラムを書けないってマジ?
>>275 Windowsでは、昔のrubyみたいな状況なので、 それ以外のプラットフォームでやるのがいいよー よく判らないアドバイスだったな… 勉強・研究しないで突っ込むのはそっちの方が賭けてる感あるし、 すぐに書き終えるなら確かにそういう難しさはないが、 ソフトウェアのプロジェクトって面白いものは大抵長くなると思う。 >>277 Windows環境はWSLではダメなん? >>261 感情表現と言うように感情はあくまでイメージ想起性のもので 文法を持ってないものだと思う。 感情をそのまま言語化なんて人間でもしてないだろ。 あくまで論理的内容の会話文章の表現に感情を想起させる表現を 選んで論理としては同じだけれど得られるイメージが異なる文を 作っているだけだと思う。 そこで文を構成するために選ぶ表現がやたら極端なときに、感情的と評されているだけで。 ていうかおじさんになったしもう無理 >>279 得られるイメージが変わってしまうのはコンピュータの制約のせいだよ fibのイメージをそのまま表現できたら感動するのになあ この状況ではコンピュータの制約は変えたいがイメージは変えたくない 「論理としては同じだけれど得られるイメージが異なる」という想定は大外れ コンピュータの制約が悪夢のようだから消去法でイメージ あほなことしてるだろ 俺達なんだぜこれ
イメージないと妥当性の判断もできんぞ。 これだって 書き込み内容を読んで 内容から推測される人物像をいままでの記憶から割り出して そういう人物に対してかつてもった心象(イメージ)を この場合の想定(先入観)として設定して 否定的判断をするという内容を伝達しているだろ 大体こういうプロセスじゃね?
数学の世界で効率を全く重視してないわけじゃないからな。無限の速度のCPU上なら同じと見なせるってだけで。 末尾再帰のfibとか数学的だからアーキテクチャ関係なく元の定義より速い。 行列苦手だから書けないが、もっと速い行列バージョンも存在する。
全く読んでないがパラダイムと論理は同じではない パラダイムの限界と論理の限界は同じではない
>>284 >末尾再帰のfib fib が末尾再帰でかけますか? sum x:xs = x + sum(xs) は数学っぽく見えるけどアキュムレータ噛ますと途端にループに見える不思議
アキュムレータは余再帰っぽく見える 数学っぽいの反対は余再帰っぽい説
Haskell知らんでも無意識に >>270 みたいな式を思い描いて for文とかに落とし込んでる感じじゃね? n回繰り返すのが昇順か降順かの違いだけで。 Python def fib(n): temp = 0 a = 0 b = 1 for i in range(n): temp = a a = b b = b + temp return a for i in range(10 + 1): print(fib(i)) Haskell main = mapM_ (print.fib) [0..10] fib n = fib' n 0 1 where fib' 0 a _ = a fib' n a b = fib' (n - 1) b (b + a) 自然数が射(関数)になっていると言う感覚が分かった気がする。 Haskellで書けないけど、書けるとするなら 1 = 1 1という名前の1を返す引数無しの関数。
記号的な1を1と書き、概念的な1をチャーチ数で表現するなら 1 = succ zero
トートロジーとかチンプンカンプンな高卒なんで。。。 補足説明や訂正があったら勉強になります( ̄^ ̄)ゞ
ラムダ的な自然数は高階関数を使うけど、圏論は冪を使わないことが多い
Haskell でもsuccって関数ありましたね。。。 私が 1 = succ zeroで表現したかったのは、どんな数体系でも1と表現される何かという意味での1です。 例えば16進数の10はAと表現されますのですが、 A = 10 とすると10が16進数では10進数の16になるので10進数でも16進数でも10として扱われる概念としてチャーチ数にしたかったのですが、 チャーチ数も含めた全ての数体系で10として扱われる何かを表現したいみたいな。 うーん。。。表現力が乏しくてすみません。
本当の所は Int $ succ Zero というような頭部正規形で表される関数のシンタックスシュガーだと思う
・チャーチ数はペアノシステムの1つの実装である ・任意のペアノシステムは(適当な公理のもとで)互いに同型である みたいな話?
>>303 > HNFは射ではない > そもそも圏論にHNFはない こういう表現は間違い 何が射かであり何が圏でないかは、どんな圏を考えているかに依存する 例えばだが、単純な型付λ計算(型の集まりが直積型の構成と関数型の構成について閉じている)に対応する圏、つまり単純な型とそれで型付けされるλ項の成す圏を考えることができる そこでは、対象は個々の型で、射はλ項だ そして個々のλ項は、そのλ項の中に現れる自由変数の各々の型の積対象からλ項全体への型という対象への射と考えるというものだ この場合、λ抽象があるので冪対象が必要になり、従って、この単純な型付λ計算に対応する圏は必然的に積閉包圏というタイプの圏になる これはいわゆる“categorical type theory”(圏論的型理論)の最も簡単な具体例だ この圏の場合は単純な型付けに関してwell-typedなλ項は全て射として認められるのでもちろんhead normal formになっているλ項もwell-typedである限りは射だ Haskellの開発環境で、ブレークポイント張って評価中の変数の値を見る、みたいなのって出来ますかね? Visual Studioのローカルウィンドウ的なの。 普段はSpacemacs使っててREPLで評価しては進め、評価しては進め、みたいな感じでやってます。
cabalのnew-から始まるnixスタイルコマンドが出来たからtackつかう意味あまりないですよね
>>309 v2-build だっけ? よく知らないが stack いらなくなるやつなんだ? stack or cabal どっちを使えばいいんだ
>>312 迷う理由がわからない 現時点で好きな方を使えばいいのでは? どっちを使っても、後で後悔することなんてないと思うが >>314 もはや同等とみていいの? 一長一短がイマイチ見えないので比較できない。 >>315 自分で情報を得られず、比較できなくて選べないくらいなら、 一長一短なんか考えずに、今好きな方や気になる方を使えば良いんだよ。 stackを長い間使ってきたから今後も使い続ける、でもいいし、 新しいcabalに興味が沸いたからcabal使ってみる、でもいい。 例えばパーサーライブラリ、Webライブラリ、FRPライブラリなどは色々あるけど、 いちいち「一長一短を比較した上で」選ぶ人はそんなに多くないでしょう。 みんな取りあえず何か一つ使ってみて、他に興味が湧いたら浮気してみて、 それからでしょ、比較するのは。 >>316 両方の一長一短をちゃんと比較して紹介するのは、 記事や本を書くプロや、意欲のある人に任せればいいと思う。 紹介のプロじゃないのなら、自分が好きな方を精一杯アピールすればいい。 それもできずに、初心者にどちらを紹介しようか悩むのなら、順番が違う。 どちらか一方でもアピールできるくらい使い込むのが何よりも先でしょ。 まぁこの手の選択にある程度以上責任持って助言するのは難しいんだよな。 少なくとも両方使ってないとどっちがいいとか言えないし。 ほとんどの人が最初に使った方をそのまま使い続けるもんじゃね。 私もcabalしかつかったことないし。
「みんなの見解を聞く」も自分で情報を得る過程のひとつだと思ってるんだが 記名ネットではしにくい無責任方言もここなら言えるでしょ
まだキチンと検討していないが、自作したツールをbrewとかで公開するとき、ビルドツールを依存に含める必要が出てくると思う。予めどっちかを使うかは決めておきたい。 バージョンを重ねるなかでフラフラ変えるのは避けたい。 あとcabalだとコンパイラを替えるときはghcupなる別ツールを使うの? これだとクロスコンパイラはどうなる。 複数のアーキテクチャのための成果物をビルドするとき、ghcup set ... && cabal build && ghcup set ... && cabal build ... みたいにいちいち指定しないといけないのかしら。 コレを解決するにはghcupにパッチを当てるかcabalを改造するか、スクリプトを書くかするわけだ。その点 stack build はコマンド一発なのに。 俺は年間50時間くらいstackのパッチや関連ツールを書いてきた。このままで行けるならいいが、stack がいずれオワコンになるなら早めに見切りつけて時間節約したい。 新元号が30年続くなら令和中に1500時間も浪費することになるんだぜ。
>>320 > 記名ネットではしにくい無責任方言もここなら言えるでしょ そんなレスは情報ではないのでは? ただのノイズでしょ(ノイズの全てがゴミとは言わないが)。 本当に情報を得たいのなら、時間の無駄だよ。 もし、そんなのを参考にどっちか決められるのなら、 初めからルーレットで決めるのと大して変わらないのでは? 「自分で情報を得る」の第一歩は、ビルドツールで一番何がしたいかを決めて、 それが出来るか、やりやすいかを「公式ドキュメント」を見て調べる事だよ。 stackとcabalの公式ドキュメントを見て比較して、 それでも分からない部分をピンポイントでSNSや掲示板などで質問する、 それが二歩目だと思う。 伸びてると思ったら。。。 今の所stackかな。 cabalは依存関係で過去に評判悪かったから、新しいのの評判が固まったらかな。
>>322 調査を並行してやっちゃいけない理由はないでしょ。聞くだけならタダやし。 スレ民の意見をノイズだなんて思ったことないよ。自分にない視点や個人的使用感、気づきにくい落とし穴を教えてもらえるかも。 俺の雑感はstackは不備だけでなくバグも多かった気がする。.stack-workを消したらビルドが直ったみたいなことが何回かあったと思う。 stackのメリットは、 (ghcupの方針が変わらないなら)コンパイラの導入まで自動でやってくれるので、例えばHaskellスクリプトを書いてシェバンにstack、 以降に依存ライブラリを書いておけばいつでもどこでも動く(HackageとStackageが活きてるかぎり)、必要なものを都度自動で用意してくれる。 stackのデメリットは、 設定ファイルが多すぎる。プロジェクトレベルでは stack.yaml, package.yaml, Hoobar.cabal と、どれに何を書くかが判りづらい、いちいち引っかかる。 >>324 無責任放言がノイズなんだよ。 で、その全てがゴミとは言わないとも言ってる。 >>325 前半は反論したし、後半は批判してないですよ。 凄いH本の中国語版見る機会があって、 漢字の用法がカタカナ語より しっくりすると思ったんですけどどうでしょうか。 模式: パターン 門衛: ガード 類型類: 型クラス さすがにモナドは漢字翻訳難しいみたいですが。
その程度のカタカナがしっくり来なかった人生を反省するんだ
慣れとしっくりくるのは別物だけどな 無意味刺激と有意味刺激、表音文字と表意文字に対する認知は先天性の個人差があるんだからあまり他人の人生なんて分かりもしないものに言及するべきではない どちらにせよ今の中国は学術用語を積極的に訳する文化ではあるよね Haskellに限らずclassや他の用語もそれに類した漢字が用いられてそう ただこれも漢字の意味が時代によって変化してくると正しい用語認識を阻害しうるのは現代日本でいくらか見られているし、一長一短と個人差だね
かつてアルゴリズムを算法とかコンパイルを翻訳とか 一部で言っていましたね。 モナドアクションを算法と訳すならモナドは法かぁ などと連想してみました。
漢字に訳する場合どっか権威のあるところが決める必要があるよね そういうところがめんどくさい
大陸だと結構あちこちで勝手に翻訳されたり 輸入されていずれ収斂されていくっていう 感じだった。 日本でも官公庁の訳語が定着しないことも 多いよね。
流れも読まずminからmaxまでのランダムな数のリスト(要素数n)を得る関数作って見た。 takerand _ _ xs 0 = return xs takerand mn mx xs n = do x <- randomRIO (mn, mx) takerand mn mx (x:xs) (n - 1) 使い方は rs <- takerand 1 6 [] 10 これで1ー6までのランダムな数が10個入ったリストが手に入る。
流れも読まずminからmaxまでのランダムな数のリスト(要素数n)を得る関数作って見た。 takerand _ _ xs 0 = return xs takerand mn mx xs n = do x <- randomRIO (mn, mx) takerand mn mx (x:xs) (n - 1) 使い方は rs <- takerand 1 6 [] 10 これで1ー6までのランダムな数が10個入ったリストが手に入る。
>>334 それなら、getStdGen と randomRs と take でいいのでは? takerand mn mx n = getStdGen >>= return . take n . randomRs (mn, mx) あるいは takerand mn mx n = take n . randomRs (mn, mx) <$> getStdGen >>335 いいのでは、と言うのは失礼な言い方だった。 こういう方法もあるよ、と言うことで。 >>335 そう言うのがあったのね。。。 thanks. Arrowised FRP を 矢矧のFRP とかいうのは好き
型クラスの訳語 類型類 は、kindの 類 とごっちゃになるな、と思ったけど、 kindは 種 が主流なのか
>>339 主流というか、それ以外に聞いたことがない >>342 なにを助言してほしいのか具体的に明確に言ってくれ。 >>344 データ処理と表示処理を切り分けた方が開発が楽になるのはその通り。 でも、グラフィックス ライブラリに何を使うかと、 楽に切り分けできるかどうかは、一般には関係ない。 特に haskell のグラフィックス ライブラリはたいてい EDSL 形式になっているから、 どれを使おうが、切り分けの楽さは大して変わらない。 後はもうライブラリの表現力が求めるレベルにあるかどうかと、 個人の経験や慣れ、趣味の問題だ。 Processing に慣れているなら processing-for-haskell でいいだろう。 個人的には gross が好き。 ところで、既存のライブラリって何だ? processing-for-haskell は 2016 年でアップデートが止まってるが、 これは既存ではないの? >>345 ありがとうございます。理解しました。 参考にしたのが School of Expression だったので 情報が古くprocessing-for-haskellが 最新の物と思えて勘違いしてました。 >>344 そういうことをしたいならProcessingだけでやった方が手間かからない Haskellで書けば楽になるとかそんなことは一切ないので >>348 「haskellで」アート芸術方面のプログラミングをするには、という質問だと思う。 ジェネラティブアートなんか haskell にもってこいじゃないかな。 もちろん、Processing の得意分野でもあるんだが、 宣言的に書ける haskell もけっこうマッチするのでは? 全て型プログラミングで生成とかもできそう。 f xs = let g = \x -> 2 * x in map g xs この場合、ラムダは最初に一回メモリにアロケートされて g に束縛されるよね。 でも、もしかして、 f xs = map (\x -> 2 * x) xs これって、f が呼ばれる度に map の第一引数のコード(ラムダ)がメモリにアロケートされるの?
クロージャにしなくてもいいラムダはただの関数として扱われるんじゃない? というか上のコードならセーフっていうのはgを使いまわしてくれるから? そんな気の利いた処理系なら下のラムダも使いまわしてくれそうだけど
その辺り、実際にどんな実行コードが生成されるかに関しては、 コンパイラ(GHC)に聞いてくれ、としか言いようがない インライン展開とかクロージャ変換といったコンパイラ技法を学ぶことを勧める 関数型言語だからTiger本とか
ラムダは何も簡約しなくても最初からWHNFじゃないのか 最初からWHNFならサンクとか不要だから普通の言語と同じでいい
>>350 ラムダ式が動的に生成されるものと思っているのなら間違い この場合は単なる関数として展開されている なるほど、納得できた。 これからは安心して引数にラムダを直接書ける。 ありがとう。
mtl によるモナド合成はモナド則を保存しない マジかよ失望しました。mtl は窓から投げ捨てます
動的型付けに比べて静的型付けの方が優れている、は常に真? 実はHaskellで動的プログラミングをやる話を読んで、 あれっコレ意外といいじゃんと思ってしまったんだ。
次にお前らは『優れているを定義してくれ』と言うッ!
任意の言語に丸投げするシェルスクリプトはズル 文字列をevalするやつもズル ズルをする必要がない言語は優れている どうせこんな感じだろうと思ってる
いくつかの基準が思いつく。 速い・短い・アシストが手厚い・理解しやすい・バグが混入しにくい… >>359 「ズル」には悪い、の意味が予め含まれていると思うので納得できない。 evalを用いた場合に比べて静的型の解決の方が優れているのを示す必要があるでしょう。 格闘技ですら、反則には反則負けという意味が含まれている
sequence_の使い所が分からん。。。 mapM_使った方が短くなるし。 うーむ。。。 渡すリストにIOな関数含められる=IOな関数を使う リスト内包表記も使えるのは良いけど、mapM_のが簡潔。 import Data.List import System main = mapM_ put $ zip hellos marks -- sequence_ [put (x,y) | (x,y) <- zip hellos marks] hellos = (cycle.tails) "Hello World!!" marks = cycle ["/","|","\\","--"] put (x,y) = do putStrLn (x ++ "\n" ++ y) mapM_ (\_ -> putStr "") [1..50000] system "clear"
hellos = (cycle.tails) "Hello World!!" marks = cycle ["/","|","\\","--"] put (x,y) = do putStrLn (x ++ "\n" ++ y) mapM_ (\_ -> putStr "") [1..50000] system "clear"
>>363 モナディックアクションを構造に入れて使うとき重宝するよ。 main = sequence_ . (map (putStr "log:" >>)) $ [print "hoo",putStr "bar"] 個々のアクションを好きに調整できる(例ではそれぞれに前処理を足した)。 >>365 ありがとう。 いつか役立てたいものです。 別件なのですが、俺俺Eq型クラス(MyEq)を作って見ているのですが、 HugsだとNum a型のインスタンスを作れるのに、GHCだとエラーが出ます。 経験ある方、いらっしゃいますでしょうか? main = do print $ 1 === 1 print $ 1 /== 1 print $ 1 === 2 print $ 1 /== 2 class MyEq a where (===),(/==) :: a -> a -> Bool x === y = not (x /== y) x /== y = not (x === y) instance (Num a) => MyEq a where x === x' = isZero (x - x') x /== x' = not (x === x') isZero 0 = True isZero _ = False GHCだと全ての型をインスタンスにしろ的なエラーメッセージが出ます。。。 スマートな方法があれば。。。
>>363 mapじゃなくunfoldrで[IO a]を作ってもいい >>367 エラーは「インスタンスにする型はこれこれこういう形にしろ」って意味 instance (Num a) => MyEq a みたいな形を許すと instance (MyEq a) => Num a とかもできて意味わからなくなるから {-# LANGUAGE FlexibleInstances, UndecidableInstances #-} というおまじないを使って制約を取っ払う >>357 オブジェクトファースト動的解決脳だとHaskellはただめんどくさいだけの言語にしか見えない 利点とされていることが欠点にしか見えないもある "--port=" <> ( 8000 <> 80 ) これが "--port=8080" になって欲しい、みたいな?
>>371 それは暗黙の型キャストとかの話な気もするが String と Num a との積を勝手に解決するなよって思う ...でも演算子を上述のように定義すると半群の結合則を満たさない。 dynamicパッケージでもそうされてなくて、結果は"--port=800080"になります。 動的プログラミングを求める人は柔軟に使える演算が欲しくて、 Haskellのデフォルトの定義は型変換がただ面倒くさい。 369が言いたかったのは例えばそういう事かなと解釈しました。
>>368 おまじない!! ありがとうございます。 これで行けそうですm(_ _)m 何やってるのかよく分からんけど、おまじないで解決 haskellの初心者時代って、こういうの他言語に比べて多いよね どうにか分かりやすく説明できないものか、いつも悩む
>>374 まあ確かに数値計算するときにfromIntegralだのrealToFracだのをゴテゴテ書くのは (それを要求される理屈はわかっていても)面倒くさい そこを「柔軟」にしていくと人が書き間違えたときに教えてくれなくなるから 結局は書きやすさと安全性とのトレードオフだよなあ 結局、マクロ、関数、型チェック以外にプログラムにできることなんてない。 バカがバカな夢を見る。
Cは関数の定義はゴテゴテ書くが演算子の定義は何も書かなかった C++が演算子を定義するようになったからHaskellも影響を受けたんじゃないか 数学的証明だけでなく、歴史を巻き添えにして議論しないと現実は見えない
すみません、 凄いH書籍で学習していて疑問に思ったのですが 型クラス中級で、真理値の様な物を持ちうる型、 JavaScriptのfalsyな値を持つ型を作る実習で Intや[ ]を独自のYesNo型のインスタンスにする 例があったのですが 標準で存在する型に後から 独自の型のインスタンスにする事に違和感を感じ バグの温床になるのではという懸念の印象がありました。 オブジェクト嗜好のサブクラスみたいに 「Int」型から「IntYesNo」型を 生成できるのなら違和感ないのですが。 これについての合理性と安全性を明示している 書籍やサイトを知っていたら教えて下さい。
>>381 温床とまで言うか・・・ そのせいで例えばどんなバグがありそうか、 ひとつでも例を示すことはできる? ごく簡単な例でいいんだが。 >>381 あと、なんど読み返してもタイポっぽく見えないんでツッコミ入れる。 「AをBのインスタンスにする」と言うとき、 Aは型、Bは『型クラス』だからな。 失礼なことを言うが、もしかして違和感の根源は、 型と型クラスがそれぞれ何なのか理解できていないところにあるのでは? 『凄いH書籍』 (;・`д・́)...ゴクリ...(`・д́・;)
同モジュール(Haskellでいう)内なら拡張に対しては責任を持つべきなので 拡張がモジュールをまたがないなら大した問題はない 他の言語でもモジュール内操作に対してはあんまりフールプルーフじゃないしね がHaskellの場合は拡張が子モジュールに伝播してしまう
Ruby の偽は、false, nil の2つだけ! JavaScript, Python, PHP などは、偽が10個ぐらいある! 空文字列・空配列・空辞書とか、0, 0.0 とか、 これらの言語は、しょーもないバグが多い! だから、Rubyよりも生産性が低い!
『入門HASKELLプログラミング』2019年07月31日発売予定 https://www.shoeisha.co.jp/book/detail/9784798158662 「コンピュータのプログラミング」から脱却し、“学術”ではない、実用度重視のHaskell 入門書 Haskellは、関数型プログラミングを研究する対象としての側面が強すぎ、一般的なアプリ ケーション構築を目的とした開発言語の側面が、ともすればおざなりになりがちでした。 そのため、他の言語(JavaとかC/C++とかC#など)がこなす、ありふれたアプリケーション をHaskellで構築しようとすると、キーボードを叩く指が止まってしまうことがありました。 本書は関数型プログラミングの基本を押さえつつ、いわゆる「開発言語」として実用的な プログラムを書けるようなレベルに誘う一冊です。(後略) >>386 rupy死んだのになんで生きてるの?ww とっとと後を追いなよwwww Pythonのfalsyな値には、そんなに違和感はないけどなぁ……。
【実体験】ブログを1,000記事ほど書いたら、月300万くらい稼げた話 VIDEO &t=604s 【報告】ブログで「月収1,000万」を達成できました【方法を解説する】 VIDEO 年間ほど努力したら「年収3,000万」になったので、経験談を語る VIDEO 期間工ブログの収入は1500万円でした。【フリーランスの現実&底辺からの復活編】 VIDEO 年商1300万のプロブロガーの初心者時代から今までの軌跡 VIDEO 【収益報告】実働月10hでも大金稼ぐ方法を解説【年収6,000万】 VIDEO &t=288s 無料ブログは稼げない。稼ぐならオススメはWordPress一択の理由 VIDEO get programming with haskellは、stackがでてくるの終盤だったり、 あまり実用度重視じゃないんだけどなー
>>389 Ture + True みたいなのはエラーにしてくれたら良いのにとは思う ありがとうございます。 既存の型を独自の型クラスの インスタンスにする事は 同モジュール内の拡張として プログラムする人が責任を持つべきなので 問題はないとの事で了解しました。 急いで質問を書いたので 型クラスを型と間違って書いてしまいすみませんでした。
プログラム板にキチガイ降臨中!botに一晩も反応する異常さ 一般人(学校恩師)に殺害予告をしているのでスレ建て通報してください。 http://2chb.net/r/tech/1559872586/ 142 名前:a4 ◆700L1Efzuv 投稿日:2019/06/18(火) 05:29:55 ID://qVkzO >>141 名古屋の人な 俺ね、君の問題を大橋先生と混ぜないことにする。つまりね、 片桐孝洋のことをボコろうと思う。普通に顎の骨を折る。これくらいで警察来るか? 一般市民とかさ、普通にさ、俺らの秘密なんだけどさ、日本人なんて復活ねーから。 functoriality とはどのような性質のことでしょうか?
>>397 補足しますと、functorial は分かります。 ですが、functoriality がいったい何に対してどのような意味で使う言葉なのか分かりません。 Hask圏を例にしてくれると助かります。