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

Add FunctorFilter #224

Merged
merged 14 commits into from
Aug 23, 2017
Merged

Add FunctorFilter #224

merged 14 commits into from
Aug 23, 2017

Conversation

JorgeCastilloPrz
Copy link
Member

Fixes: #223

  • Added FunctorFilter
  • Added FunctorFilterLaws
  • Added ComposedFunctorFilter and OptionTFunctor FunctorFilter instances.
  • Tested laws using OptionTFunctor.

@raulraja raulraja mentioned this pull request Aug 22, 2017
54 tasks
@codecov-io
Copy link

codecov-io commented Aug 22, 2017

Codecov Report

❗ No coverage uploaded for pull request base (master@1a7dd13). Click here to learn what that means.
The diff coverage is 18.42%.

Impacted file tree graph

@@            Coverage Diff            @@
##             master     #224   +/-   ##
=========================================
  Coverage          ?   49.84%           
  Complexity        ?      207           
=========================================
  Files             ?      103           
  Lines             ?     2329           
  Branches          ?      279           
=========================================
  Hits              ?     1161           
  Misses            ?     1056           
  Partials          ?      112
Impacted Files Coverage Δ Complexity Δ
...tegory/src/main/kotlin/kategory/arrow/Function1.kt 62.5% <ø> (ø) 1 <0> (?)
kategory/src/main/kotlin/kategory/data/Composed.kt 29.09% <0%> (ø) 0 <0> (?)
.../main/kotlin/kategory/typeclasses/FunctorFilter.kt 0% <0%> (ø) 0 <0> (?)
.../src/main/kotlin/kategory/arrow/PartialFunction.kt 29.41% <0%> (ø) 1 <0> (?)
.../src/main/kotlin/kategory/generators/Generators.kt 74.07% <100%> (ø) 0 <0> (?)
...main/kotlin/kategory/instances/OptionTInstances.kt 94.44% <100%> (ø) 0 <0> (?)
kategory/src/main/kotlin/kategory/data/OptionT.kt 21.27% <33.33%> (ø) 4 <0> (?)
...src/main/kotlin/kategory/laws/FunctorFilterLaws.kt 5.55% <5.55%> (ø) 1 <1> (?)

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 1a7dd13...db4614e. Read the comment docs.

@@ -55,3 +55,8 @@ fun genIntPredicate(): Gen<(Int) -> Boolean> =
{ it % absNum == absNum - 1 })
)
}

fun <B> genOption(genB: Gen<B>): Gen<Option<B>> =
Copy link
Member

@pakoito pakoito Aug 22, 2017

Choose a reason for hiding this comment

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

This method could be implemented using genApplicative(). In any case, to properly test Option we'd need to generate at all possible cases. What I'd suggest is to randomise None to a low percent by capturing a Gen.int() that'll run on every generate and and checking modulus 20 for 5% chance.

Copy link
Member Author

Choose a reason for hiding this comment

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

👍 fixed. I made it randomized to generate None and Some on a 5% - 95% basis.

Copy link
Member

@pakoito pakoito Aug 23, 2017

Choose a reason for hiding this comment

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

You need to capture genIntSmall() as a field inside the object and call generate() on it inside generate(), else you won't get adequate distributions as it restarts the seed every time.

@@ -4,7 +4,7 @@ fun <I, O> ((I) -> O).k(): Function1<I, O> = Function1(this)

operator fun <I, O> Function1Kind<I, O>.invoke(i: I): O = this.ev().f(i)

