Skip to content

Instantly share code, notes, and snippets.

@johnynek
Created December 10, 2013 23:53
Show Gist options
  • Save johnynek/7902589 to your computer and use it in GitHub Desktop.
Save johnynek/7902589 to your computer and use it in GitHub Desktop.
Weak Reference is a monad (h/t https://twitter.com/J_ )
import java.lang.ref.WeakReference
/** An option-like type that doesn't keep
* the pointed item in scope
*/
trait WeakRef[+T] {
// If the reference is still live, return it, else None
def toOption: Option[T]
// If either reference is dead, return Empty, else give the live ref
def flatMap[U](fn: T => WeakRef[U]): WeakRef[U] =
toOption.map { t => fn(t) }.getOrElse(Empty)
}
object Empty extends WeakRef[Nothing] {
def toOption = None
override def flatMap[U](fn: Nothing => WeakRef[U]): WeakRef[U] = Empty
}
class WeakRefInst[+T](ref: T) extends WeakRef[T] {
private val wref: WeakReference[_] = new WeakReference(ref)
def toOption: Option[T] = Option(wref.get.asInstanceOf[T]) // variance hack for Java
}
/**
* Here is one way to encode the Monad type-class in scala:
*/
trait Monad[M[_]] {
// return in haskell
def pure[T](t: T): M[T]
// bind in haskell, selectMany in C#
def flatMap[T,U](m: M[T])(fn: T => M[U]): M[U]
// not part of the laws, but you can derive from the above
def map[T,U](m: M[T])(fn: T => U): M[U] = flatMap(m) { t => pure(fn(t)) }
}
/** For typeclasses we often do this pattern of putting their methods
* in the object so we can call them with Monad.pure or Monad.flatMap below
*/
object Monad {
def pure[M[_],T](t: T)(implicit monad: Monad[M]): M[T] = monad.pure(t)
def flatMap[M[_],T,U](m: M[T])(fn: T => M[U])(implicit monad: Monad[M]): M[U] =
monad.flatMap(m)(fn)
def map[M[_],T,U](m: M[T])(fn: T => U)(implicit monad: Monad[M]): M[U] =
monad.map(m)(fn)
}
object WeakRef {
implicit def monad: Monad[WeakRef] = new Monad[WeakRef] {
def pure[T](t: T) = new WeakRefInst(t)
def flatMap[T,U](m: WeakRef[T])(fn: T => WeakRef[U]) = m.flatMap(fn)
}
}
val a = "hey"
val res = Monad.pure[WeakRef,String](a)
.flatMap { exists => Monad.pure[WeakRef,String](exists + " monadic world") }
println(res.toOption)
//Some(hey monadic world)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment