haskell-jp / questions #19

ありがとうございます。
私の質問が言葉足らずでしたが、
パーサーを使う程でもない、10数行程度の入門レベルのコンソールアプリのサンプルを作る際に、
毎回(pack . show)と(read . unpack)で行数がやや膨らむので悩んだところでした。

特に定番的なものがなければ、入門レベルならむしろその方が、追加のライブラリも不要ですし、
対称的で見栄えも良い、という感じでも問題は無いでしょうか?
いいと思います。
個人的には、入門程度のアプリケーションであれば、そもそもTextを使うまでもないかと思います(Textの勉強をしている場合は別ですが。。。)
textはデファクトみたいなもので、
早いうちから慣れておいた方が後々楽かなぁという思いでした。

自分のやり方があっているのかが不安でしたが、
Haskellベテランの方のご意見をお伺い出来て安心しました。
ありがとうございました!
BuilderとLazy版Textを通るのでかなり遠回りですが、 というモジュールもあります
ご紹介ありがとうございます!

実は、これにも疑問があったのですが、Lazy版しか提供されていないのは
何か理由があるのでしょうか?
ストリームから読み込む際に、変換可能なバイト列が揃うまで評価を待ちたいから、
みたいな事情でしょうか?

更に質問で恐縮ですが、よろしくお願いします。
私もなぜ正格なBuilderを提供しないのか、実はよくわかっていません。標準のBuilderは特別効率がよいとは言えないです…
正格版があったほうがパフォーマンス的に有難い気もするのですが、
パフォーマンス気にするならそもそもBuilder以外の方法を使いましょう、
みたいな方針なのですかね…

ご回答ありがとうございました
多分大きな文字列を組み立てる前提だから、正格に結合するとメモリー消費量がすごく大きくなってしまうという想定でやってるんじゃないっすかね。
扱う文字列の大きさが、(Lazyな)Builderを使うかの判断基準にはなりそうですね
ありがとうございます!
HDBC-mysqlで、ブロックが発生するクエリを実行した際に、他のスレッドが停止してしまい困っています。
対処方法などご存知の方いたら教えて下さい。
(HDBCというより、ffiで一般的な話な気もしますが、調べてもわからず、、)
module Main where

import Control.Monad
import Database.HDBC
import Database.HDBC.MySQL
import Control.Concurrent

main = do
  forkIO $ do  -- quickQuery'でブロックが発生した時点で処理がとまる
    forM_ [0..10] $ \i -> do
      print i
      threadDelay $ 1000*1000
  conn <- connectMySQL defaultMySQLConnectInfo {  } 
  withTransaction conn $ \c -> do
    quickQuery' c "select * from hoge where id = 1 for update" [] -- 別途ロックしてから実行
  threadDelay $ 10000*1000


ghc-options:         -threaded -rtsopts -with-rtsopts=-N -eventlog
ブロックする可能性のある関数をunsafe ffiで呼び出しているのが原因だと思います。ライブラリ側でsafe ffiに直すか別のパッケージを使う以外方法はないと思います。
mysqlパッケージの話ですが、基本的に同じなのでここを読むとわかりやすいかと思います。
https://ro-che.info/articles/2015-04-17-safe-concurrent-mysql-haskell
ベンチを取ってないので断言はできませんが、入力が短ければtoLazyTextによって作られるlazy textもsingletonになってtoStrictもコピーしないのでそれほど非効率にならないのではないかと思いました。
リプライありがとうございます。
Builderがちょっとしたアプリでも使えそうな感じですが、
一般的にもBuilferは良く使われるものなのでしょうか?
Lazyに変換するのをサボりたくなって、簡単な文字列変換なら、つい敬遠してshowとappendで済ませてしまいます…
ケースバイケースじゃないかと思います。時間、空間効率に問題がなければimportも少なくて済むpack.showが楽でしょうし、効率も気になるならBuilderが良いのではないかと思います。Stringは非常に富豪的なデータ構造なので、それが問題になるかを考えれば自ずと決まるのではないかと。
皆様のお話でBuilderという選択肢が得られて勉強になりました。
いろいろなご意見ありがとうございました!
HLearnはたしかsubhaskと併せて野心的なプロジェクトだったんですが、作者が自分の考える最高のコードを書くには、まだGHCが機能不足だという結論にいたって開発が止まったという話だった気がします。
結局今はPythonを使ってるとredditかどこかで見かけた気がします
http://www.datahaskell.org/docs//community/current-environment.html#machine-learning dataHaskellというコミュニティがライブラリの情報をまとめています
ありがとうございます
@Cosmia has joined the channel
高いですねw
@maoe ありがとうございます!
原因と対応方法まで理解できました。
大変抽象的な聞き方で申し訳ないのですが。ソースコードを入力にコード規約のような複数のチェックを実施して、その結果を全て返すというような処理を書くとき、haskellの場合どのような書き方をするのが王道なのでしょう。
まだ詳しく調べ切れてないのですが、heterogeneous listの実装ってなにがおすすめですか?
いまいち何が懸念なのかわかりませんが、
その要件だけ聞いてざっくり設計するなら:point_down: な型の関数を書きますかね。。。
type SourceCode = Text

data AST = {- ソースコードのASTを表す型 -}

data AnalysisResult = {- ... 解析結果を表す型 -}

