haskell-jp / questions #90

@Izawa has joined the channel
@zaneli has joined the channel
こんな感じの型って既存のパッケージにありますか?
data EList e a = End e | ECons a (EList e a)

リストの末尾に情報を1個付け加えたいのです。
補足すると、こういう形のリストに対して、主に結合演算をしたいです。
(List a, e) の同型ということですか?
だと思いますし、それでいいかな...
と、思ったけど今回の問題に割と固有(でも一般化はできそう?)な気がしたので独自に作っちゃいます。詳しい事情はそのパッケージリリースしたとき書きます。
This message was deleted.
もくもく会中の独り言であれば mokumoku-online にお願いします! :pray:
まっちがえた
@rl-king has joined the channel
Data.List.NonEmpty では
あ,違う型なのか
Kunihiro Ishiguro
@Kunihiro Ishiguro has joined the channel
@小南靖雄 has joined the channel
どのようなプログラムですか?Jsaddleを使っていますか?確かにghcjs の開発は停止しているそうです。GHC8.8, や8.10 はないですね。
@nuoun has joined the channel
ByteString 0.11 では、内部のコンストラクタが PS から BS になり、offset フィールドがなくなります。これに伴い、foreign pointer は、必ずそのByteStringのバッファの先頭を指します。drop なんかで、バッファを共有する場合、foreign pointer がいろんなところを指すようになりますが、この方法でバッファはうまく GC できるんでしょうか?
data ForeignPtr a = ForeignPtr Addr# ForeignPtrContents

