2010-09-06 10 views
9

Recientemente le he dado a Scala una segunda oportunidad, y comencé con el proyecto que siempre implementé (en lenguajes funcionales o pseudo-funcionales): un razonador automático para lógica proposicional (y posterior lógica de predicados).Scala - Prefijo Unary Operators

Ahora, he tratado de conseguir la notación de la lógica proposicional en el lenguaje mismo es tan bonita como sea posible, y he llegado hasta aquí - con una conversión implícita (String -> Atom):

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

Las funciones "y" e "implica" (y "o" y "equivalente") son métodos simples que llaman al constructor de la clase de caso relevante. Sin embargo, al aplicar "no", se queda bloqueado con cualquiera de las dos siguientes anotaciones:

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

¿Hay una manera de engañar a Scala para que acepten la deseada:

not("A" and "B") 

Preferiblemente sin cambiar el nombre de la clase "No" a "no", porque me gustaría llamarlo "¬" o algo más, en el futuro.

Respuesta

4

A partir de febrero de 2014, creo que la forma más limpia de definir una operación prefix'ish not en las expresiones, evitando todo tipo de cruxt/wrapping adicional, sería declarar la función directamente en el alcance del paquete, junto con todos sus otras funciones, clases, tipos, etc.: esto se hace definiendo un objeto de paquete (Scala no le permite simplemente poner funciones en el nivel raíz del archivo .scala) (me encantaría saber por qué, ¿es solo para seguir? Los pasos de Java?)).

package org.my.logiclib 

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

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

esta manera, haciendo import org.my.logiclib._ importará todo, incluyendo not().

Lo anterior es la misma que

package org.my 

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

    def not(expr: Expr) = ... 
} 
14

Puede definir not como un método en un objeto único, de esta manera:

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

(Donde Expr se supone que es la superclase común de And, Or, Not y Atom)

Editar : Aquí hay un ejemplo de cómo esto se puede usar con una sola importación:

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")) 
+0

Gracias, yo no sabía que podía usar "importaciones estáticas" en Scala - esto me dejaría con una importación obligatoria en cada página, sin embargo, que - en conjunto con la conversión implícita sería una gran cantidad de código adicional para cada uso. – wen

+2

@Dennetik: si simplemente pones todo en el objeto Logic, 'import Logic._' es todo lo que necesitas para usar tus clases. – sepp2k

+1

No había pensado en eso, todavía tengo que acostumbrarme a la libertad de Scala, en comparación con Java ... – wen

19

Me di cuenta en this answer a otra pregunta que parece que uno puede anteponer el nombre del operador con unary_ para lograr lo que está tratando de hacer. (Consulte unary_!.)

Edición: this article confirma la sintaxis.

+1

Sin embargo, eso no funciona con nombres de operadores personalizados. Es decir. no puede definir 'unary_not' para obtener un prefijo" not "-operator. – sepp2k

+16

Específicamente 'prefix_' solo funciona con'! ',' ~ ',' + 'Y' -'. – sepp2k

+1

@ sepp2k: Gracias, no me di cuenta de esta sutileza. Esta restricción parece un poco vergonzosa (y completamente arbitraria). –

8

¿Por qué Not en lugar de not? No hay nada que le impida hacer esto:

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

y luego usar not("A" and "B").

+0

¿por qué todos siempre encuentran formas de colocar funciones directamente en paquetes utilizando objetos de paquete ... –

+1

@ErikAllik Porque en 2010 no había objetos de paquete. –

+0

¡Buen punto! No me di cuenta de que ... Gracias :) P.S. sin embargo, ¿usarías uno hoy para definir 'not (expr: T)'? –