haskell-jp / questions #44

実のところ、 ghc に関しては ghci を起動しちゃえばわかるじゃん、という回秘策を使っていたので、真面目に調べていなかったのです… 今回 haddock のバージョンを知りたくなってハマった、というのが正直なところです :sweat_smile:
@yasuhide.takase has joined the channel
@ponta027 has joined the channel
Haskellでいう「作用」とは、「主目的である値」を返すこと以外の関数の振る舞いのこと。「副作用」とは、「作用」の一種で、特に外界との入出力やグローバル変数の変更などのこと。で、いいでしょうか?
Haskell の IO を指して副作用と言うのは、それが意図している動作であるから間違いであり、作用と言うべきだという話を前に聞いたことがあります。どっちが正しいのか議論をするつもりはなくて、こんな話もあったよー、というだけですが……
ただ説明する上で「副作用」という言葉は使った方が便利かなぁと思いますし、「「副作用」とは、「作用」の一種で、特に外界との入出力やグローバル変数の変更などのこと」という定義にはそんなに違和感を感じません。
プロセス間通信に関する質問です。2つのプロセスがお互いのHandleを相手に渡すことで通信を実現しようとしているのですが、子プロセスから親プロセスにHandleを渡す方法がわかりません。なにか方法はありますでしょうか。
https://gist.github.com/HirotoShioi/a0222e19c5dd2746ae04d3a2ba88c1c0
あ、、わかったかも!!
回答と関係ないですが、どうせ fdToHandle するなら createPipeFd ではなく createPipe を使った方がよいのではないかと。
ソースを読んだ限り結局やってることは同じみたいです。
fork前に作ったfdとそれに紐付いたリソースはforkで子プロセスにも継がれますが,
fork後に作ったfdのその数値だけを単に伝えて表面上だけfdの値を再構成できたとしても,
伝えられた側のプロセス内にそのリソースが実際に存在するわけではないので利用できません.
unix domain socket と sendmsg/recvmsg syscall を利用するとかによる descriptor passing が必要だと思います.
なるほど、ありがとうございます
fork 「後」につくった場合は notogawa さんのおっしゃるとおりですが、 fork 「前」に作った fd の番号は fork 後に特に何もしなければ「同じ番号で両方のプロセスが同じリソースをつかんでいる」状態になります。なので、 pipe システムコールで作った二つの fd は「write 側でかいたものが read 側でよめる」という状態になります。ただしこれは「片方向パイプ」の役割しか果たさないので、通常は「書きたい側のプロセスは fork 後に read 側だけ閉じて write 側だけ残し、読みたい側のプロセスは fork 後に write 側だけ閉じて read 側だけ残す」ということをやると思います。
双方向に通信したい場合(どちらのプロセスからも書いたら相手側で読めるようにしたい)のなら、 fork 前に二つ pipe を作る(つまり全部で4つ fd を確保する)か、 socketpair システムコールを使うことになると思います
Haskell で socketpair が使えるのかは知りません^^;
「前」の話はわざわざ言うことないかなと思って1行目だけ言及して流しました.
今回のソースをざっと見た感じでは単に双方向通信をしたいだけに見えるので、デスクリプタパッシングとか出してこなくても…という気がしたのです^^;
(デスクリプタパッシング、存在は知ってるけど一度も使ったことないし^^;)
先日の数独のコード、修正してみました。諸々の細かい修正に加えて、効率化を図って Tree とは別のやり方を試してみました。また、おかしな所があればご指摘いただけると嬉しいです。
https://gist.github.com/gaxiiiiiiiiiiii/b1e58813d9afea011c4466c1c18bc1ca
今気づきましたが、 sortBy row b がダブってますね。。。
サンプルコードはあくまで質問のために簡略化しているだけでしょうし,本当にやりたいことがサンプルコードになっているとは私は受け取らないので,こういうケースではできるだけ質問内容「子プロセスから親プロセスにHandleを渡す方法」を正面から突破する方法を答えるようにしていますね
Data.List に
sortOn :: Ord b => (a -> b) -> [a] -> [a]
がありますよ
Tree を使わなくなってすっきりしてるので、さらにすっきりさせるなら loopState -> Maybe State ではなくて getStates とおなじ State -> [State] にすると、場合分けが null empties = [(filled, [])]otherwise = concatMap loop $ getState states だけで済む(たぶん)ので簡単になりそうです
あんまり詳しく見てないので細かいことですが,
filled  = filter ((/= 0) . num) board
empties = filter ((== 0) . num) board

とかも Data.List モジュールの partition を使って
(filled, empties) = partition ((/= 0) . num) board

と置き換えられます.リスト関係で標準にありそうだなと思った機能は GHC 8.6 をお使いで型が類推できれば Data.List を import した上で, valid hole fits を使うと良いと思います.例えば, partition の型は (a -> Bool) -> [a] -> ([a], [a]) と類推でき, ghci でこの型や sortBy の型を検索すると以下のようになります.
Valid hole fits のサンプルです.長かったのでファイルにしました
それから,個人的な好みでもありますが,
classify = flip div 3