の定義を見れば分かる通り、ForeignPtrには既にアドレスと実体を表す値(MutableByteArray#など)の二つが入っています。故にplusForeignPtrなどは安全に定義できます
なるほど! ありがとうございました。
@ has joined the channel
これに関連してずっと気になっていたのですが,
https://haskell-jp.slack.com/archives/C5666B6BB/p1600826197000500?thread_ts=1600821584.000400&cid=C5666B6BB
data Finalizers
  = NoFinalizers
  | CFinalizers (Weak# ())
  | HaskellFinalizers [IO ()]

data ForeignPtrContents
  = PlainForeignPtr !(IORef Finalizers)
  | MallocPtr      (MutableByteArray# RealWorld) !(IORef Finalizers)
  | PlainPtr       (MutableByteArray# RealWorld)

data ForeignPtr a = ForeignPtr Addr# ForeignPtrContents

この定義で,`ForeignPtr` が IORef Finalizers への参照を保持している理由,というか,この Finalizer という名前の由来がよくわからないんですよね……….GCされるときにただ捨てられるものを指して Finalizer とはどういうことなのか.
ただ捨てられる,ってのも変だな.“garbage collector (or compilers) should treat ForeignPtrContents specially” とか書いているのを見たことないので,ふっつーに扱われるんだろうな,と思っている,と言うのが正しい.
最近追加されたコメントによると、ファイナライザの登録時に mkWeak# を使っているのがポイントのようですね https://gitlab.haskell.org/ghc/ghc/-/blob/a1f34d37b47826e86343e368a5c00f1a4b1f2bce/libraries/base/GHC/ForeignPtr.hs#L586
mkWeak#でweak pointerを作ってcapabilityごとに保持しているweak pointerのリストに追加します。GCは参照されていないweak pointerをリストアップしてscheduleFinalizersを呼び出し、リスト中のweak pointerのfinalizerを順次呼ぶという流れだと思います。Cのfinalizerはidle GCでも呼ばれていたような記憶があります。
mkWeak#はrts/PrimOps.cmmのstg_mkWeakzhを、scheduleFinalizersはrts/Weak.cを見ると見つかります。
Finalizer とは、対象オブジェクトを捨てるために呼び出すコードのことですね。
対象オブジェクトが何らかの(メモリ以外の)資源、例えばファイルハンドルを扱うものだった場合、GC でそのオブジェクトが捨てられるときにはファイルを閉じる必要があります。そのような処理をするのが finalizer です。
そのようなものがFinalizerだと思っていたので,たかが IORef に入っている IO () くらいのものをfinalizerと呼ぶのか,とずっと疑問だったのですが,あれユーザランドで勝手に弄る前提のものではなかったのですね! まずそこにびっくりしていました.exportされてるから,てっきり atomicModifyIORef あたりでユーザが勝手に弄って良いものかと・・・.
mkWeak あたりやっと読んできました。 Weak ってFinalizerをつけて作れるんですね。
(というか型の機能が型自体になくて作成時にimplicitに付けるっていうのが面白い発想だなと思いました)
@gen17 has joined the channel
agehara_hiroshi
@agehara_hiroshi has joined the channel
@mds_boy has joined the channel
Toshinori Takahashi
@Toshinori Takahashi has joined the channel
たすけてください༼;´༎ຶ ༎ຶ༽

class MonadIO m => MyClass m a | a -> m where
  foo :: a -> String
  bar :: a -> m ()

というクラスを作ったとき

instance HasLogFunc e => MyClass (RIO e) MyData

とかすると関数従属あるのにeが定まらなくてエラーになってしまいます。
Hasパターンを維持したままこのようなことするにはどうしたらいいですか?
何がしたいのかよく分かってないので、想定解ではないかもしれませんが、単純には MyClass の関数従属消せばいいのではないでしょうか?
外してしまうと foom が現れないので一意に定まらなくなってしまうような
どちらにしてももう少し詳しいモチベーションが知りたいですね。
関数従属性が逆になっているのでは?MonadState s m | m -> sのように、普通はモナドからパラメータを決めるのが典型的な方法です
なるほど、foo の定義が問題なんですね。気づきませんでした。従属逆にしても、foo の定義で引っかかる気がするので、何れにしろこういうインスタンスを作るなら MyClass の従属性と foo の定義がおかしいので見直しが必要な気がしますね

モチベーションは今botを作っていてさまざまなbotの機能を`Bot`クラスのインスタンスで実装しようとしてます。

lass MonadIO io => Bot io b | b -> io where
  name :: b -> String
  reply :: b -> String -> io (Maybe String)

instance HasLogFunc env => Bot (RIO env) MarkovChain

instance HasLogFunc env => Bot (RIO env) Shiritori

こんな雰囲気のかんじです。

なのでモナドが定まってもbが定まってほしくないので関数従属の向きはこのままがいいです༼;´༎ຶ ༎ຶ༽
どうやらデータによってenvに必要な制約が変わりうるというのが要点のようですね。だとすれば、型族を使ってこんな感じに表現できます
{-# LANGUAGE TypeFamilies #-}

import RIO
import Data.Kind
class Bot b where
  type Dep b env :: Constraint
  name :: b -> String
  reply :: Dep b env => b -> String -> RIO env (Maybe String)

data MarkovChain

instance Bot MarkovChain where
  type Dep MarkovChain a = HasLogFunc a

data Shiritori

instance Bot Shiritori where
  type Dep Shiritori a = HasLogFunc a
わあーなるほど
ありがとございます:person_in_lotus_position:
RIOではなくてIOを使う場合のインスタンスも書きたいのですがどうすればいいんですか?༼;´༎ຶ ༎ຶ༽
型族type Run b :: Type → Typeをさらに追加し、type Run Shiritori = IOのようにすることも可能ですが、インスタンスによってメソッドの型が変わると型クラスの旨味がなくなるので、type Dep Foo a = ()のようにしてRIOに統一するのをおすすめします
MonadFailが付いた型を付いてない型に変換する方法はありますか?
何故やりたいのかと言うと、
[Network.AWS.S3.StreamingUpload]()
streamUpload を使いたいのですが、

-- | 自前のYesod環境下を前提としてAwsオペレーションを実行する
runYesodAws :: Yesod App => AWS.AWS a -> HandlerFor App a
runYesodAws x = do
  site@App{appLogger, appAwsEnv} <- getYesod
  -- ログ定義にAppの定義が必要なためApp自身に予め入れることは出来ない
  let awsLogger :: AWS.Logger
      awsLogger level builder
        = messageLoggerSource site appLogger defaultLoc "amazonka" (toYesodLogLevel level) (toLogStr builder)
  runResourceT $ AWS.runAWS (appAwsEnv & AWS.envLogger .~ awsLogger) $ x

-- | amazonkaのログレベルをYesodのログレベルに変換する
toYesodLogLevel :: AWS.LogLevel -> LogLevel
toYesodLogLevel   = LevelInfo
toYesodLogLevel AWS.Error = LevelError
toYesodLogLevel AWS.Debug = LevelDebug
toYesodLogLevel AWS.Trace = LevelOther "Trace"

で変換する先の、
[Yesod.Core.Handler]()
MonadFail のインスタンスを定義していないので動かせなくて困っています。
この関数はそれぞれのハンドラーで動いて例外が発生してもYesodのランタイムによってただのサーバー内部エラーとなるため、
単に fail = error となるだけで良いのですが、
変換する方法が全く分からなくて困っています。

liftIO してIOで実行してHandlerForに移せば良いのではないか?なども考えてみたのですが、
型自体は変わらないので無理でした。

import           Control.Monad.Fail
import           Control.Monad.Trans.AWS        (AWST')

instance MonadFail (AWST' AWS.Env (ResourceT IO)) where
  fail = error

してやればとりあえず動くようなのですが、
孤立インスタンスはなるべく定義したくありません。
汎用的に使われているMonadFailを剥がせないなんて言うことはないと思うので、
私の調べ方が悪いのだと思うのですが、
方法がわかりませんでした…
冷静に考えてみると MonadFail のインスタンスが無くて困ってるのは
AWST' Env (ResourceT IO) の方でしたね
amazonka-s3-streamingの実行ファイル最新のGHCだと動かないんですね…
よく考えてみると剥がせないのが当然な気もしてきた
その場での解決方法はまだ思いつきませんが諸悪の根源は streamUploadEither を返すにもかかわらず MonadFailを要求している点であると思うので、そこはissueとして報告したいですね.... LeftSomeExcpetion があるんだから、そいつが担うこともできるでしょうに。 :cold_sweat:
作者も痛みとして思っているようですね…
とりあえずは孤立インスタンスとして凌ぐことにしようと思います