GitXplorerGitXplorer
t

instancez

public
9 stars
0 forks
0 issues

Commits

List of commits on branch master.
Unverified
982f23dddd545692734e341fa3d9120258779680

Playing with StateT monad transformer for parsing.

ttravisbrown committed 12 years ago
Unverified
bd9395c4c333edf31c521c58b2beb34d34c0d8ef

Minor edits.

ttravisbrown committed 12 years ago
Unverified
803cd6586f6167e480c4d87dc4599255f03b85c5

Added test.

ttravisbrown committed 12 years ago
Unverified
8d3f6bb19efe28776b03dd2d2f5740048f62ecab

Minor changes to wording.

ttravisbrown committed 12 years ago
Unverified
cb0dc3093670749d951ae7a359a37fc45b65f5a9

Filling out examples a bit.

ttravisbrown committed 12 years ago
Unverified
67c675e3be2ebc06f6267b26802dbc15912e50e3

Added full and empty.

ttravisbrown committed 12 years ago

README

The README file for this repository.

Instancez

This library is a collection of Scalaz 7 type class instances for various classes from other Scala and Java libraries.

It doesn't aim for comprehensiveness, and is likely to remain a grab bag of things that the author (Travis Brown) finds useful.

The following are a few of the libraries that will be represented initially:

See this Stack Overflow question by the author for more background.

Shapeless

The org.instancez.shapeless package contains the following instances:

  • Monoid for HLists (when they're made up of monoids)
  • Monoid for things that are isomorphic to HList (most relevantly case classes)

Shapeless usage examples

First for imports and set up:

import org.instancez.shapeless._
import scalaz._, std.list._, std.option._, std.string._, syntax.monoid._

case class Foo(name: Option[String], things: List[Int])

implicit val fooIso = shapeless.Iso.hlist(Foo.apply _, Foo.unapply _)

And now we have a monoid instance for Foo:

scala> val a = Foo(Some("bar"), 1 :: Nil)
a: Foo = Foo(Some(bar),List(1))

scala> val b = Foo(Some("baz"), 2 :: 3 :: Nil)
b: Foo = Foo(Some(baz),List(2, 3))

scala> a |+| b
res0: Foo = Foo(Some(barbaz),List(1, 2, 3))

We can of course change the behavior of the monoid instance for the case class by changing the monoid instances for the types of its members. For example, if we want to use the monoid as a kind of update operation for the name member, we can put the "last" monoid instance for Option into scope.

implicit def lastOptionMonoid[A] = new Monoid[Option[A]] {
  def zero = None
  def append(x: Option[A], y: => Option[A]) = y orElse x
}

Now we can "replace" the name value in a Foo by adding another Foo with a Some for its name (while a None leaves it unchanged):

scala> a |+| Foo(Some("baz"), Nil)
res1: Foo = Foo(Some(baz),List(1))

scala> a |+| Foo(None, Nil)
res2: Foo = Foo(Some(bar),List(1))

It might be better just to make name a LastOption in this case, though.

Lift

The org.instancez.lift package contains the following instances:

  • Monad for Box

Box is essentially part of the way between an Option and an Either, and a lot of the machinery that Scalaz provides for these types is useful for Box as well.

The package also includes full and empty methods, on the model of Scalaz's some and none.

Lift usage examples

Imports again:

import net.liftweb.common.{ Box, Full }
import org.instancez.lift._
import scalaz._, std.list._, syntax.traverse._

And now we've got a monad for Box, which means we also have an applicative functor for Box, which means we can sequence a list of boxes:

scala> val boxen: List[Box[Int]] = Full(1) :: Full(2) :: Full(3) :: Nil
boxen: List[net.liftweb.common.Box[Int]] = List(Full(1), Full(2), Full(3))

scala> boxen.sequence
res0: net.liftweb.common.Box[List[Int]] = Full(List(1, 2, 3))

Or, more concisely with full:

scala> List(full(1), full(2), full(3)).sequence
res1: net.liftweb.common.Box[List[Int]] = Full(List(1, 2, 3))

This won't compile if we use Full, since the inferred type of the list would be List[Full[Int]], and we of course don't have a monad for Full.

Dispatch

The org.instancez.dispatch package contains the following instances:

  • Monad for Promise

The monad instance isn't necessarily terribly useful on its own, but it allows us for example to use Scalaz's EitherT monad transformer to work with things of type Promise[Either[Throwable, A]] (a common idiom) monadically.

Dispatch usage examples

Suppose we've got a Promise representing something like some JSON containing an OAuth token:

import dispatch._

val tokenJson: Promise[String] = Promise("""
  { "access_token": "61a6efeaf1423aefefb3696dfaf684eb" }
""")

This is a simplified example—in real life this would of course come from the Internet.

Now we want to parse this and grab the token itself. I'm using the standard library JSON parser here only for the sake of having a more convenient complete working example—I know it's hideous. All that really matters here is the type of token.

import org.instancez.dispatch._
import scala.util.parsing.json.JSON.parseFull
import scalaz._

type EitherPromise[A] = EitherT[Promise, Throwable, A]

val tokenP: EitherPromise[String] = EitherT.fromEither(tokenJson.map(
  parseFull(_).flatMap(
    _.asInstanceOf[Map[String, Any]].get("access_token")
  ).asInstanceOf[Option[String]].toRight(
    new RuntimeException("Invalid JSON response.")
  )
))

Now we want to use this token to construct a new request and end up with another promise of the same type:

val resultP: EitherPromise[String] = tokenP.flatMap { token =>
  val stuff = url("https://example.com/api/stuff/") <:< Map(
    "Authorization" -> ("Bearer " + token)
  )

  EitherT.fromEither(Http(stuff OK as.String).either)
}

We could go on and parse or otherwise process the response inside the EitherPromise monad, but for this example I'll stop here.

resultP.run().toEither match {
  case Right(content)        => println("Success! " + content)
  case Left(StatusCode(404)) => println("Not found!")
  case Left(e)               => println("Something went wrong! " + e)
}