は,セクションを使って
classify = (`div` 3)

と書く方が適用の仕方が視覚的で好きです.
あ、あとパターンマッチで使わない変数に名前がついているのが気になりました(getCandidates の e:es の es とか)。
使わないところはアンダースコアにしたほうがいいと思います
null empties = [state] としてしまえば filled のほうの名前も要らなくなりそうですね
というか loop の定義をわけて loop [email protected](_,[]) = [state]loop state = concatMap loop $ getStates state にしたほうがすっきりするかも
おお!見違えるほどスッキリに!変に小難しく考えていたようでお恥ずかしい限り、、

ありがとうございます!
@kafu.h1998 has joined the channel
cabal new-build使用時、ビルド成果物のディレクトリを取得する方法はありますか? stackなら stack path --dist-dir で出来るやつです
モナドの説明時に、「作用」といった場合、おっしゃる通り「「主目的である値」を返すこと以外の関数の振る舞いのこと」を指していると思います。しかし、その文脈で「特に外界との入出力やグローバル変数の変更などのこと」を「副作用」と呼び分けてはいないように思います。
純粋な計算に関する文章では「「主目的である値」を返すこと」が「作用」で、モナドの作用は「副作用」に。
モナドに関する文章では「「主目的である値」を返すこと以外の関数の振る舞いのこと」が作用になるように思います。
用語の統一を主眼としてのお話であれば「作用」「副作用」のどちらかしか使わない、というのもありかなと思います。
ないので、doctest で困ります。困った場合、 cabal-doctest を使うのが解決方法のようです。
Programming in Haskell 2nd ed を翻訳中で、その中に両方の言葉が出てくるので、副作用という言葉を使わないという選択肢はないのです。。。
ちなみに本書で effect は、純粋な計算の対義語として使われています。
逆に、「主目的である値」を返すこと以外の関数の振る舞いのうち、「外界との入出力やグローバル変数の変更」じゃないものって何を含めてるんですか? :thinking_face:
こと IO に関して言えば大半がそれに該当しそうな気がしますが... (例外を投げるとかスレッドを作るとか?
なるほど、ありがとうございます。とりあえず今はこんな感じです。わざわざ親プロセスにハンドルを渡さなくても、子プロセス側でメッセージを送って、後で親プロセス側で受け取れることがわかりました。
https://gist.github.com/HirotoShioi/443ab877898efa5f85cabd89b62d6bfd


「いや、親プロセスから送れるようにしろ」と言われる可能性も一応あるので、koyamaさん、notogawaさんがおっしゃってることに関しても調べてみます。
全く同じではないのです用途次第ですが、executableをリストアップするなら cabal-plan list-bins が使えます。 http://hackage.haskell.org/package/cabal-plan
plan.json を直接読むことも出来ると思いますが、中身の構造が安定しているわけではなさそうな気がしています
solveはMaybe Boardを返すようにしたほうがいいと思う。理由は2つあって、まず与えられたBoardが必ず解けるわけではないことを型で表現したほうがいい。例えば全てのマスが1だったらそれは解けないよね。そういうのにも対応していると型レベルで宣言すると印象が良い。
もう1つはfromJustは(おそらく)部分関数だから使わないほうがいい。
http://hackage.haskell.org/package/base-4.12.0.0/docs/src/Data.Maybe.html#fromJust
http://tanakh.jp/posts/2011-12-25-partial-function-considered-harmful.html
部分関数はその場しのぎで使うにはいいけど、最終的には取り除く必要があります。
Maybe Boardに変更するのは、do記法を使えばそんなに難しくないと思う。
あと懸念要素としてぱっと見た感じ、getStates、getCandidatesの計算量がかなり大きいから、大量の問題を解こうとすると危ないかもしれない。
https://gist.github.com/gaxiiiiiiiiiiii/b1e58813d9afea011c4466c1c18bc1ca#file-numberplatemaybe-hs-L84
https://gist.github.com/gaxiiiiiiiiiiii/b1e58813d9afea011c4466c1c18bc1ca#file-numberplatemaybe-hs-L89
でも正直これはどうにもならないかもしれないから、その場合は気にしなくてもいい。
むしろ余詰めも含めて可能な解を全て求めるという考え方でリストにした方がよいとも思うのです。(最初の一個を取り出して表示しているのは単に表示時のポリシーの問題ということで、 solve 自体の機構ではない、という考え)
ちなみに高速化したいのなら、 empties のたまたま左上のやつを次の一手に選ぶのではなく、先に「すべての empties に対して candidates を求めてからその中でもっとも少ない candidate を返したマス」を次の一手に選ぶようにすると劇的に高速になると思います
https://www.ipsj.or.jp/07editj/promenade/4611.pdf この論文がそういう解法だったとおもいます
…と書いておくと執筆者ご本人 @nobsun さんからフォローがあるかしら^^;
ありがとうございます、cabal-plan辺りを調べてみようと思います!