Created
December 10, 2013 23:53
-
-
Save johnynek/7902589 to your computer and use it in GitHub Desktop.
Weak Reference is a monad (h/t https://twitter.com/J_ )
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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