Scala Maybe

I wrote a Maybe (a lazy Option[T]) that I can use in Scala.


Scala Maybe

… because I wanted a lazy variant of Option[+T]. I had a use case in mind at the time, but, since then; I’ve taken another approach.

Since writing this, I’ve found an explanation of Monads that “groks” with me and multiple other places where “lazy is better” and I preffer (my) Maybe[T] over Option[T].

package peterlavalle

/**
	* like Option[+A] but lazy
	*/
trait Maybe[+T] {

	/**
		* however we're implemented; ensure that any operations leading up to now are only called "once"
		*/
	def cache: Maybe[T]

	/**
		* Apply some operation to the value, and, return a new monad.
		*
		* this is (more likely) lazy
		**/
	def call[V](operation: T => V): Maybe[V]

	/**
		* bind it like a monad ... but ... not lazy
		*/
	def bind[V](operation: T => Maybe[V]): Maybe[V]

	/**
		* if we're empty; produce the other one
		*/
	def otherwise[E >: T](them: => Maybe[E]): Maybe[E]

	/**
		* produce/convert this to an eager Option[T] in preparation for reading or matching it.
		*
		* This is (kind of) a hack
		*/
	def some: Option[T]

	final def |[V](that: T => Maybe[V]): Maybe[V] = bind(that)

	final def ![V](that: T => V): Maybe[V] = call(that)

	final def ?[E >: T](them: => Maybe[E]): Maybe[E] = otherwise(them)
}

object Maybe {

	def apply[T](read: => T): Maybe[T] =
		new Maybe[T] {
			override lazy final val cache: Maybe[T] = {
				lazy val data: T = read
				apply(data)
			}

			override lazy final val some: Option[T] = Some(read)

			override final def otherwise[E >: T](them: => Maybe[E]): Maybe[E] = this

			override final def bind[V](map: T => Maybe[V]): Maybe[V] =
				map(read)

			override final def call[V](map: T => V): Maybe[V] =
				Maybe {
					map(read)
				}
		}

	def unapply[T](arg: Maybe[T]): Option[T] = arg.some

	case object Nope extends Maybe[Nothing] {
		override final val cache: Maybe[Nothing] = this

		override final val some: Option[Nothing] = None

		override final def bind[V](map: Nothing => Maybe[V]): Maybe[V] = Nope

		override final def call[V](map: Nothing => V): Maybe[V] = Nope

		override final def otherwise[E >: Nothing](them: => Maybe[E]): Maybe[E] = them
	}
}
comments powered by Disqus
Peter LaValle avatar
Peter LaValle
Any links probably include affiliate ids for that sweet sweet kickback - and some programs require that I tell you. The contents of this blog are likely unrelated - as they include games, paints, and build tools.