-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
8200cab
commit 553741f
Showing
4 changed files
with
185 additions
and
0 deletions.
There are no files selected for viewing
31 changes: 31 additions & 0 deletions
31
core/src/main/scala/pl/writeonly/catculus/adt/calculus/Fruit.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package pl.writeonly.catculus.adt.calculus | ||
|
||
import pl.writeonly.catculus.adt.calculus.Combinator.generateC | ||
import pl.writeonly.catculus.adt.tree.BinaryTree | ||
import pl.writeonly.catculus.adt.tree.BinaryTree.{Leaf, Node} | ||
import spire.math.Natural | ||
|
||
object Fruit { | ||
|
||
def generateFruitBT(tree: BinaryTree[Fruit]): String = tree match { | ||
case Leaf(a) => generateFruit(a) | ||
case Node(a, b) => s"`${generateFruitBT(a)} ${generateFruitBT(b)}" | ||
} | ||
|
||
def generateFruit(f: Fruit): String = f match { | ||
case Com(c) => generateC(c) | ||
case Nat(n) => s"$n " | ||
case Succ => ":" | ||
} | ||
|
||
def fromLambda(l: Lambda): BinaryTree[Fruit] = l match { | ||
case Lambda.Com(c) => Leaf(Com(c)) | ||
case Lambda.App(f, x) => Node(fromLambda(f), fromLambda(x)) | ||
} | ||
|
||
final case class Com(c: Combinator) extends Fruit | ||
final case class Nat(n: Natural) extends Fruit | ||
final case object Succ extends Fruit | ||
} | ||
|
||
sealed trait Fruit |
72 changes: 72 additions & 0 deletions
72
core/src/main/scala/pl/writeonly/catculus/adt/calculus/Lambda.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
package pl.writeonly.catculus.adt.calculus | ||
|
||
import cats.data.NonEmptyList | ||
import pl.writeonly.catculus.Extras.fix | ||
import pl.writeonly.catculus.adt.tree.BinaryTree | ||
import pl.writeonly.catculus.adt.tree.BinaryTree._ | ||
import spire.math.Natural | ||
|
||
object Lambda { | ||
|
||
// val thrushVariable: Lambda = Var(";") | ||
val vireoVariable: Lambda = Var(",") | ||
val nilVariable: Lambda = Var(".") | ||
val succVariable: Lambda = Var(":") | ||
val zeroVariable: Lambda = Var("0") | ||
val falseVariable: Lambda = Var("false") | ||
val trueVariable: Lambda = Var("true") | ||
|
||
// def wrapAppThrush(name: String, l1: Lambda, l2: Lambda): Lambda = App(thrushVariable, App(l1, Abs(name, l2))) | ||
def wrapAppVireoApp(l1: Lambda, l2: Lambda): Lambda = App(App (vireoVariable, l1), l2) | ||
def appSuccVariable(l: Lambda): Lambda = App(succVariable, l) | ||
|
||
def generate(l: Lambda): String = l match { | ||
case Com(c) => Combinator.generateC(c) | ||
case Var(n) => n | ||
case Abs(n, f) => s"\\$n ${generate(f)}" | ||
case App(f, x) => s"`${generate(f)} ${generate(x)}" | ||
case MultiApp(fs) => s"(${fs.map(generate).toList.mkString(" ")})" | ||
case LocalScope(fs) => s"{${fs.map(generate).toList.mkString(" ")}}" | ||
case NilList(fs) => s"[${fs.map(generate).mkString(" ")}]" | ||
case CharStr(s) => s"\"$s\"" | ||
case NatNum(n) => n.toString | ||
case IntNum(s, n) => Sign.generate(s) + n.toString | ||
} | ||
|
||
def toCombinators(l: Lambda): BinaryTree[Combinator] = l match { | ||
case Com(c) => Leaf(c) | ||
case App(f, x) => Node(toCombinators(f), toCombinators(x)) | ||
} | ||
|
||
// def apps1(head: Lambda, tail: List[Lambda]): Lambda = Apps(NonEmptyList(head, tail)) | ||
|
||
//I know it is crazy, but I wanted to check it is possible | ||
private val isOnlyCombinatorStep: (Lambda => Boolean) => Lambda => Boolean = rec => { | ||
case Com(_) => true | ||
case App(f, g) => rec(f) && rec(g) | ||
case _ => false | ||
} | ||
|
||
//I know it is crazy, but I wanted to check it is possible | ||
val isOnlyCombinator: Lambda => Boolean = fix(isOnlyCombinatorStep) | ||
|
||
def multi1(head: Lambda, tail: List[Lambda]): Lambda = MultiApp(NonEmptyList(head, tail)) | ||
def local1(head: Lambda, tail: List[Lambda]): Lambda = LocalScope(NonEmptyList(head, tail)) | ||
|
||
def natNumFromString(s: String): Lambda = NatNum(Natural(s)) | ||
|
||
def intNumFromString(sing: Sign, s: String): Lambda = IntNum(sing, Natural(s)) | ||
|
||
final case class Com(c: Combinator) extends Lambda | ||
final case class Var(name: String) extends Lambda | ||
final case class Abs(param: String, body: Lambda) extends Lambda | ||
final case class App(f: Lambda, x: Lambda) extends Lambda | ||
final case class MultiApp(fs: NonEmptyList[Lambda]) extends Lambda | ||
final case class LocalScope(xs: NonEmptyList[Lambda])extends Lambda | ||
final case class NilList(xs: List[Lambda]) extends Lambda | ||
final case class CharStr(s: String) extends Lambda | ||
final case class NatNum(n: Natural) extends Lambda | ||
final case class IntNum(s: Sign, n: Natural) extends Lambda | ||
} | ||
|
||
sealed trait Lambda |
7 changes: 7 additions & 0 deletions
7
core/src/main/scala/pl/writeonly/catculus/interpreter/FruitInterpreter.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package pl.writeonly.catculus.interpreter | ||
|
||
object FruitInterpreter { | ||
|
||
|
||
|
||
} |
75 changes: 75 additions & 0 deletions
75
core/src/test/scala/pl/writeonly/catculus/adt/calculus/LambdaSpec.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
package pl.writeonly.catculus.adt.calculus | ||
|
||
import org.scalatest.prop.TableFor3 | ||
import pl.writeonly.catculus.TableDrivenPropertySpec | ||
import pl.writeonly.catculus.adt.calculus.Lambda._ | ||
import pl.writeonly.catculus.parsers.LambdaParser | ||
import pl.writeonly.catculus.reducer.AbstractionReducer.reduceAbstraction | ||
import pl.writeonly.catculus.reducer.SugarReducer.reduceSugar | ||
|
||
class LambdaSpec extends TableDrivenPropertySpec { | ||
|
||
val basicLambda: TableFor3[String, Lambda, String] = Table( | ||
("lambda", "ast", "combinators"), | ||
("a", Var("a"), "a"), | ||
("\\a a", Abs("a", Var("a")), "I"), | ||
("`a a", App(Var("a"), Var("a")), "`a a"), | ||
("\\a `a a", Abs("a", App(Var("a"), Var("a"))), "``S I I"), | ||
("\\a \\a a", Abs("a", Abs("a", Var("a"))), "`K I"), | ||
("\\a \\b `a b", Abs("a", Abs("b", App(Var("a"), Var("b")))), "``S ``S `K S ``S `K K I `K I"), | ||
("\\a \\b `b a", Abs("a", Abs("b", App(Var("b"), Var("a")))), "``S `K `S I ``S `K K I"), | ||
) | ||
|
||
val advancedLambda: TableFor3[String, String, String] = | ||
Table( | ||
("lambda", "desugared", "combinators"), | ||
("(a a)", "`a a", "`a a"), | ||
("((a a))", "`a a", "`a a"), | ||
("(a b c)", "``a b c", "``a b c"), | ||
("{a b c}", "``a b c", "``a b c"), | ||
("{; (a b) \\c (c d)}", "``; `a b \\c `c d", "``; `a b ``S I `K d"), | ||
("(, a .)", "``, a .", "``, a ."), | ||
("(, a (, b .))", "``, a ``, b .", "``, a ``, b ."), | ||
("[]", ".", "."), | ||
("[a]", "``, a .", "``, a ."), | ||
("[a b]", "``, a ``, b .", "``, a ``, b ."), | ||
("\"\"", ".", "."), | ||
("\" \"", "``, , ``, `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: 0 .", "``, , ``, `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: 0 ."), | ||
("0", "0", "0"), | ||
("1", "`: 0", "`: 0"), | ||
("+0", "``, false 0", "``, false 0"), | ||
("-0", "``, true 0", "``, true 0"), | ||
("+1", "``, false `: 0", "``, false `: 0"), | ||
("-1", "``, true `: 0", "``, true `: 0"), | ||
) | ||
|
||
it should "parse basic Lambda and save ATS" in { | ||
forAll(basicLambda) { (lambda, ast, _) => | ||
LambdaParser.parse(lambda).value shouldBe ast | ||
} | ||
} | ||
|
||
it should "compile basic Lambda" in { | ||
forAll(basicLambda) { (lambda, _, combinators) => | ||
LambdaParser.parse(lambda).map(reduceSugar).map(reduceAbstraction).map(generate).value shouldBe combinators | ||
} | ||
} | ||
|
||
it should "parse advanced Lambda" in { | ||
forAll(advancedLambda) { (lambda, _, _) => | ||
LambdaParser.parse(lambda).map(generate).value shouldBe lambda | ||
} | ||
} | ||
|
||
it should "desugar advanced Lambda" in { | ||
forAll(advancedLambda) { (lambda, desugared, _) => | ||
LambdaParser.parse(lambda).map(reduceSugar).map(generate).value shouldBe desugared | ||
} | ||
} | ||
|
||
it should "compile advanced Lambda" in { | ||
forAll(advancedLambda) { (sugar, _, combinators) => | ||
LambdaParser.parse(sugar).map(reduceSugar).map(reduceAbstraction).map(generate).value shouldBe combinators | ||
} | ||
} | ||
} |