user2616002
user2616002

Reputation: 15

Clojure pattern matching on argument's class

I have a simple program written in Scala, which operates logical expressions as members of the case classes, which extend Expr trait (code below). Then I have some functions that simply pattern match on the class of the argument and perform some actions.

sealed trait Expr 

case class Implication(lhs: Expr, rhs: Expr) extends Expr {
  override def toString = "(" + lhs.toString + "->" + rhs.toString + ")"
}

case class Negation(body: Expr) extends Expr {
  override def toString = "!" + body.toString
}

case class Conj(lhs: Expr, rhs: Expr) extends Expr {
  override def toString = "(" + lhs.toString + "&" + rhs.toString + ")"
}

case class Disj(lhs: Expr, rhs: Expr) extends Expr {
  override def toString = "(" + lhs.toString + "|" + rhs.toString + ")"
}

case class Variable(name: String) extends Expr {
  override def toString = name
}

Example of a function:

def substitute(map: m.HashMap[String, Expr]): Expr = this match {
    case Variable(name) => map.getOrElse(name, this)
    case Conj(a, b) => Conj(a.substitute(map), b.substitute(map))
    case Disj(a, b) => Disj(a.substitute(map), b.substitute(map))
    case Implication(a, b) => Implication(a.substitute(map), b.substitute(map))
    case Negation(a) => Negation(a.substitute(map))
}

The question is: How can I imitate the same functionality in Clojure? Basically all I want is to distinguish the class of a function argument and pattern match on it, preferably with guards.

Upvotes: 0

Views: 466

Answers (2)

edbond
edbond

Reputation: 3951

The problem can be solved using if, cond, condp or other conditional operators. To find class use class or type functions.

Use zippers to walk and edit map tree. http://ravi.pckl.me/short/functional-xml-editing-using-zippers-in-clojure/

There are many ways to tag entries in map:

  • {:tag :Variable :value 42}
  • (defrecord Variable [value])

Take a look at enlive for inspiration - https://github.com/cgrand/enlive

Upvotes: 0

Greggo
Greggo

Reputation: 181

It looks like the core of an expression is that it is a recursive data structure with tagged nodes. You could build the expression data structure from an example of a Red-Black tree in Clojure.

The key insight is that the expression tree is represented with nested plain Clojure datatypes. In the red-black example, each node is a 4-tuple [type left-child value right-child]. In your example, it might make more sense to represent an expression as [type & children].

In either case, core.match uses pattern matching against plain Clojure types like vectors and keywords. You could probably port your expression match 1-to-1.

Upvotes: 0

Related Questions