Skip to content
This repository
file 105 lines (84 sloc) 2.86 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
/*
* Copyright (c) 2012-3 Miles Sabin
*
* 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 shapeless.examples

import shapeless._

object MonoidExamples extends App {
  import MonoidSyntax._

  // A pair of arbitrary case classes
  case class Foo(i : Int, s : String)
  case class Bar(b : Boolean, s : String, d : Double)

  // Automatically they're monoids ...
  {
    import Monoid.auto._
    val f = Foo(13, "foo") |+| Foo(23, "bar")
    assert(f == Foo(36, "foobar"))
  }

  // ... or explicitly
  {
    implicit val barInstance = Monoid[Bar]

    val b = Bar(true, "foo", 1.0) |+| Bar(false, "bar", 3.0)
    assert(b == Bar(true, "foobar", 4.0))
  }
}

/**
* Pedagogic subset of the Scalaz monoid
*/
trait Monoid[T] {
  def zero : T
  def append(a : T, b : T) : T
}

object Monoid extends ProductTypeClassCompanion[Monoid] {
  def mzero[T](implicit mt : Monoid[T]) = mt.zero
  
  implicit def booleanMonoid : Monoid[Boolean] = new Monoid[Boolean] {
    def zero = false
    def append(a : Boolean, b : Boolean) = a || b
  }
  
  implicit def intMonoid : Monoid[Int] = new Monoid[Int] {
    def zero = 0
    def append(a : Int, b : Int) = a+b
  }
  
  implicit def doubleMonoid : Monoid[Double] = new Monoid[Double] {
    def zero = 0.0
    def append(a : Double, b : Double) = a+b
  }
  
  implicit def stringMonoid : Monoid[String] = new Monoid[String] {
    def zero = ""
    def append(a : String, b : String) = a+b
  }

  implicit val monoidInstance: ProductTypeClass[Monoid] = new ProductTypeClass[Monoid] {
    def emptyProduct = new Monoid[HNil] {
      def zero = HNil
      def append(a : HNil, b : HNil) = HNil
    }

    def product[F, T <: HList](FHead : Monoid[F], FTail : Monoid[T]) = new Monoid[F :: T] {
      def zero = FHead.zero :: FTail.zero
      def append(a : F :: T, b : F :: T) = FHead.append(a.head, b.head) :: FTail.append(a.tail, b.tail)
    }

    def project[F, G](instance : => Monoid[G], to : F => G, from : G => F) = new Monoid[F] {
      def zero = from(instance.zero)
      def append(a : F, b : F) = from(instance.append(to(a), to(b)))
    }
  }

}

trait MonoidSyntax[T] {
  def |+|(b : T) : T
}

object MonoidSyntax {
  implicit def monoidSyntax[T](a : T)(implicit mt : Monoid[T]) : MonoidSyntax[T] = new MonoidSyntax[T] {
    def |+|(b : T) = mt.append(a, b)
  }
}

// vim: expandtab:ts=2:sw=2
Something went wrong with that request. Please try again.