Where communities thrive

  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
Repo info
  • 19:44
    LukaJCB opened #3456
  • 19:44

    LukaJCB on more-laziness

    Override map2Eval and combineKEā€¦ (compare)

  • 18:01
    djspiewak closed #2195
  • 18:01
    djspiewak commented #2195
  • 17:51
    dantb commented #3373
  • 17:38
    dantb synchronize #3373
  • 15:48
    psilospore synchronize #3455
  • 14:52
    LukaJCB commented #3392
  • 14:18
    barambani commented #3392
  • 12:45
    psttf commented #2195
  • 11:12
    gagandeepkalra review_requested #3392
  • 07:14
    travisbrown milestoned #3440
  • 07:14
    travisbrown labeled #3440
  • Jun 04 21:23
    psilospore commented #3455
  • Jun 04 20:11
    psilospore opened #3455
  • Jun 04 20:06
    djspiewak commented #3411
  • Jun 04 13:55
    travisbrown commented #3442
  • Jun 04 13:20

    travisbrown on master

    Optimise NonEmptyTraverse impleā€¦ (compare)

  • Jun 04 13:20
    travisbrown closed #3382
  • Jun 04 13:20
    travisbrown closed #3381
A friend asked about whether we would have CycledEnum as well (as in Mon, Tues, ...),but it'd be hard to formulate a law for it. Ideally I'd like to say forall b a. exists. next(a) = b.
P. Oscar Boykin
should Next extends PartialNext or build default instance?
I think def cycleNext[A: PartialNext: Lowerbounded](a: A): A
that's just a method, right?
Yilin Wei
Yeah, good point.
I hesitated in the same hierarchy; since I was thinking if you wrote a method it could easily never terminate.
Which feels pretty bad to me; is there any precedent?
P. Oscar Boykin
I didn't follow you. if you have trait Next[A] extends PartialNext[A] { final def partialNext(a: A) = Some(next(a)) }
I don't see the problem
but you could also do with: implicit def partialFromNext[A: Next]: PartialNext[A] = ...
P. Oscar Boykin
what I meant about cycleNext is that can you write: def cycleNext[A: PartialNext: LowerBounded](a: A): A = PartialNext[A].partialNext(a).getOrElse(LowerBounded[A].lowerBound)
I don't think we need a law for a function like that since it is implied by PartialNext and LowerBounded, but you could write a test with a small cardinality type, e.g. Byte and show that the period of any value is exactly 256
Yilin Wei
No I meant that it feels problematic to me because I was thinking of having a function which enumerated the values dependent on only a LowerBound and PartialNext which would be none terminating if Next extended PartialNext. I guess it depends on how you read the signature (i.e. I read it as there exist s an upper bound for a partial next) which is why it extends UpperBound.
I guess if you were thinking of having multiple ranges, then we'd remove that constraint.
(since theoretically if we see next as something which links elements in a partial order, nothing says it must close under that operation)
How about I add a Closed variant?
Or is this getting a little complicated?
Yilin Wei
Apologies if unclear. On my phone atm.
Yilin Wei
Sleeping on it I think you're right, I'll remove the UpperBound from PartialNext and put it on the relevant Enum trait.
Then Next can extend PartialNext. The caveat on PartialNext being that it makes no guarantee of returning a None eventually. We move the law next(max) ==None on the Enum instead.
P. Oscar Boykin
ahh, I see your point. I overlooked that your design had PartialNext[A] implying the existence of UpperBounded[A]... In this way, you have the idea that Iterator.iterate(Option(a))(_.flatMap(PartialNext[A].partialNext)).collect { case Some(a) => a } is always finite.
I guess the key issue: do we want to write code against both Next and PartialNext at the same time? Like, are there cases where we don't care if we terminate or not?
Also, similar to getting a Monoid from a Semigroup by adding an empty element (the Option transformation) you could do the same by adding a point at infinity.
so, you could take Next[BigInt] => PartialNext[Option[BigInt]] where None > Some(_) or you could make a similar artificial point at infinity.
(if you don't want to use Opiton)
so, I may have clouded the issue... I can see arguments for both designs.
but, I think I like your last suggestion: Next can PartialNext, but if you have both a PartialNext AND and UpperBounded, then next(max) == None and iterating next will eventually terminate.
P. Oscar Boykin
I guess it comes down to this: does PartialNext mean definitely partial, or possibly partial? For other structures, we don't usually make them mean definitely limited, e.g. PartialOrdering doesn't mean there are definitely two incomparable items.
and Semigroup doesn't mean there definitely isn't an empty element.
so, I think consistency-wise, using an additional constraint to imply that is the right way: PartialNext + UpperBounded
Yilin Wei
Yes; I came to the same conclusion ( I think that the bounds are not implied alone by the PartialNext.
P. Oscar Boykin
I don't think PartialNext can extend UpperBounded
not if Next extends PartialNext
and your code above has that
Yilin Wei
Oops, yes I should have removed that
P. Oscar Boykin
other than that, it looks good to me.
Yilin Wei
Would it be best to put the helper functions such as cycleNext, members, between in cats-core? I know the kernel is meant to be really thin.
P. Oscar Boykin
I think functions that only depend on kernel, should live in kernel
my opinion of kernel today is that is should be non-higherkinded typeclasses
e.g. F[_] not F[_[_]]
so, Next[BigInt] not Monad[List]
the original motivation was to unify the typeclasses in spire and algebird
(they both use kernel now), and cats needed them too, but we didn't want spire and algebird to depend on cats.
Yilin Wei
Alright - I'll add the laws and instances and then submit the a tentative PR. Will probably be sometime on the weekend. Thanks for your help!
Fabio Labella

and cats needed them too, but we didn't want spire and algebird to depend on cats.

out of sheer curiosity, given how cats has turned out, would you say not depending on it is still the right thing for spire and algebird?

Luka Jacobowitz
Back then we still had breaking changes every few months or so
I think nowadays the distinction between kernel and core are pretty much moot
Unless you care about small jar sizes