-
-
Notifications
You must be signed in to change notification settings - Fork 4.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactored play-functional to make it clearer + moved Constraints bac…
…k to play core project because I want to keep Forms as is for now
- Loading branch information
Showing
11 changed files
with
200 additions
and
160 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
10 changes: 10 additions & 0 deletions
10
framework/src/play-datacommons/src/main/scala/play/api/data/validation/ValidationError.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package play.api.data.validation | ||
|
||
/** | ||
* A validation error. | ||
* | ||
* @param message the error message | ||
* @param args the error message arguments | ||
*/ | ||
case class ValidationError(message: String, args: Any*) | ||
|
File renamed without changes.
21 changes: 21 additions & 0 deletions
21
framework/src/play-functional/src/main/scala/play/api/libs/functional/Alternative.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package play.api.libs.functional | ||
|
||
import scala.language.higherKinds | ||
|
||
trait Alternative[M[_]]{ | ||
|
||
def app: Applicative[M] | ||
def |[A,B >: A](alt1: M[A], alt2 : M[B]): M[B] | ||
def empty: M[Nothing] | ||
//def some[A](m: M[A]): M[List[A]] | ||
//def many[A](m: M[A]): M[List[A]] | ||
|
||
} | ||
|
||
class AlternativeOps[M[_],A](alt1: M[A])(implicit a: Alternative[M]){ | ||
|
||
def |[B >: A](alt2: M[B]):M[B] = a.|(alt1,alt2) | ||
def or[B >: A](alt2: M[B]):M[B] = |(alt2) | ||
|
||
} | ||
|
23 changes: 23 additions & 0 deletions
23
framework/src/play-functional/src/main/scala/play/api/libs/functional/Applicative.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package play.api.libs.functional | ||
|
||
import scala.language.higherKinds | ||
|
||
trait Applicative[M[_]]{ | ||
|
||
def pure[A](a: A): M[A] | ||
def map[A,B](m: M[A], f: A => B): M[B] | ||
def apply[A,B](mf: M[A => B], ma: M[A]): M[B] | ||
|
||
} | ||
|
||
This comment has been minimized.
Sorry, something went wrong. |
||
class ApplicativeOps[M[_],A](ma:M[A])(implicit a:Applicative[M]){ | ||
|
||
def ~>[B](mb: M[B]):M[B] = a(a(a.pure((_:A) => (b:B) => b), ma),mb) | ||
def andKeep[B](mb: M[B]):M[B] = ~>(mb) | ||
|
||
def <~[B](mb: M[B]):M[A] = a(a(a.pure((a:A) => (_:B) => a), ma),mb) | ||
def keepAnd[B](mb: M[B]):M[A] = <~(mb) | ||
|
||
def <~>[B,C](mb: M[B])(implicit witness: <:<[A,B => C]): M[C] = apply(mb) | ||
def apply[B,C](mb: M[B])(implicit witness: <:<[A,B => C]): M[C] = a(a.map(ma,witness),mb) | ||
} |
41 changes: 41 additions & 0 deletions
41
framework/src/play-functional/src/main/scala/play/api/libs/functional/Functors.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package play.api.libs.functional | ||
|
||
import scala.language.higherKinds | ||
|
||
trait Variant[M[_]] | ||
|
||
trait Functor[M[_]] extends Variant[M]{ | ||
|
||
def fmap[A,B](m: M[A], f: A => B): M[B] | ||
|
||
} | ||
|
||
trait InvariantFunctor[M[_]] extends Variant[M]{ | ||
|
||
def inmap[A,B](m: M[A], f1: A => B, f2: B => A): M[B] | ||
|
||
} | ||
|
||
trait ContravariantFunctor[M[_]] extends Variant[M]{ | ||
|
||
def contramap[A,B](m: M[A], f1: B => A): M[B] | ||
|
||
} | ||
|
||
class FunctorOps[M[_],A](ma: M[A])(implicit fu: Functor[M]){ | ||
|
||
def fmap[B](f: A => B):M[B] = fu.fmap(ma, f) | ||
|
||
} | ||
|
||
class ContravariantFunctorOps[M[_],A](ma:M[A])(implicit fu:ContravariantFunctor[M]){ | ||
|
||
def contramap[B](f: B => A):M[B] = fu.contramap(ma, f) | ||
|
||
} | ||
|
||
class InvariantFunctorOps[M[_],A](ma:M[A])(implicit fu:InvariantFunctor[M]){ | ||
|
||
def inmap[B](f: A => B, g: B => A):M[B] = fu.inmap(ma, f, g) | ||
|
||
} |
29 changes: 29 additions & 0 deletions
29
framework/src/play-functional/src/main/scala/play/api/libs/functional/Monoid.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package play.api.libs.functional | ||
|
||
trait Monoid[A] { | ||
|
||
def append(a1: A, a2: A): A | ||
def identity: A | ||
|
||
} | ||
|
||
/* A practical variant of monoid act/action/operator (search on wikipedia) | ||
* - allows to take an element A to create a B | ||
* - allows a prepend/append a A to a B | ||
* cf Reducer[JsValue, JsArray] | ||
*/ | ||
trait Reducer[A, B] { | ||
|
||
def unit(a: A): B | ||
def prepend(a: A, b: B): B | ||
def append(b: B, a: A): B | ||
|
||
} | ||
|
||
object Reducer { | ||
def apply[A, B](f: A => B)(implicit m: Monoid[B]) = new Reducer[A, B] { | ||
def unit(a: A): B = f(a) | ||
def prepend(a: A, b: B) = m.append(unit(a), b) | ||
def append(b: B, a: A) = m.append(b, unit(a)) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
51 changes: 51 additions & 0 deletions
51
framework/src/play-functional/src/main/scala/play/api/libs/functional/syntax/package.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package play.api.libs.functional.syntax | ||
|
||
import scala.language.higherKinds | ||
import scala.language.implicitConversions | ||
|
||
import play.api.libs.functional._ | ||
|
||
/** | ||
* Don't forget to {{{import play.api.libs.functional.syntax._}}} to enable functional combinators | ||
* when using Json API. | ||
*/ | ||
object `package` { | ||
|
||
implicit def toAlternativeOps[M[_],A](a: M[A])(implicit app: Alternative[M]): AlternativeOps[M,A] = new AlternativeOps(a) | ||
|
||
implicit def toApplicativeOps[M[_],A](a: M[A])(implicit app: Applicative[M]): ApplicativeOps[M,A] = new ApplicativeOps(a) | ||
|
||
implicit def toFunctionalBuilderOps[M[_],A](a: M[A])(implicit fcb: FunctionalCanBuild[M]) = new FunctionalBuilderOps[M,A](a)(fcb) | ||
|
||
implicit def functionalCanBuildApplicative[M[_]](implicit app: Applicative[M]): FunctionalCanBuild[M] = new FunctionalCanBuild[M] { | ||
|
||
def apply[A,B](a: M[A], b: M[B]): M[A~B] = app.apply(app.map[A, B => A ~ B](a, a => ((b: B) => new ~(a,b))),b) | ||
|
||
} | ||
|
||
implicit def functorOption: Functor[Option] = new Functor[Option] { | ||
|
||
def fmap[A,B](a:Option[A], f: A => B):Option[B] = a.map(f) | ||
|
||
} | ||
|
||
implicit def applicativeOption: Applicative[Option] = new Applicative[Option]{ | ||
|
||
def pure[A](a: A):Option[A] = Some(a) | ||
|
||
def map[A,B](m:Option[A], f: A => B):Option[B] = m.map(f) | ||
|
||
def apply[A,B](mf:Option[A => B], ma: Option[A]):Option[B] = mf.flatMap(f => ma.map(f)) | ||
|
||
} | ||
|
||
implicit def toFunctorOps[M[_], A](ma: M[A])(implicit fu: Functor[M]): FunctorOps[M, A] = new FunctorOps(ma) | ||
implicit def toContraFunctorOps[M[_], A](ma: M[A])(implicit fu: ContravariantFunctor[M]): ContravariantFunctorOps[M, A] = new ContravariantFunctorOps(ma) | ||
implicit def toInvariantFunctorOps[M[_], A](ma: M[A])(implicit fu: InvariantFunctor[M]): InvariantFunctorOps[M, A] = new InvariantFunctorOps(ma) | ||
|
||
def unapply[B, A](f: B => Option[A]) = { b: B => f(b).get } | ||
|
||
def unlift[A, B](f: A => Option[B]): A => B = Function.unlift(f) | ||
|
||
} | ||
|
Oops, something went wrong.
I don't know any blog about it sorry...
You have to implement a Application[YourClass[_]]...
Have a look at Reads.scala file which implements Applicative[Reads]
Then as soon as you have an Applicative[YourClass], you can compose it using FunctionalBuilder exactly as we do with our Reads!