ia_2.11.0.12.1.0-b575bf3.source-code.mercator.scala Maven / Gradle / Ivy
The newest version!
/*
Mercator, version 0.1.1. Copyright 2018 Jon Pretty, Propensive Ltd.
The primary distribution site is: https://propensive.com/
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
this file except in compliance with the License. You may obtain a copy of the
License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations under
the License.
*/
package mercator
import scala.language.higherKinds
import scala.reflect.macros._
import language.experimental.macros
import language.implicitConversions
object `package` {
implicit def monadic[F[_]]: Monadic[F] =
macro Mercator.instantiate[F[Nothing]]
final implicit class Ops[M[_], A](val value: M[A]) extends AnyVal {
@inline def flatMap[B](fn: A => M[B])(implicit monadic: Monadic[M]): M[B] =
monadic.flatMap[A, B](value)(fn)
@inline def map[B](fn: A => B)(implicit monadic: Monadic[M]): M[B] =
monadic.map[A, B](value)(fn)
@inline def filter(fn: A => Boolean)(implicit monadic: MonadicFilter[M]): M[A] =
monadic.filter[A](value)(fn)
}
implicit def collOps[M[_], Coll[T] <: Iterable[T], A](value: Coll[M[A]]): CollOps[M, Coll, A] =
new CollOps(value)
implicit def traversableOps[Coll[T] <: Iterable[T], A](value: Coll[A]): TraversableOps[Coll, A] =
new TraversableOps(value)
}
object Mercator {
def instantiate[F: c.WeakTypeTag](c: whitebox.Context): c.Tree = {
import c.universe._
val typeConstructor = weakTypeOf[F].typeConstructor
val mockType = appliedType(typeConstructor, typeOf[Mercator.type])
val companion = typeConstructor.dealias.typeSymbol.companion
val returnType = scala.util.Try(c.typecheck(q"$companion.apply(_root_.mercator.Mercator)").tpe)
val pointApplication = if(returnType.map(_ <:< mockType).getOrElse(false)) q"${companion.asModule}(value)" else {
val subtypes = typeConstructor.typeSymbol.asClass.knownDirectSubclasses.filter { sub =>
c.typecheck(q"${sub.companion}.apply(_root_.mercator.Mercator)").tpe <:< mockType
}.map { sub => q"${sub.companion}.apply(value)" }
if(subtypes.size == 1) subtypes.head
else c.abort(c.enclosingPosition, s"mercator: unable to derive Monadic instance for type constructor $typeConstructor")
}
val filterMethods: List[Tree] = if(mockType.typeSymbol.info.member(TermName("filter")) == NoSymbol) Nil
else List(q"def filter[A](value: Monad[A])(fn: A => Boolean) = value.filter(fn)")
val instantiation =
if(filterMethods.isEmpty) tq"_root_.mercator.Monadic[$typeConstructor]"
else tq"_root_.mercator.MonadicFilter[$typeConstructor]"
q"""
new $instantiation {
def point[A](value: A): Monad[A] = $pointApplication
def flatMap[A, B](from: Monad[A])(fn: A => Monad[B]): Monad[B] = from.flatMap(fn)
def map[A, B](from: Monad[A])(fn: A => B): Monad[B] = from.map(fn)
..$filterMethods
}
"""
}
}
trait Monadic[F[_]] {
type Monad[T] = F[T]
def point[A](value: A): F[A]
def flatMap[A, B](from: F[A])(fn: A => F[B]): F[B]
def map[A, B](from: F[A])(fn: A => B): F[B]
}
trait MonadicFilter[F[_]] extends Monadic[F] {
def filter[A](value: F[A])(fn: A => Boolean): F[A]
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy