Skip to content

Commit

Permalink
Add reverseo
Browse files Browse the repository at this point in the history
  • Loading branch information
jsyeo committed Apr 22, 2019
1 parent 4e92458 commit d094c23
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 11 deletions.
34 changes: 23 additions & 11 deletions src/main/scala/MuKanren.scala
Original file line number Diff line number Diff line change
Expand Up @@ -125,30 +125,26 @@ object MuKanren {

def assignVariables(elems: (Variable, Term)*): State = State(this.variables, this.values ++ Map(elems: _*), this.counter)

def valueOf(candidate: Term): Term = {
def valueOf(candidate: Term): Term =
candidate match {
case _: Variable => values.get(candidate).map(valueOf).getOrElse(candidate)
case Pair(f, s) => Pair(valueOf(f), valueOf(s))
case _ => candidate
}
}

def occursCheck(x: Term, y: Term): Boolean = (x, y) match {
case (_: Integer, _) | (_, _: Integer) | (Nil, _) | (_, Nil) => false
case (_: Variable, _: Variable) => x == y
case (Pair(x1, x2), _) => occursCheck(x1, y) || occursCheck(x2, y)
case (_, Pair(y1, y2)) => occursCheck(x, y1) || occursCheck(x, y2)
case _ => occursCheck(x, y)
def occursCheck(variable: Variable, y: Term): Boolean = valueOf(y) match {
case yVar: Variable => variable == yVar
case Pair(f, s) => occursCheck(variable, f) || occursCheck(variable, s)
case _ => false
}

def unify(x: Term, y: Term): Option[State] = {
val (xVal, yVal) = (valueOf(x), valueOf(y))

(xVal, yVal) match {
case _ if xVal == yVal => Some(this)
case _ if occursCheck(xVal, yVal) => None
case (xVal: Variable, _) => Some(assignVariables(xVal -> yVal))
case (_, yVal: Variable) => Some(assignVariables(yVal -> xVal))
case (xVal: Variable, _) => if(occursCheck(xVal, yVal)) None else Some(assignVariables(xVal -> yVal))
case (_, yVal: Variable) => if(occursCheck(yVal, xVal)) None else Some(assignVariables(yVal -> xVal))
case (Pair(f1, s1), Pair(f2, s2)) => unify(f1, f2).flatMap(state => state.unify(s1, s2))
case _ => None
}
Expand Down Expand Up @@ -179,5 +175,21 @@ object MuKanren {
}
)
}

// reverse [] = []
// reverse (x::xs) = append (reverse xs) [x]
def reverseo(a: Term, b: Term): Goal = {
Goal.either(
Goal.both(
Goal.eq(a, MyList()),
Goal.eq(b, MyList())),
Goal.fresh { (firstA, restA, reversed) =>
Goal.both(
Goal.eq(a, Pair(firstA, restA)),
Goal.both(
reverseo(restA, reversed),
appendo(reversed, MyList(firstA), b)))
})
}
}

12 changes: 12 additions & 0 deletions src/test/scala/MuKanrenTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -171,4 +171,16 @@ class MuKanrenTest extends FlatSpec with Matchers {
results should contain(List(MyList(Integer(1), Integer(2), Integer(3)), MyList(Integer(4))))
results should contain(List(MyList(Integer(1), Integer(2), Integer(3), Integer(4)), Nil))
}

"reverseo" should "reverse a list" in {
val reverse123 = Goal.fresh {x => reverseo(MyList(Integer(1), Integer(2), Integer(3)), x)}
val states = reverse123.pursueIn(State())
states.head.results(1) should be(List(MyList(Integer(3), Integer(2), Integer(1))))
}

"reverseo" should "relate the output with its input" in {
val goal = Goal.fresh {x => reverseo(MyList(Integer(1), Integer(2), Integer(3)), MyList(Integer(3), Integer(2), x))}
val states = goal.pursueIn(State())
states.head.results(1) should be(List(Integer(1)))
}
}

0 comments on commit d094c23

Please sign in to comment.