These are chat archives for typelevel/cats

7th
Dec 2017
Jeremy Lyman
@maarek
Dec 07 2017 03:05
What do you use when you want to map over Some(value)? Option seems a little awkward because there could never be None. Can you have a Functor(value)?
I suppose Monad(v) for larger constructions with flatMap. For example this statement { val r = i % 2; if (r == i) 0 else i }. Could be Some(i%2).map(r => if (r == i) 0 else i)
Christopher Davenport
@ChristopherDavenport
Dec 07 2017 03:08
Why do you have some(value)
That is equivalent to I'd.
Id
Jeremy Lyman
@maarek
Dec 07 2017 03:10
How does Id work? :P
Rob Norris
@tpolecat
Dec 07 2017 03:10
You can use Id but map is equivalent to just applying the function. There’s the thrush operator |> defined in mouse that lets you say a |> func which may be closer to what you’re looking for.
Jeremy Lyman
@maarek
Dec 07 2017 03:13
I'm not understanding where Id is defined :P
Is it bad that I want to not have code that looks like this .map(v => { val a = i + 1; val b = i + 2; val c = i + 3; if (i == a) i else b }). So I figured if I could map / flatMap over the vals then it'd be great. Knowing that I have some value, I wasn't sure if Option was most minimal type for this. I hope that makes sense.
Rob Norris
@tpolecat
Dec 07 2017 03:23
blah.map { v =>
  val a = i + 1
  val b = i + 2
  val c = i + 3
  if (i == a) i else b
}
nothing wrong with that
intermediate bindings are totally fine
Note the use of braces there, which makes it a bit nicer than what you had.
Jeremy Lyman
@maarek
Dec 07 2017 03:27
Yeah. I guess. :P You get some functions that are so nicely composed def foo = for { } yield, def bar = if else, def baz = opt.map . Then you get those others that are def qux = { val val val val work }
Christopher Davenport
@ChristopherDavenport
Dec 07 2017 03:28
Well you can make smaller functions and compose. But is often far more work then a few bindings.
Jeremy Lyman
@maarek
Dec 07 2017 03:29
  def distribute: Vector[Int] => Vector[Int] = (v: Vector[Int]) => (for {
      max <- Option(v.max)
      index <- Option(v.indexOf(max))
      rotV <- Option(rotate(index)(v))
      compV <- Option(updateHead(rotV) ++ updateTail(rotV, max))
    } yield rotate(v.size - index)(compV))
    .getOrElse(Vector.empty[Int])
