haskell-jp / questions #71

ぽんちゃん
出先でしたのでご返信遅れてしまいすいません。

動作確認できました!
お手伝いいただいたみなさまありがとうございました!!

これからの拡張はどこを参考にしたらよいでしょうか…?
一応 https://github.com/mpickering/slack-api/tree/master/example にいくつかサンプルが載ってるみたいですね
あとはどこまで書かれているか分かりませんのでexampleの方が確実そうですが、exampleでわからなければslack-apiのドキュメントを読め、ってところですね…。
残念ながらhackageにまだ公開されていないバージョンなので、slack-apiのリポジトリーをgit cloneしてcdして、
stack haddock --open
と実行すれば、ビルド実行後にドキュメントが開かれます
--open 知らなかった
3.0のリリースノートによるとデフォルトはnew-**に変更済みとの事なので、上記発言の文言を断定形に直しました
cabal replをしてもグローバルstoreには入らないはずなので、多分C-cC-lでcabalのstoreを参照するか、cabal replするようになってるんじゃないですかね
Hackageにあるライブラリのコードを一部借用するときに、そのライブラリがBSD-3ライセンスの場合にはライセンス表記はどうすればいいのでしょうか。


http://hackage.haskell.org/package/template-0.2.0.10
チーム内の話し合いでData.Text.Templateを使おうって話があったんですが、一部のコードが自分たちのニーズに合わないのでその部分だけ改変して使用しようと決めました。この場合PRを送るのが一番なのでしょうが、残念ながらこのライブラリは9年前のもので、作者も消息不明だそうです(同僚の知り合いらしい)。
よって、利用するコードがごく一部(200行ほど)なので、そこだけを借用しようという話になりました。
問題はそのライブラリがBSD-3ライセンスなので、その表記をどうすればいいのかよくわからないという点です。個人的には借用したプロジェクト内にライセンス表記を記載したMarkdownファイルを添加?しておくのがいいのかなーと考えていますがいかがでしょうか。
http://hackage.haskell.org/package/template-0.2.0.10/src/LICENSE
@mkasa has joined the channel
常識的に読めるように元のライセンス原文をパッケージに含めておけばいい気がします
(個人の意見で責任は云々
なるほど!ありがとうございます。
僕もあまりライセンス系統は自信ないですが,

• ソースコードの再配布やコンパイルしたバイナリの配布などをしないなら特に記載なくて問題ないはずです.例えば Web サイトのバックエンドに使うなどはライセンス表記はなくて問題なくて,ゲームアプリなどユーザにインストールしてもらうもので使う場合,ライセンス表記を含める必要があります. (ただし, AGPL などはその限りではないです)
• オープンソースの場合,使ったライブラリが cabal ファイルなどから辿れるのでライセンスが分かるとして,特別な表記をしなくて問題ないという暗黙的な合意があります (ちゃんとライセンスをまとめたものを用意しておくのが親切ですが)

今回の場合どういう配布形態になるのか分からないですが,バイナリ形式 (アプリ配布など) での配布を検討されているなら, BSD3 の条文にあるように,そのアプリのドキュメントまたは何かライセンス表記用の特別なファイルにこのライセンス全文を表示するスペースを用意しておけば問題ないはずです (どこの部分にそれを使ったかを明記しておくとより親切ですが)
@西山寛之 has joined the channel
ページネーションを実装するためにEsqueletoでテーブルの検索結果件数を所得しようとしていますが、countRowsの値が所得できません。

このページを参考にしながら作っています。
https://ersocon.net/blog/2016/10/10/pagination-in-yesod-from-naive-to-monads

StackOverflowからselectCount関数を取ってきたと言っているので調べて以下の記事を見つけました。
https://codeday.me/jp/qa/20190405/557765.html

ここで手に負えないエラーが出てきたので助けて頂きたいです。
どのように修正したらcountRowsの値を所得できますか?
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
import Control.Monad.IO.Class (MonadIO, liftIO)
import Control.Monad.Logger (runNoLoggingT)
import Database.Persist
import Database.Persist.Sqlite
import 
import qualified Database.Esqueleto as E

share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase|
  Person
    name String
    age  Int Maybe
    deriving Eq Show
|]

main :: IO ()
main = runNoLoggingT . withSqlitePool ":memory:" 10 . runSqlPool $ do
  runMigration migrateAll

  insert $ Person "John"  (Just 18)
  insert $ Person "Peter" (Just 20)
  insert $ Person "Mary"  (Just 30)
  insert $ Person "Jane"  (Just 14)

  selectCount
  selectCount' (\p -> do
                  E.where_ (p E.^. PersonName E.==. E.val "John")
                  return p
               )

selectCount :: MonadIO m => SqlPersistT m ()
selectCount = do
  cnt <- E.select $ E.from $
    (\(_ :: E.SqlExpr (Entity Person)) -> return (E.countRows :: E.SqlExpr (E.Value Int)))
  liftIO $ print cnt

selectCount' :: (E.From a, MonadIO m) => (a -> E.SqlQuery b) -> SqlPersistT m ()
selectCount' q = do
  cnt <- E.select $ E.from $
    (\x -> q x >> return (E.countRows :: E.SqlExpr (E.Value Int)))
  liftIO $ print cnt


