Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inject for either #1600

Merged
merged 2 commits into from
Jun 24, 2017
Merged

Inject for either #1600

merged 2 commits into from
Jun 24, 2017

Conversation

andyscott
Copy link
Contributor

@andyscott andyscott commented Apr 9, 2017

Re-introduces Inject, but for Either. I also went ahead and tried to document both Inject and InjectK.

Todo:

  • Add Inject
  • Scaladoc for Inject and InjectK
  • Add tests

Associated issue: #1599

@kailuowang kailuowang added this to the 1.0.0-MF milestone Apr 11, 2017
@andyscott andyscott force-pushed the inject-for-either branch 2 times, most recently from 3848ed5 to 1b61293 Compare April 24, 2017 15:55
@kailuowang kailuowang mentioned this pull request May 25, 2017
26 tasks
@andyscott
Copy link
Contributor Author

I'll rebase/finish this after settling #1725

@andyscott andyscott force-pushed the inject-for-either branch 3 times, most recently from 9146b2b to b070c71 Compare June 14, 2017 04:38
@andyscott andyscott changed the title [Work in Progress] Inject for either Inject for either Jun 14, 2017
@andyscott andyscott force-pushed the inject-for-either branch from b070c71 to 5c51adf Compare June 14, 2017 05:10
@codecov-io
Copy link

codecov-io commented Jun 14, 2017

Codecov Report

Merging #1600 into master will increase coverage by 0.03%.
The diff coverage is 100%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #1600      +/-   ##
==========================================
+ Coverage   93.99%   94.02%   +0.03%     
==========================================
  Files         253      256       +3     
  Lines        4180     4202      +22     
  Branches      155       90      -65     
==========================================
+ Hits         3929     3951      +22     
  Misses        251      251
Impacted Files Coverage Δ
core/src/main/scala/cats/InjectK.scala 100% <ø> (ø) ⬆️
laws/src/main/scala/cats/laws/InjectLaws.scala 100% <100%> (ø)
core/src/main/scala/cats/Inject.scala 100% <100%> (ø)
.../main/scala/cats/laws/discipline/InjectTests.scala 100% <100%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update e3a969e...521a0c4. Read the comment docs.


def prj: B => Option[A]

def apply(a: A): B = inj(a)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shall we make these two final as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch!

@andyscott andyscott force-pushed the inject-for-either branch from 5c51adf to b56e92a Compare June 15, 2017 15:50
/**
* Inject is a type class to inject a value of type `A` into a
* coproduct of types `B` when `A :≺: B`. The coproduct `B` is
* modelled with `Either`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's true that it is the original incentive for introducing this class, but now that we made a type class, this is just one specific usage/instances of Inject and InjectK right?
We could have an Inject between A and List[A] or Int and Double, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's correct. I suppose it could be reworded to indicate that that's just the default behavior?

Inject is a type class to inject a value of type `A` into another type `B`.
The default instances provided by cats injects `A` into coproduct of types
`B` when `A :≺: B`. The coproduct `B` is modelled with `Either`.

Also in this explanation, :≺: is used in a conceptual sense. :≺: exists as a type alias for InjectK which could be confusing. Thoughts?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My understanding of the Inject type class is that it represents an injective function between type A and B. If we treat types as sets, and a function between the two types are just pairs of elements in the two sets A and B. Each pair has an "input" element in set A and an "output" element of B. For an injective function, for every element in A there is exactly one pair. And for every element in B there is either one pair or no pair at all.

A total pure scala function is an injective function, but it only specifies pairs for all elements in A, i.e. given any A you can get a B. It doesn't specify pairs for elements in B, this Inject type class does that through proj.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed with @kailuowang; I don't think this is particularly informative as to what Inject does, especially because we're likely going to provide these other instances in the future from cats. I'd pick something like:

Inject is a type class providing an injection f from type A into another type B.
An injection is a function which does not destroy any information, and thus for every b: B there is at most one a: A such that f(a) = b.

Because of this all injections admit partial inverses, functions B => Option[A], which pair a value b: B with the single value a: A that f sends to b if it exists.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@edmundnoble I like your explanation. I tweaked it a tad-- how about:

/**
 * Inject is a type class providing an injection from type `A` into
 * another type `B`.  An injection is a function `inj` which does not
 * destroy any information: for every `b: B` there is at most one
 * `a: A` such that `inj(a) = b`.
 *
 * Because of this all injections admit partial inverses `prj` which
 * pair a value `b: B` back with a single value `a: A`.
 *
 * @since 1.0
 * @note Prior to cats 1.0, Inject handled injection for type
 * constructors. For injection of type constructors, use [[InjectK]].
 *
 * @see [[InjectK]] for injection for [[cats.data.EitherK]]
 */
abstract class Inject[A, B] // ...

I'll give the same treatment to InjectK once proper doc is decided.

@andyscott andyscott force-pushed the inject-for-either branch from b56e92a to 521a0c4 Compare June 22, 2017 03:38
@kailuowang
Copy link
Contributor

merge with 2 sign-offs

@kailuowang kailuowang merged commit 05b9118 into typelevel:master Jun 24, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants