<p dir="ltr">Hey Victor,</p>
<p dir="ltr">If you're not actually the Monad instance of IO,<br>
then `andThen` is (*>) for `Compose RowParser IO a` (<a href="https://hackage.haskell.org/package/base-4.10.0.0/docs/Data-Functor-Compose.html">https://hackage.haskell.org/package/base-4.10.0.0/docs/Data-Functor-Compose.html</a>).</p>
<p dir="ltr">So `rowPrinter` would be</p>
<p dir="ltr">rowPrinter =<br>
getCompose $<br>
Compose (printP1 <$> field) *><br>
Compose (printP2 <$> field) *><br>
...<br>
Compose (printPn <$> field)</p>
<p dir="ltr">It's a bit more verbose, but I think it's the best answer.</p>
<br><div class="gmail_quote"><div dir="ltr">On Thu, 28 Sep. 2017, 6:54 pm Viktor Dukhovni, <<a href="mailto:ietf-dane@dukhovni.org">ietf-dane@dukhovni.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><br>
When generating a report file from a database I found it much more<br>
efficient (significantly shorter runtime) to represent each row<br>
by an I/O action that prints the row, rather than to construct a<br>
Row object that to print and throw away.<br>
<br>
But the naive way to construct the I/O action can be tedious to<br>
maintain once the column count gets appreciably high:<br>
<br>
newtype Foo = Foo { _foo :: IO () }<br>
instance FromRow Foo where<br>
fromRow = Foo <$> (rowPrinter <$> field <*> field <*> field <*> ... <*> field)<br>
where<br>
rowPrinter :: Type1 -> Type2 -> Type3 -> ... -> TypeN -> IO ()<br>
rowPrinter p1 p2 p3 ... pN = do<br>
printP1<br>
printP2<br>
printP3<br>
...<br>
printPN<br>
<br>
So I decided to applicatively decompose the rowPrinter function<br>
(with the actual name of "andthen" to be determined later) as:<br>
<br>
rowPrinter = (printP1 <$> field) `andthen`<br>
(printP2 <$> field) `andthen`<br>
(printP3 <$> field) `andthen`<br>
...<br>
(printPN <$> field)<br>
<br>
which avoids the need to package the column printers explicitly into<br>
a single function, and may be somewhat more efficient a well.<br>
<br>
What was not immediately obvious to me was whether there's an "off the<br>
shelf" implementation of "andthen" I could just reuse. The necessary<br>
operator satisfies:<br>
<br>
andthen (f (m a)) (f (m b)) = f (ma >> mb)<br>
<br>
or, equivalently:<br>
<br>
a `andthen` b = (>>) <$> a <*> b<br>
<br>
for which <a href="http://pointree.io" rel="noreferrer" target="_blank">http://pointree.io</a> dutifully gives me:<br>
<br>
andthen = (<*>) . ((>>) <$>)<br>
<br>
Its type signature is:<br>
<br>
Prelude> :set prompt "l> "<br>
l> :m + Control.Applicative<br>
l> :m + Control.Monad<br>
l> :t ((<*>) . ((>>) <$>))<br>
((<*>) . ((>>) <$>))<br>
:: (Monad m, Applicative f) => f (m a) -> f (m b) -> f (m b)<br>
l><br>
<br>
It seems to me that this would have been done before, and the operator<br>
would already be present in some package, but I'm having trouble finding<br>
it.<br>
<br>
(Due to the hidden constructors of FromRow defining a Semigroup does not<br>
work out here, so I can't use (<>), which also inconveniently conflicts<br>
with Monoid (<>)).<br>
<br>
So my question is whether the operator in question is already available,<br>
under some name in some package, or else suggested names for it if new.<br>
<br>
--<br>
Viktor.<br>
<br>
_______________________________________________<br>
Haskell-Cafe mailing list<br>
To (un)subscribe, modify options or view archives go to:<br>
<a href="http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe" rel="noreferrer" target="_blank">http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe</a><br>
Only members subscribed via the mailman list are allowed to post.</blockquote></div>