<div dir="ltr">This is a bit of a tangent, but one can use the <a href="http://hackage.haskell.org/package/foldl-1.2.1/docs/Control-Foldl.html#v:FoldM">FoldM</a> type from the <a href="http://hackage.haskell.org/package/foldl">foldl </a>package to build composable logger-like things that perform effects.<div><br></div><div>The semigroupoids package contains the <a href="http://hackage.haskell.org/package/semigroupoids-5.0.1/docs/Data-Functor-Extend.html#t:Extend">Extend</a> typeclass, which is basically "Comonad without extract". If we make FoldM an instance of Extend, we can "single-step" a FoldM with the function:</div><div><br></div><div>     import Data.Functor.Extend (<a href="http://hackage.haskell.org/package/semigroupoids-5.0.1/docs/Data-Functor-Extend.html#v:duplicated">duplicated</a>)<br></div><div>     import qualified Control.Foldl as L</div><div><br></div><div>     singleStep :: i -> L.FoldM IO i r -> IO (L.FoldM IO i r)</div><div>     singleStep i :: flip L.foldM [i] . duplicated<br><br>Which is basically a logging function.</div><div><br></div><div>Also, since FoldM is an instance of Applicative, you can combine a list of loggers using <a href="http://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Foldable.html#v:sequenceA_">sequenceA_</a>.</div><div><br></div><div>Another way to define a logger type would be with <a href="http://hackage.haskell.org/package/free-4.12.4/docs/Control-Comonad-Cofree.html">Cofree </a>from the free package. Something like:</div><div><br></div><div>     type Logger = Cofree ((->) String) (IO ()) </div><div><br></div><div>Which would also be an Applicative. One could then define stateful loggers using Cofree's <a href="http://One then could define loggers using unfold. ">unfold</a>.</div><div><br></div><div>I think the Cofree version has the advantage that you can be sure the logger's state only depends on the messages it receives (even as it emits IO actions on each step). The FoldM version, meanwhile, could perform some devious IO action to update its state.</div><div><br>On Saturday, June 4, 2016 at 3:24:57 PM UTC+2, martin wrote:<blockquote class="gmail_quote" style="margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">Hello all,
<br>
<br>I find myself frequentlly writing types like this
<br>
<br>data Logger a l = Lgr {
<br>  runLogger :: a -> Log l -> (Log l, Logger a l)
<br>  }
<br>
<br>The purpose is to give a logger a chance to carry an internal state. It could e.g. choose to log only every n
<br>invocations. To do this it must keep track of how many times it has been called. I want to leave such things private to
<br>the Logger.
<br>
<br>
<br>(1) I know that this is not an unusal thing to do, but it has an OO feel to it. Is there a more functional alternative
<br>to it. Should I just not worry?
<br>
<br>(2) I can write a combinator which creates a Logger from a list of Loggers. Since each Logger potentially returns a new
<br>version of itself, I must always re-assemble the combined logger from all the returned new versions. I am worried that
<br>this is a costly operation, particularly when most Loggers just return themselves unaltered. I don't have any hard
<br>numbers about the performance penalty though.
<br>
<br>These Loggers are used in a discrete-event-simulation and they will get called many times (once for each event), but
<br>only occastionally actually write to the Log.
<br>______________________________<wbr>_________________
<br>Haskell-Cafe mailing list
<br><a href="javascript:" target="_blank" gdf-obfuscated-mailto="AaA3yoFJBAAJ" rel="nofollow" onmousedown="this.href='javascript:';return true;" onclick="this.href='javascript:';return true;">Haskel...@haskell.org</a>
<br><a href="http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe" target="_blank" rel="nofollow" onmousedown="this.href='http://www.google.com/url?q\x3dhttp%3A%2F%2Fmail.haskell.org%2Fcgi-bin%2Fmailman%2Flistinfo%2Fhaskell-cafe\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNH7sFgl7KfuDcDlaGGG3ip3kRaoIA';return true;" onclick="this.href='http://www.google.com/url?q\x3dhttp%3A%2F%2Fmail.haskell.org%2Fcgi-bin%2Fmailman%2Flistinfo%2Fhaskell-cafe\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNH7sFgl7KfuDcDlaGGG3ip3kRaoIA';return true;">http://mail.haskell.org/cgi-<wbr>bin/mailman/listinfo/haskell-<wbr>cafe</a>
<br></blockquote></div></div>