haskell-jp / questions #61

まったくの思いつきで恐縮ですが、
forkIOで別スレッドで処理される中で、コネクションの`close`が意図するタイミングで呼ばれていない可能性はありませんか?
insertLog db' lfbracketを使うようにするとどうでしょうか。
ありがとうございます.
bracketを利用しましたが同様の挙動になりました.
insertLog :: String -> LogField -> IO()
insertLog db' lf = bracket
                   (open db')
                   close
                   $ \conn -> execute conn "INSERT INTO log VALUES (null,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)" lf
https://teratail.com/questions/5099 このような記述をみつけました。本質的な問題なのかも?
たしか、現在の実装では、当該データベース ファイルに対する更新処理はジャーナル ファイルにいったん保持した後、ジャーナルの世代が古い順からトランザクションとして処理していき(FIFO)、最終的にジャーナル ファイルがなくなるまでファイルを更新し続けます。
その際、更新処理が多重で走ることによりジャーナルをデータベース ファイルに適用するのが間に合わなくなってくると、ロックに関する例外を吐くようになります。
ロックの問題はどこかで「retryすればいいよ!」と見かけたのですが,もしかしたらその処理が追い付かなくなっているのかもしれないですね...
この際pgがmysqlを導入することを検討しようかと思います.
みなさんありがとうございます.
ログ書くときの forkIO を止めて同期的に書き込むだけで若干改善されませんかね(もちろんその分動作は遅くなりますが)
(どちらにしてもそれだけのリクエストを裁くのであればSQLiteは止めた方がいいのでしょうけども)
そうですね,このプログラム自体がサイトのレスポンスタイムを記録しておきたいものなのでspawnしたいです..
私個人のサイトなのでsqliteでいいかなと思ったのですが,pg動かすことにします.
ナイーブに字句解析器でトークンに位置情報を入れるというのはよくやります.
@n.kurata1005 has joined the channel
こちらの方法、今日になって気づいたんですが、 引数が2つ以上ある関数の場合、 (>>) の第2引数に渡した関数しか実行されない という落とし穴があるようです。 :scream:
自分でも調べてみますが、どなたか詳しい理由がわかったら教えてください...
Haskell-jp Blogの記事にしようかな...
https://haskell-jp.slack.com/archives/C4M4TT8JJ/p1559094017015900
例:
> a x y = putStrLn ("a: " ++ x ++ y)
> b x y = putStrLn ("b: " ++ x ++ y)
> ((>>) <$> a <*> b) "x" "y"
b: xy
(>>)が関数のモナドに対するものなので、ask
...みたいなふるまいをしていますね
っぽいですね... 自分も等式変換しているうちに見えてきました... :disappointed_relieved:
((<*>) <$> (((<$>) (>>)) . a) <*> b) "x" "y"
おおかわさんさすがです... :joy:
というわけで,単に2以上のarityに対して等価な変換じゃないというだけですね.落とし穴ではない
地道に簡約してみました

((>>) <$> a <*> b) "x" "y"
((fmap (>>) a) <*> b) "x" "y"
(((>>) . a) <*> b) "x" "y"
((\arg -> ((>>) (a arg))) <*> b) "x" "y"
((\arg2 -> (\arg -> ((>>) (a arg))) arg2 (b arg2))) "x" "y"
((\arg2 -> (\arg -> (\k -> (a arg >>= (\_ -> k)))) arg2 (b arg2))) "x" "y"
((\arg2 -> (\arg -> (\k -> (a arg >>= (\_ -> k)))) arg2 (b arg2))) "x" "y" -- Monadの (>>) を展開
((\arg2 -> (\arg -> (\k -> (\r -> (\_ -> k) (a arg r) r))) arg2 (b arg2))) "x" "y" -- (-> r) Monadの (>>=) を展開
(\arg2 -> (\arg k r -> (\_ -> k) (a arg r) r) arg2 (b arg2)) "x" "y" -- 入れ子になったλ式をくっつける
(\arg2 -> (\arg k r -> k r) arg2 (b arg2)) "x" "y" -- (\_ -> k) (a arg r) を簡約。aが消えた!
(\arg2 -> (\r -> (b arg2) r)) "x" "y" -- (\arg k r -> k r) arg2 (b arg2) を簡約。
(\r -> (b "x") r) "y" -- (\arg2 -> (\r -> (b arg2) r)) "x" を簡約。
(b "x") "y" -- (\r -> (b "x") r) "y" を簡約。
これ、:point_down: みたいに引数を一切追加しないで do に直したら unused-do-bind の警告になりましたね。
do
  a
  b

戻り値が関数になっている(あるいは、もっとアグレッシブに戻り値が () 以外の)アクションに対して (>>) を使うと警告が出る、みたいな仕組みを作るといいのかもしれません。
自分がYesodとPostgreSQLで同じような問題に突き当たった時は,コネクションを取得している文脈でコネクションを開放せずにコネクションをもう一度取得しようとしていて,複数の関数でコネクションを取得しようとしてデッドロックに陥ってました
Simpleの仕組みはよくわかりませんがDBを使ったらその場でコネクションを削除するようにすれば問題なくなるかもしれません
doはシンタックスシュガーだからコンパイル時に警告が出てくれるとありがたいですけど、 (>>) は第一引数のアクションの戻り値を捨てる関数だから、警告出すのは微妙な気がしますね……。 const 1 (f x) って書いたときに (f x) は評価されないよーっていう警告を出すかどうかみたいな。
気分的には、HLintに「こういう組み合わせの式は使わないで、こっちを使ってね」と警告させるのと同じような感じにすれば、オプトイン・オプトアウトも簡単になるしいいかな、と思うのですが、いかがでしょう?(現状のHLintにそこまでできたかは忘れましたが)
文脈を理解していないですが引数を必ず使わせたいなら linear types の出番?
それは確かにそのとおりですが、ちょっとオーバーキルかな... と。 :sweat_smile:
どちらかというと、意図しないインスタンスを使用しないためにはどうすればいいか、というところにフォーカスする方に個人的には関心があります。(ちょっと話がそれてしまいますが...)
https://haskell-jp.slack.com/archives/C5666B6BB/p1558343939072900 の時みたいに。
値を捨てている部分を可視化できるようなエディタの支援機能があったら面白そうです。 しばしば議論の的となるlength (1,2)とかもわかるし
↑に対して「1と2を捨ててる(見てない)」ってわかるやつってことですか?
よく考えたら何の意味もない例でした。すみません
@sky.is.gray has joined the channel
STArray (または STUArray )を複数同時に初期化するにはどうしたら良いでしょうか?
例えば一つならば 
buildA = runSTUArray $ do
  a <- newArray (0,2) 0 :: ST s (STUArray s Int Int)
  writeArray a 0 999
  -- detail omitted
  return a

λ> a = buildA
a :: U.UArray Int Int
λ> a U.! 0
999

これでOKですが
2つ同時にするとエラーとなります
buildAB = runSTUArray $ do
  a <- newArray (0,2) 0 :: ST s (STUArray s Int Int)
  b <- newArray (1,9) 1 :: ST s (STUArray s Int Int)
  writeArray a 0 999
  writeArray a 1 111
  -- detail omitted
  return (a, b)

• Couldn't match type ‘(STUArray s Int Int, STUArray s Int Int)’
                  with ‘STUArray s i e’
  Expected type: ST s (STUArray s i e)
    Actual type: ST s (STUArray s Int Int, STUArray s Int Int)
Lensを使っていて、ちょっと気になる挙動に出遭ったので、どなたか理由をご存知であれば教えていただきたいです。
こちらのコード https://gist.github.com/igrep/19139bb4e3bc7fe7988597559b9ab2dd なんですが、
viewThenSet :: Sample -> Lens' Sample Int -> (Int, Sample)

という Lens を受け取る関数を使って、
main = print . viewThenSet (Sample 1 2) $ field' @"sample1"

というコードを書くと、 Functor f が曖昧だよ!という型エラーになってしまいます(エラーメッセージの詳細はコードにコメントとして張りました)。

しかし、 . の代わりに $ を使い、 :point_down: のように書き換えると、エラーがなくなります(あるいは、どちらも使わずに括弧で囲うか)。
main = print $ viewThenSet (Sample 1 2) $ field' @"sample1"

通常、 f $ g $ x という式は f . g $ x という式に書き換えられることが知られてますが、なぜこの場合は . を使うと型エラーになるのでしょうか?
main = print $ viewThenSet (Sample 1 2) $ field' @"sample1"
2つ目はこう?
すぐに思い付いたのはこれですが、これだとそれぞれの初期化が独立である必要がありますね。
おそらく配列 a と b の初期化で何らか相互に関係するのですよね?
https://wandbox.org/permlink/9cSyhgzxGAGprbN1
もっといい方法がありそうな気がしますが、ぱっと思いつくところでは、 runSTArray https://www.stackage.org/haddock/lts-13.24/array-0.5.3.0/src/Data-Array-ST.html#runSTArray がやっているように、 GHC.Arr.unsafeFreezeSTArray を自前で呼んで runST すればよいのではないかと思います。
hackageにhaddockも生成されてないモジュールの関数なんで大丈夫なのか?という気もしますが...
おっと済みません凡ミスでした...
修正済みです。
このぐらいで再現できますね
{-# LANGUAGE RankNTypes #-}
rankNfunc :: (forall a. Show a => a->b) -> [b]
rankNfunc f = [f 42, f True]

f = length $ rankNfunc $ show  -- OK
g = length . rankNfunc $ show   -- NG
impredicative polymorphismと $ の特別扱いの話は以前記事を書いたので参考までに: https://qiita.com/mod_poppo/items/806c9c3e0ccb46be92ae#%E9%96%A2%E6%95%B0%E9%81%A9%E7%94%A8%E6%BC%94%E7%AE%97%E5%AD%90%E3%81%AE%E7%89%B9%E4%BE%8B
ありがとうございます!案の定読んではてブしてるのに忘れてるw
それにしても {-# LANGUAGE ImpredicativeTypes #-} をつけると g = (length . rankNfunc) show はいけるようになるのに g = length . rankNfunc $ show だとだめなままなのはなんでだろう… ($) の特別扱いが逆に悪さしてるんですかね
ただ、なるべく独立して初期化させた方が行儀のいいコードにはなりそうな気がします。
kakkun61 さんどうもありがとうございます お察しのとうり訳アリで ab の初期化は絡み合っていて 分離は出来ません

@igrep さん 環境設定が悪いのかもしれませんが 出来ませんでした
Not in scope: ‘GHC.Arr.unsafeFreezeSTUArray’
No module named ‘GHC.Arr’ is imported.
import GHC.Arr (unsafeFreezeSTUArray) してください。そういう意味です。
いや、あれ、 ghci のバージョンによって挙動が違う気がしてきました…
手元にあった 8.0.2 だと ImpredicativeTypes で (length . rankNfunc) show が通るけれど 8.4.4 と 8.6.3 では ImpredicativeTypes をつけてもダメっぽい
それはしてあります
参照するときは GHC.Arr. をつけずに unsafeFreezeSTUArray と呼べばいいはずですが...
それにしても @"sample1" ってなんだろうとおもったら、これ、 TypeApplications と DataKinds のコンボですか?
そうです。generic-lensを使っていますので。すみません、言及が漏れてましたね。。。 https://github.com/kcsongor/generic-lens
いえ、脳内が Haskell2010 のままで止まっているので勉強になります^^; (イヤ、下手したら Haskell98 のままで止まってるかも…)
...
import GHC.Arr (unsafeFreezeSTUArray)
...
buildA' = runST $ do
  a <- newArray (0,2) 0 :: ST s (STUArray s Int Int)
  writeArray a 0 999
  -- detail omitted
  a >>= unsafeFreezeSTUArray

これでテストしました