alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Scala example source code file (TagUsage.scala)

This example Scala source code file (TagUsage.scala) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Scala by Example" TM.

Learn more about this Scala project at its project page.

Java - Scala tags/keywords

any, app, boolean, conjunction, disjunction, firstval, lastval, list, maxval, minval, multiplication, option, sorted, tagusage

The TagUsage.scala Scala example source code

package scalaz
package example

/**
  scalaz contains a way to simulate something similar to a Haskell
  newtype, where we can take an existing type, and create a new type
  from it, and allow us to create new typeclass instances for our
  newly created type to get different behaviors.  The same thing could
  be done with scala 2.10's Value Classes:
  http://docs.scala-lang.org/overviews/core/value-classes.html however
  one has to be very careful when using value classes, because there
  are a lot of instances in which using a value class will incur a
  runtime boxing/unboxing of your value, which incurs a runtime
  cost. The scalaz tagged types will never cause boxing of a value.
  */
object TagUsage extends App {
  import Tags._
  import syntax.monoid._
  import syntax.foldable._
  import syntax.equal._
  import std.anyVal._
  import std.option._
  import std.list._

  // Int has a Monoid by default which performs addition
  assert((3 |+| 3) === 6)
  assert(Monoid[Int].zero === 0)

  // Though the set of Ints forms a perfectly valid Monoid using
  // multiplication as the binary operation. We can Tag Ints with the
  // Multiplication tag, and this monoid will be selected.
  assert((Multiplication(3) |+| Multiplication(3)) === Multiplication(9))
  assert(Monoid[Int @@ Multiplication].zero === Multiplication(1))

  // There is no default Monoid for booleans, but there are Monoids
  // for booleans tagged with either the Conjunction or Disjunction
  // tag.
  assert((Conjunction(true) |+| Conjunction(true)) === Conjunction(true))
  assert((Conjunction(true) |+| Conjunction(false)) === Conjunction(false))
  assert((Conjunction(false) |+| Conjunction(false)) === Conjunction(false))
  assert(Monoid[Boolean @@ Conjunction].zero === Conjunction(true))

  assert((Disjunction(true) |+| Disjunction(true)) === Disjunction(true))
  assert((Disjunction(true) |+| Disjunction(false)) === Disjunction(true))
  assert((Disjunction(false) |+| Disjunction(false)) === Disjunction(false))
  assert(Monoid[Boolean @@ Disjunction].zero === Disjunction(false))

  // tags have a convenience method name subst for tagging an F[A] as
  // a F[A @@ SomeTag]
  assert(Conjunction.subst(List(false, true, false)).suml === Conjunction(false))
  assert(Conjunction.subst(List.empty[Boolean]).suml === Conjunction(true))
  assert(Conjunction.subst(List(true, true)).suml === Conjunction(true))

  assert(Disjunction.subst(List(false, true, false)).suml === Disjunction(true))
  assert(Disjunction.subst(List.empty[Boolean]).suml === Disjunction(false))
  assert(Disjunction.subst(List(false, false)).suml === Disjunction(false))

  // tagging a value does not actually alter the value, it is merely
  // typecasting the value to a tagged type, all this is actually lost
  // at runtime, so when we do a non-typesafe equal comparision, it
  // actually works.
  @unchecked def equalsTrue(x: Any): Boolean = x == true
  assert(equalsTrue(Disjunction(true)))

  // however at compile time, they appear to be different types, so a
  // typesafe comparison would fail to compile:
  // assert(Disjunction(true) === true)

  // Tags have an unwrap method which converts the value back to a untagged type:
  assert(Disjunction.unwrap(Disjunction(true)) === true)
  assert(Conjunction.unwrap(Conjunction.subst(List(false, true, false)).suml) === false)

  // Some other Tags in scalaz:

  // A Semigroup that selects the minimum element:
  assert(MinVal.unwrap(MinVal(3) |+| MinVal(1) |+| MinVal(5)) === 1)

  // A Semigroup that selects the maximum element:
  assert(MaxVal.unwrap(MaxVal(3) |+| MaxVal(1) |+| MaxVal(5)) === 5)

  // A Semigroup that selects the first element:
  assert(FirstVal.unwrap(FirstVal(1) |+| FirstVal(5)) === 1)

  // A Semigroup that selects the last element:
  assert(LastVal.unwrap(LastVal(1) |+| LastVal(5)) === 5)

  // Tags are not only useful for selecting typeclass instances
  // lets create our own tag, named Sorted which indicates a List that has been sorted
  sealed trait Sorted
  val Sorted = Tag.of[Sorted]

  // a sort function which will sort then add the Tag
  def sortList[A: scala.math.Ordering](as: List[A]): List[A] @@ Sorted =
    Sorted(as.sorted)

  // now we can define a function which takes lists which are tagged as being sorted
  def minOption[A](a: List[A] @@ Sorted): Option[A] = Sorted.unwrap(a).headOption

  implicit val ord = implicitly[Order[Option[Int]]].toScalaOrdering
  assert(minOption(sortList(List(3,2,1,5,3))) === Some(1))

  // we can also use pattern matching:
  def minOption_v2[A]: List[A] @@ Sorted ⇒ Option[A] = {
    case Sorted(list) ⇒ list.headOption
  }
}

Other Scala examples (source code examples)

Here is a short list of links related to this Scala TagUsage.scala source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.