haskell-jp / questions #70

確かに、言われてみればなんの区切りもなく匿名関数が始まっているようで、普通の式とどうやって見分けるんだろうという感じがしますね...
たしかに。
括弧にくるんでるからって安心してましたけどたしかにexprASTも括弧にくるまれてるから安心できなかった
なるほど,不思議な動作ですね… 確かに Strict の時のみ stack overflow になりました… ちょっとそれは想定してませんでしたね…
あ,いいのか.過去の自分に追いつけてなかった.
まず, Strict をつけようがつけまいが,
foldl (\ z x -> x : z) [] [1..n]


let k = \ z x -> x : z in (([] `k` 1) ... `k` n)

みたいなものを生成することになります.でそれぞれの括弧の中身はサンクのままヒープにのって評価されるのを待つことになります.

evaluate でそれが WHNF まで評価されることになりますが,まず一番外側の評価
(… `k` n) => n : ...

が実行されることになります. Strict をつけない場合 ... は評価されませんが, Strict をつける場合 ... の部分が評価されることになり,さらにその評価のために k (…) (n - 1) の評価が走りという感じで,どんどんスタックに退避された値が積み上がっていきスタックオーバーフローになります.

なお,ちゃんと foldl' を使った場合,ヒープに積み上がるはずだったサンクが先に消化されながらループが回るため,どちらの場合もスタックオーバーフローは起きません
あ,だから Strict 拡張のみで stack overflow する例なんですね.前のコメントは間違いですね.失礼しました
初めて template Haskell を書いたのですがビルド時に 10GB 以上消費されるようになってしまいました…… :cry:
コードレビューしてほしいです
https://github.com/kakkun61/tuple/pull/1
Ty*等構文木のコンストラクタを直で使うとバージョンアップで壊れやすいものができあがるので,可能な限りQuasi-quotationを使って書いておいたほうが幸せになると思います.
なるほど!
Q モナドは, runQ を使えば IO の元で走らせることができるようになっているので,それでデバッグできます.大体のデータ型は Show が実装されているので,単純に表示してみると良いと思います.

>>> runQ (consType 1) :: IO [Dec]
[TySynInstD Data.Tuple.List.Data.Cons (TySynEqn [VarT x_2,TupleT 0] (AppT (TupleT 1) (VarT x_2)))]


みたいな感じでそれぞれの関数の Dec を表示する Main モジュールを書いて,プロファイルを取ってみるといいと思いますね.

ついでにですが,無限リストの利用は計画的に行った方が良いと思いますね
runQ したのをわざわざコピーしてました……
できないと思う。少なくとも僕が関わっているプロジェクトではstackでインストールしたパッケージをnixの環境では利用できなかった。


OSSでhydra使うにはどうしたらいいでしょうか。自分でたてるしかないですか?
自分もよくわからないからきいてみます!
お疲れ様です
type levelの関数をpropertyテストするにはどうすればいいでしょうか?
doctestでkinds!やtype-specで個別の値はテストできるのですが。
あとはtemplate haskellつかうとか?
https://hackage.haskell.org/package/should-not-typecheck をうまく使えば... と思ったけど型レベルで生成する必要があるわけですよね... :gununu:

