From d516b3efe6d691c2ffca2c0a0d8c66b81e76e989 Mon Sep 17 00:00:00 2001 From: Mirco Dotta <mirco.dotta@gmail.com> Date: Wed, 8 Jul 2009 12:45:31 +0000 Subject: [PATCH] Examples from Matcheck. --- tests/plugin/LambdaEvaluator.scala | 91 +++++++++++++++++++++++++++ tests/plugin/PropositionalLogic.scala | 59 +++++++++++++++++ 2 files changed, 150 insertions(+) create mode 100644 tests/plugin/LambdaEvaluator.scala create mode 100644 tests/plugin/PropositionalLogic.scala diff --git a/tests/plugin/LambdaEvaluator.scala b/tests/plugin/LambdaEvaluator.scala new file mode 100644 index 000000000..8f0686f76 --- /dev/null +++ b/tests/plugin/LambdaEvaluator.scala @@ -0,0 +1,91 @@ +package plugin + +/** ================================================= + * Evaluator for the untyped lambda calculus using + * The de Bruijn notation for lambda-terms + * ================================================= + */ + +import funcheck.lib.Specs._ + +object LambdaEvaluator { + /** ================================================= + * Lambda Terms for Untyped Lambda Calculus + * ================================================= + */ + @generator + sealed abstract class Term + case class App(val t1: Term, val t2: Term) extends Term + case class Abstr(val t: Term) extends Term + case class Var(val index: Int) extends Term + case class Const() extends Term + + def reduce(that: Term): Term = { + if(reduceCallByValue(that) == that) + that + else + reduce(reduceCallByValue(that)) + } + + def isValue(that: Term): Boolean = that.isInstanceOf[Abstr] + + def reduceCallByValue(that: Term): Term = that match { + + case App(Abstr(t1:Term),v2:Term) if isValue(v2) => + subst(t1,1,v2) + + case App(v1: Abstr, t2: Term) if !isValue(t2) => + App(v1, reduceCallByValue(t2)) + + case App(t1: Term, t2: Term) if !isValue(t1) => + App(reduceCallByValue(t1), t2) + + case Abstr(t1: Term) => Abstr(reduceCallByValue(t1)) + case Var(_) => that + case Const() => that + } + + def subst(t: Term, index: Int, s: Term): Term = t match { + case Const() => t + + case Var(y) => + if (y == index) { s } else { t } + + case Abstr(t1: Term) => Abstr(subst(t1,index+1,s)) + + case App(t1: Term, t2: Term) => + App(subst(t1,index,s), subst(t2,index,s)) + } + + // this fails (which is correct!) + // counter-example: p._1=Var(13) , p._2 = 13 , p._3 = Const() + //forAll[(Term,Int,Term)]{p => p._1 == subst(subst(p._1,p._2,p._3),p._2,p._1)} + + + def main(args: Array[String]) = { + /** ================================================= + * \\z. (\\y. y (\\x. x)) (\\x. z x) + * is in de Bruijn notation + * \\ (\\ 1 (\\ 1)) (\\ 2 1) + * and it evaluates to: + * \\ 2 (\\ 1) that is \\z. z (\\x. x) + * ================================================= + */ + assert( + reduce( + Abstr( + App( + Abstr(App(Var(1), Abstr(Var(1)))), + Abstr(App(Var(2),Var(1))) + ) + ) + ) + == + Abstr(App(Var(2), Abstr(Var(1)))) + ) + } + +} + + + diff --git a/tests/plugin/PropositionalLogic.scala b/tests/plugin/PropositionalLogic.scala new file mode 100644 index 000000000..a32ba3871 --- /dev/null +++ b/tests/plugin/PropositionalLogic.scala @@ -0,0 +1,59 @@ +package plugin + +import funcheck.lib.Specs._ + +object PropositionalLogic { + + + + // This crash because there are too many non-terminals, and the automatically + // injected generator may end up generating infinite formulas, which produce + // java.lang.StackOverflowError + @generator + sealed abstract class Formula + case class And(left: Formula, right: Formula) extends Formula + case class Or(left: Formula, right: Formula) extends Formula + case class Neg(f: Formula) extends Formula + case class True() extends Formula + case class False() extends Formula + case class Imply(left: Formula,right: Formula) extends Formula + + + + + def desugar(f: Formula): Formula = f match { + case True() => f + case False() => f + case And(left,right) => And(desugar(left),desugar(right)) + case Or(left,right) => Or(desugar(left),desugar(right)) + case Neg(f) => Neg(desugar(f)) + case Imply(left,right) => Or(Neg(desugar(left)),desugar(right)) + } + + def isDesugared(f: Formula): Boolean = f match { + case And(left,right) => isDesugared(left) && isDesugared(right) + case Or(left,right) => isDesugared(left) && isDesugared(right) + case Neg(f) => isDesugared(f) + case True() => true + case False() => true + case i: Imply => false + } + + forAll{f : Formula => isDesugared(f) ==> desugar(f) == f } + // the above forAll invariant replaces the below somewhat cummbersome Matcheck spec + /** Type refinement: A desugarized formula does not contain an Imply node. + This condition must hold recursively over the whole tree + */ + /* constraint (\forall f. f \in DesugaredFormula <--> + ( f \in Tru | + f \in Flse | + (f \in Neg & Neg_getField_f(f) \in DesugaredFormula) | + (f \in IOr & IOr_getField_left(f) \in DesugaredFormula & IOr_getField_right(f) \in DesugaredFormula) | + (f \in IAnd & IAnd_getField_left(f) \in DesugaredFormula & IAnd_getField_right(f) \in DesugaredFormula) + )) + */ + + def main(args: Array[String]) = + assert(isDesugared(desugar(Imply(Imply(True(),False()),False())))) +} + -- GitLab