@higherkind class Function1<I, out O>(val f: (I) -> O) : Function1Kind<I, O> {
@higherkind open class Function1<I, out O>(val f: (I) -> O) : Function1Kind<I, O> {
Copy link
Member

Choose a reason for hiding this comment

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

Who inherits from Function1?

Copy link
Member Author

Choose a reason for hiding this comment

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

Nobody. It was being inherited by Lifted in the beginning, but no need for it anymore.

@@ -45,6 +45,13 @@ package kategory
inline fun <reified F> monoidK(MF: Monad<F> = kategory.monad<F>()): MonoidK<OptionTKindPartial<F>> = object : OptionTMonoidK<F> {
override fun F(): Monad<F> = MF
}

inline fun <reified F> functorFilter(MF: Monad<F> = kategory.monad<F>(), FF: Functor<F> = kategory.functor()): FunctorFilter<OptionTKindPartial<F>> =
Copy link
Member

Choose a reason for hiding this comment

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

Monad implies functor. You only need 1 parameter.


fun FF(): Functor<F>

fun MF(): Monad<F>
Copy link
Member

Choose a reason for hiding this comment

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

Monad implies functor. One should be enough.


object FunctorFilterLaws {

inline fun <reified F> laws(AP: Applicative<F> = applicative(), FFF: FunctorFilter<F> = functorFilter(), EQ: Eq<HK<F, Int>>): List<Law> =
Copy link
Member

@pakoito pakoito Aug 22, 2017

Choose a reason for hiding this comment

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

Some FunctorFilters may not be Applicatives. I'd suggest passing a constructor function, using genConstructor() and inlining AP::pure in the current callsites instead.

Copy link
Member Author

Choose a reason for hiding this comment

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

What do you mean ? FunctorFilterLaws depend on FunctorLaws which need an Applicative to run, that's why it's being passed here, but the FunctorFilterLaws are being tested using the FunctorFilter passed as a second argument.

Copy link
Member

@pakoito pakoito Aug 23, 2017

Choose a reason for hiding this comment

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

FunctorLaws has 2 constructor, one convenient one with Applicative in the case that you're testing anything that inherits from applicative, and another that takes a constructor function for other cases. In this case as we're testing something that doesn't inherit from applicative please use the second one.

Copy link
Member Author

Choose a reason for hiding this comment

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

Fixed.

testLaws(FunctorFilterLaws.laws(
OptionT.applicative(Option),
OptionT.functorFilter(),
Eq.any()))
Copy link
Member

Choose a reason for hiding this comment

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

I believe it may need an instance of Eq<OptionTPartial<Option, Int>>, as we've seen similar issues with other tests before.

Copy link
Member Author

Choose a reason for hiding this comment

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

Fixed 👍

@JorgeCastilloPrz
Copy link
Member Author

Back to you @pakoito

companion object {
inline operator fun <reified F, reified G> invoke(FF: Functor<F> = functor(), FFG: FunctorFilter<G> = functorFilter()): ComposedFunctorFilter<F, G> =
object : ComposedFunctorFilter<F, G> {
override fun F(): Functor<F> = FF
Copy link
Member

Choose a reason for hiding this comment

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

FunctorFilter implies Functor, you don't need the second parameter.

Copy link
Member Author

Choose a reason for hiding this comment

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

Well that's inherited from ComposedFunctor, following cats implementation.

Copy link
Member

Choose a reason for hiding this comment

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

I mean you can assign FFG to this field too.

Copy link
Member

Choose a reason for hiding this comment

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

Derp, I see.

OptionT.functorFilter(),
object : Eq<HK<OptionTKindPartial<OptionHK>, Int>>{
override fun eqv(a: HK<OptionTKindPartial<OptionHK>, Int>, b: HK<OptionTKindPartial<OptionHK>, Int>): Boolean =
a.ev().value == b.ev().value
Copy link
Member

Choose a reason for hiding this comment

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

Are we sure we can compare Option with ==, or do we need an Eq instance?

Copy link
Member Author

Choose a reason for hiding this comment

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

We are doing the same for other laws being tested on this class. I've changed it now to use the already created OptionTFIdEq instance (on top part of this test class).

@JorgeCastilloPrz
Copy link
Member Author

Back to you again @pakoito

Copy link
Member

@pakoito pakoito left a comment

Choose a reason for hiding this comment

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

Boom! Closer to MTL now!

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.

None yet

4 participants