上記のコードでそれっぽく動きました。

λ stack repl Es.hs --resolver lts-14.5 --package persistent-sqlite --package esqueleto --package persistent --package persistent-template --package monad-logger

*Main> main
Migrating: CREATE TABLE "person"("id" INTEGER PRIMARY KEY,"name" VARCHAR NOT NULL,"age" INTEGER NULL)
[Value {unValue = 4}]
[Value {unValue = 1}]


esqueleto のことはあまり知らないのでアドバイスしづらいですが、 E.countRows の型を明示的に書いてあげると動きました。
parseTest    
((between (optional $ single ' ') (optional $ single ' ')
   (single 'a' `sepBy` single ' ')) <* eof :: Parsec Void Text [Char]) $ pack "a a "


1:6:
  |
1 |  a a 
  |      ^
unexpected end of input
expecting 'a'

と失敗するのは何故ですか?
sepBy (single ' ') が空白を先に受理して、空白のあとは 'a' が来ないと行けないからじゃない?
どうすれば解決できますか?`sepEndBy`を使う?
少なくとも sepEndBy でパースはできそう(それが意図してる動作なのかは怪しいけど)
どんどこすすむ
@どんどこすすむ has joined the channel
@wataash has joined the channel
ありがとうございます。以下のようにしたら無事コンパイルが通るコードになりました。
selectCount :: (MonadIO m, E.From a) => (a -> E.SqlQuery b) -> SqlPersistT m [E.Value Int]
selectCount q = E.select $ E.from $ (\x -> q x >> return (E.countRows :: E.SqlExpr (E.Value Int))) 
@firn has joined the channel
@おかだ has joined the channel
magaparsecでパーサの中でparseを使うのはおそらく邪道なんだと思うんですが、どうやって同じ効果を得るパーサを書けば良いんですか?(betweenパーサがうまく動かないので先に挟まれた文字列を取ってきてから内側のパーサを走らせようとしている)
今はこんな感じ(これはfailureのとこで型が合わないので駄目)
いやこれ要る?
ああ、 `between parser0 parser1 $ takeWhileP Nothing (const True)`みたいなものでも動いてほしかったのか?
何がしたいのかはよく分かってないですが,エラーメッセージがちょっとおかしくなるかもしれないのを許容すれば,早期消費型の between はこんな感じでできそうです
@tangible.bits has joined the channel
@ has joined the channel
hackageに間違えてビルドが通らないパッケージを上げてしまった場合に、該当のバージョンを削除するなど、何かとれる対応はありますか?(やってしまった :cold_sweat:
:thinking_face: ... と、思いきや直ちに修正して新しいバージョンをアップロードしたせいか、ビルドできないバージョンはアップロードされなかった?
もしアップロードしてしまっても、` versionを設定すればcabalから選ばれなくなるはずです
ありがとうございます!やっぱりビルドできないバージョンをアップロードしていたのでdeprecateしておきました!
すごいHaskellあたりを読み終えたあと次に読みながら手を動かすのによい本を聞かれたんですが、何かあるでしょうか?
とりあえず古いところに注意しながらRealworld Haskellあたりがいいんじゃないと言いましたが……
『Haskell 入門』の後半いいと思います
意見が被りますが
全然入門者向けじゃないと一部で評判の「Haskell入門」
https://www.amazon.co.jp/dp/4774192376
か、ちょっと難しいけど独特な知識が得られる並行並列本で!
https://www.oreilly.co.jp/books/9784873116891/
なるほど、自分でも買ってちょっと読んでみます
(スレッドにし忘れたな
並列並行はよい本ですが流石に次に勧めるのはためらわれますね……
いろいろ雑多ですが https://wiki.haskell.jp/Links に書いてある個別の記事をちょっとずつ覗いてみるのもいいかもしれません。

あと、毎度手前味噌ですがHaskell入門書を終えた人向け全般のコンテンツとして https://wiki.haskell.jp/Hikers%20Guide%20to%20Haskell を勧めておきます。
Fun of Programming とか(あがってないやつだと)
https://twitter.com/coord_e/status/1177861179965767680 こちらのスレッドでしゃべっていて気になったんですが、
class MyEq a where
  eq :: a -> a -> Bool

instance MyEq Integer where
  eq = (==)

というEq型クラスと等価な型クラスとそのインスタンスがあったとして、
main = print $ eq 1 2Ambiguous type variable になるのに
main = print $ 1 == 2Ambiguous type variable にならないのはなぜでしょうか。
Num 型クラスのデフォルトである Integer が選ばれた、まではわかるのですが、なぜ Eq 型クラスの場合のみデフォルトが採用されたのでしょうか?
Haskell の仕様として、 context に現れるのが全て標準の型クラスでないと defaulting は適用されないという制約があるからですね
https://www.haskell.org/onlinereport/haskell2010/haskellch4.html#x10-790004.3.4
ghci の中では eq 1 2 は False になりますね.
GHCi 上では ExtendedDefaultRules が有効になるので、その場合標準のではない場合にも defaulting が行われます
ですね.
@ has joined the channel
@ has joined the channel