Last active
June 20, 2017 11:28
-
-
Save dszakallas/c595fe23b5a1a960f997024cb63a3fff to your computer and use it in GitHub Desktop.
Kleene logic in Scala
This file contains hidden or 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
/* Copyright 2017 David Szakallas, MIT License */ | |
/* | |
Kleene logic represented on 2 bits, implemented as a value class. | |
00: false | |
{01,10}: null | |
11: true | |
*/ | |
class Kleene(val value: Int) extends AnyVal { | |
def &&(rhs: Kleene): Kleene = new Kleene(value & rhs.value) | |
def ||(rhs: Kleene): Kleene = new Kleene(value | rhs.value) | |
def unary_! : Kleene = new Kleene(value ^ 0x3) | |
def ==(rhs: Kleene): Kleene = !(this != rhs) | |
def !=(rhs: Kleene): Kleene = { | |
val first = value ^ rhs.value | |
val second = value ^ rhs.flippedValue | |
// MSbs are ANDed, LSbs are ORed | |
new Kleene((first & second & 0x2) | ((first | second) & 0x1)) | |
} | |
def isFalse: Boolean = value == 0x0 | |
def isTrue: Boolean = value == 0x3 | |
def isNull: Boolean = value == 0x1 || value == 0x2 | |
private def flippedValue: Int = (value & 0x1) << 1 | (value & 0x2) >> 1 | |
implicit def toOption: Option[Boolean] = { | |
if (this.isTrue) { | |
Some(true) | |
} else if (this.isFalse) { | |
Some(false) | |
} else { | |
None | |
} | |
} | |
} | |
object Kleene { | |
def False: Kleene = new Kleene(0) | |
def Null: Kleene = new Kleene(1) | |
def True: Kleene = new Kleene(3) | |
implicit def fromBoolean(b: Boolean): Kleene = if (b) True else False | |
implicit def fromOption[B <: Boolean](o: Option[B]): Kleene = o match { | |
case Some(b) => fromBoolean(b) | |
case _ => Null | |
} | |
implicit class OptionBooleanToKleene[B <: Boolean](val opt: Option[B]) extends AnyVal { | |
def toKleene: Kleene = fromOption(opt) | |
} | |
} |
This file contains hidden or 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
/* Copyright 2017 David Szakallas, MIT License */ | |
import simulacrum.{op, typeclass} | |
@typeclass trait GenKleeneLike[-A] { | |
@op("|=|") def eq(x: A, y: A): Option[Boolean] | |
@op("|!|") def ne(x: A, y: A): Option[Boolean] | |
} | |
object GenKleeneLike { | |
class GenKleeneLikeForOption[Opt <: Option[Any]] extends GenKleeneLike[Opt] { | |
override def eq(x: Opt, y: Opt): Option[Boolean] = | |
for { _x <- x; _y <- y } yield _x == _y | |
override def ne(x: Opt, y: Opt): Option[Boolean] = | |
for { _x <- x; _y <- y } yield _x != _y | |
} | |
implicit def genKleeneLikeForOption[Opt <: Option[Any]]: GenKleeneLike[Opt] = new GenKleeneLikeForOption[Opt] | |
} | |
@typeclass trait KleeneLike[-A] extends GenKleeneLike[A] { | |
@op("&&") def and(x: A, y: A): Option[Boolean] | |
@op("||") def or(x: A, y: A): Option[Boolean] | |
@op("unary_!") def not(x: A): Option[Boolean] | |
} | |
object KleeneLike { | |
import GenKleeneLike.GenKleeneLikeForOption | |
class KleeneLikeForOptionBoolean[Opt <: Option[Boolean]] extends GenKleeneLikeForOption[Opt] with KleeneLike[Opt] { | |
override def and(x: Opt, y: Opt): Option[Boolean] = (x, y) match { | |
case (Some(true), Some(true)) => Some(true) | |
case (Some(false), _) => Some(false) | |
case (_, Some(false)) => Some(false) | |
case _ => None | |
} | |
override def or(x: Opt, y: Opt): Option[Boolean] = (x, y) match { | |
case (Some(false), Some(false)) => Some(false) | |
case (Some(true), _) => Some(true) | |
case (_, Some(true)) => Some(true) | |
case _ => None | |
} | |
override def not(x: Opt): Option[Boolean] = | |
for { _x <- x } yield !_x | |
} | |
implicit def optionBooleanKleeneLike[OptB <: Option[Boolean]]: KleeneLike[OptB] = new KleeneLikeForOptionBoolean[OptB] | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment