Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
Andi Miller
@andimiller
and it does technically work
Nick Telford
@nicktelford
my issue is that, once I have a Service[ConnectionIO], I need some way to lift that to IO so that http4s can work with it
which is what I was trying to do - but I feel like I was doing it in a really roundabout way!
Rob Norris
@tpolecat
But composing them and then translating to your target monad F (given a Transactor[F]) isn't just a transparent translation. It defines transaction boundaries.
Nick Telford
@nicktelford
that's ok in this case, as each method on my Service layer is expected to be a transaction
Rob Norris
@tpolecat
So I recommend distinct layers because they have distinct semantics and in the general case won't line up 1:1
Ok.
Nick Telford
@nicktelford
though I am curious about the general case
Rob Norris
@tpolecat
Well in that case yeah you can mapK with transact and get a new service thing in IO or whatever.
But in the general case that's too constrained. If you ever want to do two things in a transaction you're out of luck.
Ryan Zeigler
@rzeigler
That allows some of your services to depend on others while still allowing tranasction blocks correct?
ergo, ServiceB[ConnectionIO](sa: ServiceA[ConnectionIO])
Luka Jacobowitz
@LukaJCB
Folks, care to comment on this issue? :) non/kind-projector#84
Nick Telford
@nicktelford
so the reason for my derived implicit def from above is that I have a bunch of different algebras, and I didn't want to have to write Alg[ConnectionIO].mapK(xa.trans) 10 times - I was simply trying to have it auto-derive it - but perhaps that's just not a good idea
I must admit, while I've been learning the pure-FP side of Scala, the most difficult thing by far is idioms around program structure, mostly because there seems to be very little literature around it
Rob Norris
@tpolecat
Yeah Someone™ needs to give a talk on how to write programs using cats.
Nick Telford
@nicktelford
I would watch the hell out of that! :D
Rob Norris
@tpolecat
This is a small program that uses a pattern that's working well for me. tl;dr tagless interfaces are always traits and F is always unconstrained. Implementations are anonymous, often on companions, and are constrained as necessary. https://github.com/tpolecat/mosaic-server
Nick Telford
@nicktelford
@tpolecat thanks
Rob Norris
@tpolecat
I'm doing the same thing with https://github.com/tpolecat/skunk and it kind of writes itself. Seems like a good pattern.
You might also look at @LukaJCB's talk from SBTB
Fabio Labella
@SystemFw

, the most difficult thing by far is idioms around program structure

tbh that's the most difficult thing in general, because imho there is no one-size fits all approach, in any tech (and the tech that force one on you like Elm end up very limiting). I do agree we need to do a better job popularising things that do work, but it's a bit hard to discuss application structure in any way other than working together on it

fwiw, I use roughly the same pattern @tpolecat mentions
Nick Telford
@nicktelford
Rob Norris
@tpolecat
Yes, that's the one.
Nick Telford
@nicktelford
Thank you both, you've given me a fair bit to think about. I think one of the key differences is that you're assembling your algebra explicitly, rather than implicitly, which doesn't put you at the mercy of Scala's implicit search and type inference quirks. That seems sensible!
Jakub Kozłowski
@kubukoz
@nicktelford also check out splain
Fabio Labella
@SystemFw

@nicktelford

I think one of the key differences is that you're assembling your algebra explicitly, rather than implicitly,

What I do is passing algebras implicitly, like F[_]: MyThing, but having explicit constructors in the companion object, and then using implicit call sites, basically

constructor.flatMap { implicit alg =>
  thingThatWantsImplicitAlg
}
this gives me low boilerplate but no implicit weirdness
especially because in current scala if you nest two of those with the same type you get a compile error (which is what you want)
the only thing you need to remember is to make things implicit as close as possible to their call site, which isn't that big of a rule in terms of practical pain (almost none)
Jakub Kozłowski
@kubukoz
generally implicit auto-derivation of algebras becomes really painful for testing as soon as you stub anything
Rob Norris
@tpolecat
There's some subtlety to this that probably deserves a blog post.
Jakub Kozłowski
@kubukoz
Someone™ should write one
Luka Jacobowitz
@LukaJCB
I gotta say I'm a huge fan of
Someone™ , they seem to be doing a ton of work
Long Cao
@longcao
Jakub Kozłowski
@kubukoz
I was about to say something about being ashamed of giving Someone so much to work on
Ryan Zeigler
@rzeigler
Well, the rewards of a job well done and all that
Ryan Zeigler
@rzeigler
so, simpler question, what is the proper name of the >> syntax?
like, *> is to productR
Rob Norris
@tpolecat
Not really simpler, the original names were *> and >>.
People kept asking us to make up a non-symbolic name so we invented productR
Oleg Pyzhcov
@oleg-py
Which is even worse :D
Rob Norris
@tpolecat
:-)
Christopher Davenport
@ChristopherDavenport
Refer to *> and >>. Just easier. I use applicative discard and monadic discard when I’m discussing and people don’t know the symbol.
Ryan Zeigler
@rzeigler
I didn't know if there was a named version at all. *> documentation references produceR, but >> just says its equivalent to flatMap(_ =>
Ryan Zeigler
@rzeigler
for the record, I don't think productR is particularly confusing
maybe I'm weird
Rob Norris
@tpolecat
It's not confusing, just not well know. Everyone who has been doing this for a while will know *> but few would recognize productR.
Ryan Zeigler
@rzeigler
I guess that's fair. When I found that <*> was product, the reason productR is the name for *> made perfect sense