Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala - Prefix Unary Operators

I've recently given Scala a second chance, and started with the project I always implement (in functional or pseudo-functional languages): an automated reasoner for propositional logic (and later predicate logic).

Now, I've tried to get the notation of propositional logic in the language itself as pretty as possible, and I've gotten this far - with an implicit conversion (String -> Atom):

("A" and "B") implies "C"

The functions "and" and "implies" (and "or" and "equivalent") are simple methods that call the relevant case class constructor. However, when implementing "not", I get stuck with either of the two following notations:

("A" and "B").not
Not("A" and "B")

Is there a way to trick Scala into accepting the desired:

not("A" and "B")

Preferrably without renaming the class "Not" to "not", because I might like to call it "¬" or something else, in th future.

like image 289
wen Avatar asked Sep 06 '10 12:09

wen


4 Answers

I noticed on this answer to another question that it appears that one can prefix the operator name with unary_ to achive what you are trying to do. (See unary_!.)

Edit: this article confirms the syntax.

like image 74
Paul Ruane Avatar answered Oct 06 '22 23:10

Paul Ruane


You can define not as a method on a singleton object, like this:

object Logic {
  def not(x:Expr) = Not(x)
}
import Logic._
not("A" and "B")

(Where Expr is supposed to be the common superclass of And, Or, Not and Atom)

Edit: Here's an example of how this could be used with only a single import:

object Logic {
  abstract class Expr {
    def and(e: Expr) = Conjunction(this, e)
    def or(e: Expr) = Disjunction(this, e)
    def implies(e: Expr) = Implication(this, e)
  }
  case class Conjunction(e1: Expr, e2: Expr) extends Expr
  case class Disjunction(e1: Expr, e2: Expr) extends Expr
  case class Implication(e1: Expr, e2: Expr) extends Expr
  case class Negation(e: Expr) extends Expr
  case class Atom(name: String) extends Expr

  def not(e: Expr) = Negation(e)
  implicit def string2atom(str: String) = Atom(str)
}

// use site
import Logic._
not("A" and "B") implies (not("A") or not("B"))
like image 35
sepp2k Avatar answered Oct 06 '22 22:10

sepp2k


Why Not instead of not? There's nothing to stop you from doing this:

object not {
  def apply(expr: T) = ...
}

And then use not("A" and "B").

like image 32
Daniel C. Sobral Avatar answered Oct 06 '22 23:10

Daniel C. Sobral


As of Feb 2014, I think the cleanest way to define a prefix'ish not operation on expressions, while avoiding all sorts of extra cruft/wrapping, would be to declare the function directly in the package scope, together with all your other functions, classes, types etc: This is done by defining a package object (Scala doesn't allow you to just put functions at the root level of the .scala file (I'd love to learn why—is it just to follow Java's footsteps?)).

package org.my.logiclib

implicit class Atom(s: String) { ... }
class MyType1
class MyType2

object `package` {
  def not(expr: Expr) = ...
}

this way, doing import org.my.logiclib._ will import everything, including not().

The above is the same as

package org.my

package logiclib {
  implicit class Atom ...
  ...

  def not(expr: Expr) = ...
}
like image 34
Erik Kaplun Avatar answered Oct 06 '22 23:10

Erik Kaplun