haskell-jp / questions #84

詳しい事情はhaskell-cafeあたりで何度か触れられていると思います(自分もぶっちゃけよく調べてない...
https://takenobu-hs.github.io/haskell-wiki-search/?siteview=full からチェックを入れて検索してみてください。
みてみます!
ありがとうございます
あと、base-4.13以降のドキュメントについては https://wiki.haskell.jp/Hikers%20Guide%20to%20Haskell#base-4.13%E4%BB%A5%E9%99%8D%E3%81%AE%E3%83%89%E3%82%AD%E3%83%A5%E3%83%A1%E3%83%B3%E3%83%88 でも触れているとおり、GHC添付のドキュメントを探れ、とのこと。
オォ…知らなかった…
ありがとうございます
ちょっとわかりづらい…
@HK290000 has joined the channel
@ has joined the channel
@GrimssonG has joined the channel
質問させていただきます.
このプログラムのlikeReturn に相当するような処理は実現可能でしょうか?

ST s (STArray s a b) を引数にとって, <ST action> をその内部に適用しつつ,runSTをその内部で利用したいというかなりわがままな利用ができたら色々とキレイに書けるので試行錯誤しています.

> update i test = readArray test i >>= writeArray (_test test) (i + 1)
の形にしたり,
> runSTTest :: STTest s -> Int -> ST s Int
にするとシンタックスが手続き型っぽくなるので,できないものかと.

unsafePerformIOを使ってunsafeRunSTを作ればできそうですが悩みどころです.

現行で発生するエラーは下記になります

> *• Couldn’t match type ‘s1’ with ‘s’*
>    *‘s1’ is a rigid type variable bound by*
>     *the type signature for:*
>      *likeReturn :: Test s -> STTest s*
>     *at /Users/akagi/Documents/Programs/Haskell/VirtualEconomy/src/Sample.hs:26:1-36*
>    *‘s’ is a rigid type variable bound by*
>     *the type signature for:*
>      *likeReturn :: forall s. Test s -> STTest s*
>     *at /Users/akagi/Documents/Programs/Haskell/VirtualEconomy/src/Sample.hs:25:1-42*
>    *Expected type: ST s1 (Test s1)*
>     *Actual type: ST s1 (Test s)*
>   *• In the expression: ST (\ s -> (# s, x #))*
>    *In an equation for ‘likeReturn’:*
>      *likeReturn x = ST (\ s -> (# s, x #))*
>   *• Relevant bindings include*
>     *x :: Test s*
>      *(bound at /Users/akagi/Documents/Programs/Haskell/VirtualEconomy/src/Sample.hs:26:12)*
>     *likeReturn :: Test s -> STTest s*
>      *(bound at /Users/akagi/Documents/Programs/Haskell/VirtualEconomy/src/Sample.hs:26:1)*
質問の意図が取れているか自信がないのですが、
• runSTTestが ST s Int ではなく Int を返せば、 runSTTest ... >>= f ではなく f (runSTTest ...) と書けるので恰好いい
• なので、runSTTestの中でrunSTを呼び、外側のSTに紐づいたSTMArrayを参照したい
というモチベーションでしょうか。内側にいるとはいえ、STのRankN多相で守られた配列を参照しようとしている事になるので、無理っぽい気がします
type STTest s = forall s. ST s (Test s)

この宣言ですが、右辺のforall sで新しいスコープの変数sが定義されてしまって、左辺のsは使用されないのでは。
ご返信ありがとうございます.
意図はそのとおりで,単に見た目が数式のとおりになるので,という話なのですが,難しそうですね.

たしかに,左辺のsは使用しませんね.左辺のsを消すと

forall s. Test s -> STTest
となり
動かない理由が直感的にもわかりやすいですね.

実際のコードでは,複数の時系列変数が大量につまったTest sのようなものを引き連れているので, わかりやすさと更新の速さを両立させたいですが,なかなかうまく行きません.
更新を伴う大量のデータを引数に引き回す際にもともとはMapをつかっていたものをSTに変更しようとしていましたがrunSTをかませるとコードがかなり複雑になってしますので,難しいところです
@Peacock has joined the channel
純粋に書いたコードをMutableに直すのが難しいのは、Haskellの泣き所の一つですね(他の言語でも難しいのは変わりないけれど、他の言語だとそもそも最初からMutableで書くので手間が発生しない)
元の問題の解決方法としてはunsafe系しかなくて、具体的には unsafeIOToST . unsafeSTToIO でsの型を強引に合わせられるので、それを使えばなんとか……という感じです
@ktahi has joined the channel
質問させていただきます.
truncateにNaNをくわせると,以下のような挙動になるのは,仕様ですか?

truncate 1.1
1
truncate (1/0)
179769313486231590772930519078902473361797697894230657273430081157732675805500963132708477322407536021120113879871393357658789768814416622492847430639474124377767893424865485276302219601246094119453082952085005768838150682342462881473913110540827237163350510684586298239947245938479716304835356329624224137216
truncate $ log $ (-1 :: Double)
-269653970229347386159395778618353710042696546841345985910145121736599013708251444699062715983611304031680170819807090036488184653221624933739271145959211186566651840137298227914453329401869141179179624428127508653257226023513694322210869665811240855745025766026879447359920868907719574457253034494436336205824
この挙動のせいで,ループが無限に終わらないのに気づくのに一日費やしました,,笑
全体の処理を早くしようと,STに変更したり色々していたのですが,先程新しくした質問の方が原因でした.
実時間をとってloop回していたのですが,処理が重くなるとtruncateにNaNが回る仕様になっていて,無限に処理が終わらないという...
質問の答えじゃなくてすみません、 (1/0)NaN じゃなくて Infinity かと。
あ,そうですね,質問文が InfinityやNaNでした.ご指摘ありがとうございます.
で、これは推測ですが、Haskellの仕様と言うよりは、浮動小数点演算の仕様な気がしますね...
C言語で近いことをやった場合の結果: https://ideone.com/hQYKZG
さらに試していて気づいたんですが、結果を Int にしていると 0 が返るみたいです(でもこれも環境依存かもだし、あまり期待しない方がいいかも)。
> truncate  (0.0 / 0.0) :: Int
0
なるほど.
取りあえずのところ,NaNやInfinityを渡していたのがまずいので,
truncateSafe x
| isNaN x =
| isInfty x =
的な対処でやり過ごしますが,
これがあるあるではないのなら結構ハマる人多そうに感じます.
ご教示ありがとうございます.
なるほど :bulb: 確かに見落としがちな話だと思うので、パッケージ :package: にしておくと案外受け入れてもらえるかも知れませんね!
今調べてみるとceiling , floor, roundでも同様でしたね.
ちなみに toRational や realToFrac にも同様の問題があります
さすが、地雷踏み済みか... :open_mouth:
Float と Double 間の realToFrac は最適化の有無(rewrite rule発動の有無)でNaNやInfに関する挙動が変わるという素敵仕様です:sob:
STアクションAを引数にとってその内部でAをrunSTするとそれぞれが独立に評価されるので同じアクションが何度もゼロから評価されものすごいコストになることに気が付きました,
いずれにせよこれをやるのはコストが高すぎるようです..
a .+ b = (+) <$> a <*> b
のような形で中置演算子を定義していけば,そのまま内部で使えそうだという方法が結構ニーズに近いものだったかもしれません
@Summit has joined the channel
@Noah has joined the channel
vector のbugfixを書いているんですが、 INLINE 関数がloopbreakerになってしまっているかってどうやって検証するんでしたっけ?
@ms has joined the channel
-dcore-lint でINLINEプラグマが付いた関数がloop breakerになると警告が出たような気がします
単純にある関数がloop breakerか否かを調べるだけならCoreを出力してOcc=Loopbreakerみたいな情報が付いてるかでチェックできます
なるほど。つまり、 -ddump-ds とかですね?
Occ=Loopbreakerは-ddump-simplで確認できます
確かにー。ありがとうございます。
Hackage / Stackage にも登録がある cabal package (non-stack project)を修正した上で、 Hackage 版ではなく修正版に依存するように、 cabal exec ghc (これがどれくらいまともに稼働するコマンドか理解していません)か stack ghc か、またはそれに類する何かを走らせるにはどうすればいいでしょうか?
ライブラリコードがインラインされた時の最適化がうまくいくように修正を掛けたつもりなので、それを適当な短いコードに対する ghc -ddump-simpl で確認したいのですが、別にtestをいきなり追加したいわけではないし、自分のパッケージでもないので、いきなりそのパッケージの cabal.project を弄るのにも抵抗があるんですよね・・・。(いやもちろん git-managedなので弄るのに問題はないんですが)
修正したパッケージは手元にあって、まだhackageに公開してないってことですよね?
該当のパッケージのディレクトリーで stack build した上で stack exec ghc すればいけるはずだったかと。
今考えているのって non-stack project ですから,その場合, stack.yamlpackage.yaml***.cabal から適当に作ってから,ってことになるんでしょうか.
ああー、確かにstackでやる場合 stack init はしないといけませんね(別に package.yaml は必須じゃないですよ!)。
で、cabalでやる場合でもstackと同様あらかじめ cabal build してから cabal exec ghc でいけるはずです(普段cabal使わないのでちょっと自信ない)
型シグネチャを書かずに cabal v2-repl で正常にロードできるコードがあります。
:t で確認した型をそのまま型シグネチャとして追加して :reload するとエラーになる。
このような一見矛盾と思える挙動について、そもそもどういった原因が考えられますか?
お手元のcabalのバージョンが2系だった場合、cabal new-{build,exec}の方がおすすめかもです。ただ、cabalのexecってghcのオプションはケアしてくれるんだったかな…
GHC関係の環境変数はいい感じに整えてくれるからうまくいくだろう、と信じています...
@katsu-o has joined the channel
(cabal-3.2.0.0に甘えてnewを忘れてしまった人間なので) cabal exec ghc を試したのですが、
import Data.Vector

main = return ()

ケア、してもらえなかったです・・・。リコンパイルをはじめた挙句多分 cabal.projectvector.cabal すらも読んでない… (`vector.cabal` に記述があるはずの vector.h が発見できないとか抜かしやがりましたので)。
あとで stack ghc と、あと cabal.project.local を用いた cabal build を試してみます。