parse :: FilePath -> SourceCode -> AST

analyze :: AST -> [AnalysisResult]
すみません。具体的な懸念があるということではなく純粋にどういう形になるのが一般的なのかと思いまして。

いただいた例ではテキストを抽象構文木に変換したのちに解析して最終的に解析結果のリストを返すということですね。いまひとつ具体的なイメージがわかないのはanalyze関数の部分です。チェックの内容にもよると思うのですが、複数のチェックを実施する場合、チェックの都度ASTを頭から舐めなおすことになるのかなと。

単純化するためにチェックの内容を特定のインストラクションが含まれているとして、”A"がある・”B"がある・”C"があるの3つのチェックをする場合、ASTに"A"が含まれるか→結果を結果リストに追加→ASTに”B"が・・・→結果リストを戻すというような実装になるのか、それともASTを頭から葉まで一回舐めていくうちに結果を貯めていくような方法とするのか、それらを混在させるのか。
毎回舐めなおすのはどんなチェックにも対応できそうですが効率が悪いですし、一方舐めるのを一回で済ませようとしても必ずバックトラックが必要なタイプのチェックもあるように思いますし。
単にOK・NGを返す、もしくは最初にエラーとなった内容を返すだけなら個々のチェックを実施するパーサを連結すればできそうだなというイメージはあるのですが、全てを返す方法がイメージできていません。
「単一の入力に対して複数のチェックを実施して、その結果を全て返却する」というような処理は私の仕事では頻出のパターンでして、比較的一般的な処理だと思いましたので、良く知られたオーソドックスな方法があるのかも?と思った次第です。全体的に分かりにくくて申し訳ありません。
もちろん一般論としてなるべくバックトラックが少ない方が効率的なのは間違いないでしょうし、その辺はやってみないとなんとも。。。という感じです。幸いhlintをはじめその手のHaskell製ツールはたくさんOSSで存在するので、読んでみるといいかもしれません。
ぱっと思いつくのは、Haskellのソースコードで言えば、「module単位で行うチェック」、「関数単位で行うチェック」、「型宣言に対して行うチェック」、「式に対して行うチェック」みたいにあらかじめ分類しておいた上で、各単位の頭から都度処理する、みたいなやり方ですかねぇ。

式単位だと当然入れ子になる式が出てくるでしょうから、お話はまだ複雑になりますけども。
コマンドライン引数のオプションの解析、自分で書いたことはありますが「車輪の再発明やめよう」ということでライブラリを使おうと思い調べてみたところ、かなり候補が出てきたのですが、オススメとか避けるべきとかってありますかね
https://wiki.haskell.org/Command_line_option_parsers
ほかとの比較はしたことないですが、optparse-applicativeはよく使われているイメージです。
自分も最近は optparse-applicative をよく使ってます。 ただ、これが理想かというとう~ん……
extensible以外のものをお探しでしょうか?
そうですね、extensibleも(もちろんいにしえのHListも)含めて見てみます。
この際なのでついでにfumiさんに伺いたいのですが、OverloadedLabelsをextensibleに応用した、
https://hackage.haskell.org/package/extensible-0.4.8/docs/Data-Extensible-Label.html
を使った場合、どんな使用方法になるのでしょうか?
もしかして、
https://www.schoolofhaskell.com/user/fumieval/extensible/extensible-records

mkField "name collective cry"

の箇所がなくなって
dove :: Animal
dove = #name @= "dove"
  <: #collective @= "dule"
  <: #cry @= Just "coo"
  <: Nil

みたいに書けるイメージですかね。
はい、従来はTemplate Haskellで生成したものをラベル記法にそのまま置き換えることができます
リストにないですが tanakh さんの optparse-declarative はそこそこ楽できた覚えがあります
選択肢を増やすようで申し訳ないですが、optparse-applicativeに対抗されて作られたalternativeです。
上記のwikiにも載っていません。
https://github.com/lspitzner/butcher
stack new でテンプレートを指定しなかったときデフォルトで使われるファイルを new-template 以外のカスタムテンプレートを使うように簡便に指定できないものでしょうか.
globalのconfig.yamlでdefault-templateを指定すればできるはずです
https://docs.haskellstack.org/en/latest/yaml_configuration/#default-template
できました.ありがとうございます:pray:
package.yaml or cabalで,stack testを実行した時に特定のプリプロセッサフラグを有効にする方法は無いでしょうか?
DEVELOPMENTフラグを有効化してテスト時のみYesod.Auth.Dummyを読み込ませたいのですが…
一々stack test --flag application:devとタイプするしか無いのでしょうか
サンプルを見るとtest以下にcpp-options: -DDEVELOPMENTと書けば良いように見えたのですが,どうもそうではないっぽい
-Dオプションはパッケージ単位でしか効かなかった気がします(未確認)
https://github.com/haskell/cabal/issues/2821 これが使えれば、テストスイートからだけフラグを有効にする、という事が可能かと思われますが、採用されるか分からない感じですね
なるほど、 cabal の flag はソースコード中でそのようにして参照できるのですね。
やってみます!
ああなるほどそれが議論されているということは普通では無理ということでしょうね
外部パッケージのためだけかと思ってました
yesod界隈では{fast,monad}-loggerが使われていますが、一般的にロガーを自分で選択するときは何を使っていますか?