Scala - Префикс Унарные Операторы - PullRequest
10 голосов
/ 06 сентября 2010

Я недавно дал Scala второй шанс и начал с проекта, который я всегда реализую (на функциональных или псевдо-функциональных языках): автоматизированный анализ логики высказываний (и более поздней логики предикатов).

Теперь я попытался сделать нотацию логики высказываний в самом языке настолько красивой, насколько это возможно, и дошел до этого - неявным преобразованием (String -> Atom):

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

Функции "и" и "подразумевает" (и "или" и "эквивалент") являются простыми методами, которые вызывают соответствующий конструктор класса case. Тем не менее, при реализации «нет», я застрял с одной из двух следующих обозначений:

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

Есть ли способ обмануть Скалу, чтобы он принял желаемое:

not("A" and "B")

Желательно без переименования класса «Не» в «не», потому что я хотел бы назвать его «¬» или как-нибудь еще в будущем.

Ответы [ 4 ]

22 голосов
/ 06 сентября 2010

Я заметил на этот ответ на другой вопрос, что кажется, что можно добавить префикс оператора к unary_, чтобы достичь того, что вы пытаетесь сделать. (См. unary_!.)

Редактировать: эта статья подтверждает синтаксис.

14 голосов
/ 06 сентября 2010

Вы можете определить not как метод для одноэлементного объекта, например:

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

(где Expr должен быть общим суперклассом And, Or,Not и Atom)

Редактировать: Вот пример того, как это можно использовать только с одним импортом:

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"))
8 голосов
/ 06 сентября 2010

Почему Not вместо not?Ничто не мешает вам сделать это:

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

А затем используйте not("A" and "B").

5 голосов
/ 13 февраля 2014

По состоянию на февраль 2014 года, я думаю, что самым чистым способом определения операции prefix'ish not для выражений, избегая при этом всех видов лишних запутываний / переносов, было бы объявление функции непосредственно в области действия пакета вместе с все остальные функции, классы, типы и т. д. Это делается путем определения объекта пакета (Scala не позволяет просто помещать функции на корневой уровень файла .scala (хотелось бы узнать, почему - так ли это просто следовать по стопам Java?)).

package org.my.logiclib

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

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

таким образом, import org.my.logiclib._ импортирует все, включая not().

Выше указано то же, что и

package org.my

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

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