From 55f1d76452bc24f6bffbab43d1e839e688533c82 Mon Sep 17 00:00:00 2001 From: Nathan Howell Date: Wed, 17 Feb 2016 12:42:07 -0800 Subject: [PATCH] Add the Identity monad --- .../scala/com/twitter/algebird/Identity.scala | 71 +++++++++++++++++++ .../com/twitter/algebird/MonadLaws.scala | 3 + .../algebird/ApplicativeProperties.scala | 7 ++ .../twitter/algebird/FunctorProperties.scala | 6 +- .../twitter/algebird/MonadProperties.scala | 4 ++ 5 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 algebird-core/src/main/scala/com/twitter/algebird/Identity.scala diff --git a/algebird-core/src/main/scala/com/twitter/algebird/Identity.scala b/algebird-core/src/main/scala/com/twitter/algebird/Identity.scala new file mode 100644 index 000000000..47f9e3d9f --- /dev/null +++ b/algebird-core/src/main/scala/com/twitter/algebird/Identity.scala @@ -0,0 +1,71 @@ +/* +Copyright 2016 GoDaddy, Inc. + +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 com.twitter.algebird + +case class Identity[T](get: T) + +object IdentityMonad extends Monad[Identity] { + override def map[T, U](m: Identity[T])(fn: T => U): Identity[U] = { + Identity(fn(m.get)) + } + + override def apply[T](v: T): Identity[T] = { + Identity(v) + } + + override def join[T, U](mt: Identity[T], mu: Identity[U]): Identity[(T, U)] = { + Identity((mt.get, mu.get)) + } + + override def flatMap[T, U](m: Identity[T])(fn: T => Identity[U]): Identity[U] = { + fn(m.get) + } + + override def sequence[T](ms: Seq[Identity[T]]): Identity[Seq[T]] = { + Identity(ms.map(_.get)) + } + + override def joinWith[T, U, V](mt: Identity[T], mu: Identity[U])(fn: (T, U) => V): Identity[V] = { + Identity(fn(mt.get, mu.get)) + } + + override def join[T1, T2, T3](m1: Identity[T1], m2: Identity[T2], m3: Identity[T3]): Identity[(T1, T2, T3)] = { + Identity((m1.get, m2.get, m3.get)) + } + + override def join[T1, T2, T3, T4](m1: Identity[T1], m2: Identity[T2], m3: Identity[T3], m4: Identity[T4]): Identity[(T1, T2, T3, T4)] = { + Identity((m1.get, m2.get, m3.get, m4.get)) + } + + override def join[T1, T2, T3, T4, T5](m1: Identity[T1], m2: Identity[T2], m3: Identity[T3], m4: Identity[T4], m5: Identity[T5]): Identity[(T1, T2, T3, T4, T5)] = { + Identity((m1.get, m2.get, m3.get, m4.get, m5.get)) + } +} + +object Identity { + implicit def identityFunctor: Functor[Identity] = { + IdentityMonad + } + + implicit def identityApplicative: Applicative[Identity] = { + IdentityMonad + } + + implicit def identityMonad: Monad[Identity] = { + IdentityMonad + } +} diff --git a/algebird-test/src/main/scala/com/twitter/algebird/MonadLaws.scala b/algebird-test/src/main/scala/com/twitter/algebird/MonadLaws.scala index 74359c0c8..92a634de4 100644 --- a/algebird-test/src/main/scala/com/twitter/algebird/MonadLaws.scala +++ b/algebird-test/src/main/scala/com/twitter/algebird/MonadLaws.scala @@ -65,4 +65,7 @@ object MonadLaws { implicit def someA[T](implicit arbl: Arbitrary[T]): Arbitrary[Some[T]] = Arbitrary { arbl.arbitrary.map { l => Some(l) } } + + implicit def identityA[T](implicit arbl: Arbitrary[T]): Arbitrary[Identity[T]] = + Arbitrary { arbl.arbitrary.map { l => Identity(l) } } } diff --git a/algebird-test/src/test/scala/com/twitter/algebird/ApplicativeProperties.scala b/algebird-test/src/test/scala/com/twitter/algebird/ApplicativeProperties.scala index f455dc4a0..0704913ec 100644 --- a/algebird-test/src/test/scala/com/twitter/algebird/ApplicativeProperties.scala +++ b/algebird-test/src/test/scala/com/twitter/algebird/ApplicativeProperties.scala @@ -37,6 +37,7 @@ class ApplicativeProperties extends CheckProperties { property("indexedseq") { applicativeLaws[IndexedSeq, Int, String, Long]() } + property("vector") { applicativeLaws[Vector, Int, String, Long]() } @@ -44,9 +45,15 @@ class ApplicativeProperties extends CheckProperties { property("set") { applicativeLaws[Set, Int, String, Long]() } + property("seq") { applicativeLaws[Seq, Int, String, Long]() } + + property("identity") { + applicativeLaws[Identity, Int, String, Long]() + } + property("sequenceGen") { // This follows from the laws, so we are just testing // the implementation of sequenceGen against sequence here diff --git a/algebird-test/src/test/scala/com/twitter/algebird/FunctorProperties.scala b/algebird-test/src/test/scala/com/twitter/algebird/FunctorProperties.scala index cf787f91f..3de377df8 100644 --- a/algebird-test/src/test/scala/com/twitter/algebird/FunctorProperties.scala +++ b/algebird-test/src/test/scala/com/twitter/algebird/FunctorProperties.scala @@ -18,7 +18,8 @@ package com.twitter.algebird class FunctorProperties extends CheckProperties { import com.twitter.algebird.FunctorLaws._ - import com.twitter.algebird.Monad._ // for Arbitrary instances + import com.twitter.algebird.Monad._ // for Functor instances + import com.twitter.algebird.MonadLaws._ // for Arbitrary instances property("list") { functorLaws[List, Int, String, Long]() @@ -44,4 +45,7 @@ class FunctorProperties extends CheckProperties { functorLaws[Seq, Int, String, Long]() } + property("identity") { + functorLaws[Identity, Int, String, Long]() + } } diff --git a/algebird-test/src/test/scala/com/twitter/algebird/MonadProperties.scala b/algebird-test/src/test/scala/com/twitter/algebird/MonadProperties.scala index b746aa70c..17d89e8cb 100644 --- a/algebird-test/src/test/scala/com/twitter/algebird/MonadProperties.scala +++ b/algebird-test/src/test/scala/com/twitter/algebird/MonadProperties.scala @@ -48,4 +48,8 @@ class MonadProperties extends CheckProperties { property("seq") { monadLaws[Seq, Int, String, Long]() } + + property("identity") { + monadLaws[Identity, Int, String, Long]() + } }