確かにTemplate Haskellを使って頑張って書くしか思いつかないですね... (新しいパッケージを作るチャンス!
改めて試して、
foldr (\x z -> x : z) [] [1 .. size]

と、 foldr にした場合、
Strict をつけた場合最適化を有効にしてもスタックがあふれますね。大体理屈は foldl の場合と同じ、ですよね?
foldr に渡した関数 (\x z -> x : z) は実質的に両辺をWHNFまで評価する : ということでしょうから。
foldr の場合 foldl の時と事情が少々異なっていて,まず strict な foldr 相当のものは通常リストを reverse するなどしない限り,固定スタックの再帰にできません.それは,リストの後ろの要素から得られる値が分からないと前の要素に対しての計算ができないからです. foldr の場合,
let k = \ x z -> x : z in (1 `k` foldr k [] [2 .. n])

みたいなものが最初にヒープに乗ることになります.そして,このサンクを評価する時 k が strict なので, foldr k [] [2 .. n] 部分の評価が始まりこの時スタックに値が退避されます.同様の操作がされることによってスタックがどんどん積み上がっていくことになりますが,ヒープの消費量はサンクが nursery にいる間に処理されるため抑えられます.

foldr'foldl を使って実装されているため,スタックを消費しない代わりにヒープを消費する実装になっています (これは前回のやつの原理からですね.今回はリストを生成するため,そちらの方にもヒープが割かれて顕著な差がないですが, \ x z -> x とかだと差が出ると思います) なので,基本的に Strict 拡張下では foldr 系統は使ってはいけません.代わりに foldl' を使ってなんとかするか, lazy にするか, mutable の使用を検討すべきです.

foldl の例は一見 strict にしたらいけそうに見えるけど,実は中身が正格消費になっていないので heap を辿りながらスタックオーバーフローしてしまう例になっていて, strict にするだけではダメで中身も正格消費なものを使わないといけないということになります.ここらへんは, (`foldl` は有名な例ですが) 遅延評価での罠を知っていないと判断できないですし,逆に strict 拡張はこういう遅延評価の罠から生まれたもので, BangPattern と strictness flag を書くのがめんどい人用の拡張なので,背景を抑えると strict 拡張がどういう動作をするのかは見えやすいのでは? というのがあのコメントで言いたいことですね
なので基本的には、
* foldr 系統は strict 下では使ってはいけない
* foldl 系統は (strict 下でなくても) 正格消費版を使うこと
みたいな感じですね
詳しい解説ありがとうございます!
@makoto0607 has joined the channel
こんにちは!OSSでHydraを使うならこれを参考にするといいよっていわれました。
https://nixos.org/hydra/manual/#chap-installation
ありがとうございます。
@atsushi3r has joined the channel
cutsea110@waikiki ~/.ghc/x86_64-linux-8.6.5/package.conf.d (master *)
$ ghci -V
The Glorious Glasgow Haskell Compilation System, version 8.6.5
cutsea110@waikiki ~/.ghc/x86_64-linux-8.6.5/package.conf.d (master *)
$ ghc -V
The Glorious Glasgow Haskell Compilation System, version 8.6.5
$ cabal -V
cabal-install version 3.0.0.0
compiled using version 3.0.0.0 of the Cabal library


な環境で,cabal install criterionしたらひととおりinstallされて最後にcriterion-reportも${HOME}/.cabal/bin以下でsymlinkされた様子.
ところが肝心のCriterion関係のモジュールが見当りません.

cutsea110@waikiki ~/.ghc/x86_64-linux-8.6.5/package.conf.d (master *)
$ ghci
GHCi, version 8.6.5:   :? for help
Loaded GHCi configuration from /home/cutsea110/.ghci
ghci> :m +Criterion.Main

<no location info>: error:
    Could not find module ‘Criterion.Main’
    It is not a module in the current program, or in any known package.
ghci>


一応ghc-pkgで探してみましたが...

cutsea110@waikiki ~/.ghc/x86_64-linux-8.6.5/package.conf.d (master *)
$ ghc-pkg find-module Data.Vector
/usr/lib/ghc/package.conf.d
    (no packages)
/home/cutsea110/.ghc/x86_64-linux-8.6.5/package.conf.d
    vector-0.12.0.3
cutsea110@waikiki ~/.ghc/x86_64-linux-8.6.5/package.conf.d (master *)
$ ghc-pkg find-module Criterion.Main
/usr/lib/ghc/package.conf.d
    (no packages)
/home/cutsea110/.ghc/x86_64-linux-8.6.5/package.conf.d
    (no packages)


それとは別に

${HOME}/.cabal/store/ghc-8.6.5/criterion-1.5.6.0-ca84ad97c60c610760a3be5cf2c9aa3cb940af0857a14e85a3e329ed3111cd2b/lib


には

$ ls
.   Criterion         Criterion.hi            Paths_criterion.hi                                                                                   libHScriterion-1.5.6.0-ca84ad97c60c610760a3be5cf2c9aa3cb940af0857a14e85a3e329ed3111cd2b.a
..  Criterion.dyn_hi  Paths_criterion.dyn_hi  libHScriterion-1.5.6.0-ca84ad97c60c610760a3be5cf2c9aa3cb940af0857a14e85a3e329ed3111cd2b-ghc8.6.5.so


という具合でモジュールが入っている様子です.
.cabal側のstoreってのがどうも良く分かってないのですが...
これはどうやればCriterion.Mainモジュールを使えるようになるんでしょうか?
あう.自己解決したぽい.
cabal replから

$ cabal repl
Resolving dependencies...
Build profile: -w ghc-8.6.5 -O1
In order, the following will be built (use -v for more details):
 - h2p2-0.1.0.0 (exe:h2p2) (first run)
Preprocessing executable 'h2p2' for h2p2-0.1.0.0..
GHCi, version 8.6.5:   :? for help
Loaded GHCi configuration from /home/cutsea110/.ghci
[1 of 1] Compiling Main             ( Main.hs, interpreted )
Ok, one module loaded.
ghci> :m +Criterion.Main
ghci> :t defaultMain
defaultMain :: [Benchmark] -> IO ()
ghci>


とすればうまくloadできました.
build-dependsに入れてロードできなかったので調べはじめてたのに今はうまくロードできている.謎ですがひとまず解消しました.
確かcabal 3.X ってnew-**がデフォルトになる(new-無しでもnew-**が呼ばれる)って話でしたよね。なので、適切な.cabalのあるディレクトリでcabal replやcabal buildをすれば、最悪インストールされていなくても宜しくやってくれるはず
素のghc(i)からでもロードできるようにするには、ライブラリの cabal (new-)install--lib オプションを付けるんだったと思います
ぽんちゃん
@ぽんちゃん has joined the channel
ぽんちゃん
質問するのが初めてでありますので必要な情報が足りなければすみません。こちらの情報としてGithubのURLを貼っておきますが、ピンポイントで欲しい情報があればそこだけピックアップして貼ります。

SlackBotを作ろうと思い、ネットの記事やSlackAPIのGitHubのページを参照してサンプルコードをとりあえず実行しようと思ったのですが、

    Not in scope: type constructor or class 'SlackHandle'
   |
27 | echoBot :: SlackHandle -> IO ()
   |            ^^^^^^^^^^^


ビルド時にこのようなエラーが出てきます。検索しても同じような状況で困っている人がいなそうなので、質問させていただきます。どうか知恵を貸していただけませんでしょうか。

↓GithubのURLです。
https://github.com/P0ngCh4ng/OkSlackBot
参考にしたページがあるとありがたいです
どちらの記事でも SlackHandle なる型は使ってないようですね...
本当にこの記事なんでしょうか? :thinking_face:

いずれにしても、そのエラーは 「 SlackHandle という型が存在していない」というエラーです。
おそらく参考にした記事の内容が古く、APIが変ってしまっているのが原因と思われます。
あっ、元ネタがわかりました。
https://github.com/mpickering/slack-api のREADMEですか... :cold_sweat:
確かに SlackHandle 使ってる...
ぽんちゃん
実を言うと記事の方は依存関係を参考にしたんですが、記事のコードを丸パクしても全く違うエラーが出てくるのでそちらからのアプローチは諦めて、依存関係はそのままにAPIのGithubのExampleを参考にした形です。
ぱっと見Qiitaの記事の方が最新版のAPI http://hackage.haskell.org/package/slack-api-0.12/docs/Web-Slack.html に則っていて正しそうに見えるんですが、 https://qiita.com/kentahama/items/261c9c86d02161680933#comment-d9420910bf8304645efd なんて指摘されてるな..
GitHub の README は新しすぎるようですね. SlackHandle は現状の開発版で新しく入ったもののようです.参考にすべきは,こっちの方かもしれません:
https://github.com/mpickering/slack-api/tree/v0.12
なおリリースが 2017 年なので, Slack の現在の API に追いついてないかもしれませんね.最新のものがちゃんと動くかは分からないですが, master のを使ってみるといいかもしれません.少なくとも 0.12 では次のようなエラーが報告されてますね:
https://github.com/mpickering/slack-api/issues
ぽんちゃん
そちらのバージョンで試してみます!
ついでにこちらの方は一応メンテされてそうですね:
https://hackage.haskell.org/package/slack-web

example はなさそうですが…
使用する場合は stack.yaml

extra-deps:
- git: 
  commit: <使用したいコミットのSHA>


と書き加えてください。
参考: https://docs.haskellstack.org/en/stable/yaml_configuration/#extra-deps
slack-webの方はSlack Web API向けのライブラリーです。bot作りには向いてません(我らが https://github.com/haskell-jp/slack-log を作るのにはぴったりでしたが)
ぽんちゃん
0.12の一番新しいコミットSHAを登録して今ビルドし直しています。
コードは0.12のexampleを使いました。
ぽんちゃん
user error (When parsing the record Preferences of type Web.Slack.Types.Preferences.Preferences the key email_misc was not present.)

このエラーが出てきました;;
記事を丸パクしたやつと同じエラーでした。正直これはslackAPI側の権限とかそっち周りな気がするんですが見たことある方いらっしゃいますか?
https://github.com/mpickering/slack-api/commit/5fbc7732272289d5bdde9227b68c9ec362115f27
このコミットで修正されている問題だと思われます。
masterの最新版を使わないとダメなのかも知れません... :fearful:
多分これですね.現状の master では治ってるようですが,リリースはないと思うので master のコミットを使うしかないような気がします
https://github.com/mpickering/slack-api/pull/99
ぽんちゃん
こっちでビルドし直してみます!
ぽんちゃん
user error (When parsing the record Preferences of type Web.Slack.Types.Preferences.Preferences the key full_text_extracts was not present.)

こ、今度は違うkeyのエラーが、、
最新版でこれだと直近のバージョンだとslackbotは作れないのでしょうか,,,
要するに最近のSlackの仕様変更に追いついてない、ということなので
https://github.com/mpickering/slack-api/pull/99 みたいに直すPull requestを送るしかなさそうですね... :disappointed_relieved:
ずっとghciで確認してて、ロードできなくて、cabal replしてみたらうまくいったので、そのあとでemacsからC-cC-lしたら通ったんだけど、もしかしてcabal replしたことで活が入った??