This is what happens when I try to make everything an Option
Christopher Davenport
@ChristopherDavenport
Dec 07 2017 03:31
I don't think that's a great choice personally if you are using safe methods.
Jeremy Lyman
@maarek
Dec 07 2017 03:31
I didn't really like it either.
Cory Parent
@goedelsoup
Dec 07 2017 03:39
Which version of cats? I've learned my lesson here but it's a little easier to fix in cats 1 imo.
Jeremy Lyman
@maarek
Dec 07 2017 03:43
@goedelsoup Me?
Cory Parent
@goedelsoup
Dec 07 2017 03:44
What I've learned is: have layers return predictable and expected monads, up a layer compose those together if needed and at the top crush and execute. Step B can be multiphasic but if you get all of the step As in line it's easier. Above all, avoid monad transformers until you need them.
@maarek yes
Jeremy Lyman
@maarek
Dec 07 2017 03:45
Yeah I am using RC1
Cory Parent
@goedelsoup
Dec 07 2017 03:47
In that case, my advice is that if you're expressing core logic, ensure it's implemented in something that maturally utilizes ApplicativeError/MonadError.
Def upront cost to write pure. I'm saying...the alternative doesnt lead anywhere great.
Most of our bugs exist in comfortable patterns
Jeremy Lyman
@maarek
Dec 07 2017 03:52
I'll keep that in mind. :)
Cory Parent
@goedelsoup
Dec 07 2017 03:53
I see you're using stdlib for the start of the comprehension and letting it influence the rest
Jeremy Lyman
@maarek
Dec 07 2017 03:54
Yeah often it's the case.
Cory Parent
@goedelsoup
Dec 07 2017 03:54
Fold that option into something meaningful, pick the appropriate target monad and drive from there.
You will be happier. I'm dealing with legacy now, have a ton of monad transformers to make things work, but the end goal is to simplify. We're having to get heady to make confident refactoring a possibility.
I.e. the transformers didn't exist, we added to make things deterministic and now we're replacing them with cats.effect.IO or Monix/fs2
Don't build monad nesting depth/complexity
Christopher Davenport
@ChristopherDavenport
Dec 07 2017 03:59
F[_]:Sync is great for interop.
Cory Parent
@goedelsoup
Dec 07 2017 04:01
It is...don't get into Sync[Either [Throwable, Option[Foo]]]
My biggest advise to cats users is to understand ApplicativeError and MonadError to mitigate all the pains I hit.
Roll programs and execute where necessary
Christopher Davenport
@ChristopherDavenport
Dec 07 2017 04:04
Execute at end of world.
Cory Parent
@goedelsoup
Dec 07 2017 04:06
Yes. Stick to gluing monads, preferably without transformers, and I promise bug count will drop drastically.
I inherited code that takes Doobie connection to as option and wraps to either of not found, instead of raiseError that expressed the missing record. Nightmare.
If you're writing code to handle state while using the solid Typelevel libs, you're probably doing something wrong.
Cory Parent
@goedelsoup
Dec 07 2017 04:11
Or you have a complex domain and it's fair. Personally, I've found all of our Scala to be overcomplicated.
Christopher Davenport
@ChristopherDavenport
Dec 07 2017 04:14
Id be happy if my inherited legacy code was a State monad of some sort over an Akka mess.
I keep threatening to rewrite it as IndexedReaderWriterStateT.
Piotr Gawryś
@Avasil
Dec 07 2017 07:43
How is MonadError supposed to be used? As a more generic replacement to Either/Try?
Daniel Wunsch
@dwunsch
Dec 07 2017 12:21
yes. it provides something like try/catch functionality for arbitrary monads/monad stacks.
Ionuț G. Stan
@igstan
Dec 07 2017 14:06
Does cats have a way of zipping more than three lists with a function? mapN gives a cartesian product.
Fabio Labella
@SystemFw
Dec 07 2017 14:16
@igstan have you tried parMapN ?
don't know if the Parallel[List, ZipList] instance is there yet
but worth a try
Ionuț G. Stan
@igstan
Dec 07 2017 14:19
@SystemFw thanks. Unfortunatelly, it doesn't work yet.
Fabio Labella
@SystemFw
Dec 07 2017 14:20
what happened, it didn't compile?
Ionuț G. Stan
@igstan
Dec 07 2017 14:20
scala> (List(1,2), List(3,4)).parMapN((a,b) => println("" + a + b))
<console>:40: error: could not find implicit value for parameter p: cats.NonEmptyParallel[List,F]
       (List(1,2), List(3,4)).parMapN((a,b) => println("" + a + b))
                                     ^
With import cats._, data._, implicits._
Fabio Labella
@SystemFw
Dec 07 2017 14:21
typelevel/cats#1938
it should work
Ionuț G. Stan
@igstan
Dec 07 2017 14:21
Oh, I'm on RC1. I think that PR didn't make it.
Luka Jacobowitz
@LukaJCB
Dec 07 2017 14:22
Yeah coming in 1.0, sorry
Ionuț G. Stan
@igstan
Dec 07 2017 14:22
No worries. At least it's coming :)
Thanks!
Fabio Labella
@SystemFw
Dec 07 2017 14:22
ah, fair enough
Kai(luo) Wang
@kailuowang
Dec 07 2017 16:01
5 days away from bin compat breaking PR freezing and 7 days away from 1.0
Cody Allen
@ceedubs
Dec 07 2017 23:07
I think that #2080 is my favorite Cats PR that I’ve ever made. ScalaDoc grouping for all of the ap2, ap3, etc boilerplate methods :heart_eyes_cat: