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

Custom Functor Typeclass #1643

Merged
merged 10 commits into from Oct 6, 2016

Conversation

Projects
None yet
3 participants
@fosskers
Contributor

fosskers commented Sep 29, 2016

TODO

  • Functor trait
  • Instance for TileLayerMetadata[K] (maps over KeyBounds)
  • Remove SpatialComponent constraint on TIleLayerMetadata.apply
  • Get .map to inject properly (thanks to @pomadchin )
  • Add test to confirm #1575 fix (no point, the compiler guarantees it)

Motivation

#1575 describes how TileLayerRDD.toSpatial doesn't reflect the change in key type in its metadata. After much deliberation, we recognized our attempts to address this as attempts to write a Functor instance for TileLayerMetadata[K] which maps over its KeyBounds. Unfortunately, Scalaz's Functor trait is a bit too restrictive, in that types that use it can't impose additional constraints on their inner type. Compare Scalaz:

trait Functor[F[_]] extends InvariantFunctor[F] { self =>

  /** Lift `f` into `F` and apply to `F[A]`. */
  def map[A, B](fa: F[A])(f: A => B): F[B]
...
}

to our implementation:

 trait Functor[F[_], A] extends MethodExtensions[F[A]]{
   /** Lift `f` into `F` and apply to `F[A]`. */
   def map[B](f: A => B): F[B]
 }

where A is lifted into Functor's type signature. This allows us to write code like this:

def foo[K: A: B: C](implicit f: Functor[TileLayerMetadata, K]): ??? = {
...
  tlm.map(k => ... ) // `k` has all the power of its constraints A, B, and C.
...
}

fosskers and others added some commits Sep 29, 2016

@fosskers

This comment has been minimized.

Contributor

fosskers commented Sep 29, 2016

This may or may not be an actual Functor, depending on how well we can convince ourselves that the second Functor law holds:

fmap (g . h) = (fmap g) . (fmap h)

If you only had one implicit Functor[F, A] in scope, then:

val m: F[A] = ???
val f: A => B = ???
val g: B => C = ???

val n: F[C] = m.map(f).map(g)

wouldn't compile. But if you did have both Functor[F, A] and Functor[F, B] (which may both use the same underlying implicit class, see class TlmFunctor[A]), then the above would compile. Furthermore, so would:

val n: F[C] = m.map(k => g(f(k)))

and so the Functor law holds, and it is indeed a Functor.

@fosskers fosskers changed the title from [WIP] Custom Functor Typeclass to Custom Functor Typeclass Sep 29, 2016

pomadchin and others added some commits Sep 29, 2016

Merge pull request #2 from pomadchin/feature/cgw/functor-kindprojector
Use kind projector lambdas to get rid of explicit implicits usage
@@ -16,9 +16,8 @@ trait Implicits {
extends TileLayerRDDFilterMethods[K, V, M]
implicit class withSpaceTimeToSpatialMethods[
K: SpatialComponent: TemporalComponent,
K: SpatialComponent: TemporalComponent: λ[α => M[α] => Functor[M, α]]: λ[α => Component[M[α], Bounds[α]]],

This comment has been minimized.

@lossyrob

lossyrob Oct 5, 2016

Member

This should be type aliased w/ a broken down explained in a comment, pretty tough to parse and also understand why they just can't be context bounds on M

This comment has been minimized.

@fosskers

fosskers Oct 5, 2016

Contributor

It's definitely space voodoo the first time you see it, yeah. For technical reasons they can't be bounds on M, so I'll explain that.

@@ -62,6 +61,14 @@ package object spark
new ContextRDD(rdd, metadata)
}
implicit class TileLayerMetadataFunctor[A](val self: TileLayerMetadata[A]) extends Functor[TileLayerMetadata, A] {

This comment has been minimized.

@lossyrob

lossyrob Oct 5, 2016

Member

Comments to explain why this is needed.

pomadchin and others added some commits Oct 6, 2016

@lossyrob lossyrob merged commit 3b132fd into locationtech:master Oct 6, 2016

1 check passed

continuous-integration/travis-ci/pr The Travis CI build passed
Details

@lossyrob lossyrob added this to the 1.0 milestone Oct 18, 2016

@fosskers fosskers referenced this pull request Dec 28, 2016

Closed

Generic Functor usage #1948

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment