Skip to content

Commit 553741f

Browse files
committed
Generate Fruit
1 parent 8200cab commit 553741f

File tree

4 files changed

+185
-0
lines changed

4 files changed

+185
-0
lines changed
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package pl.writeonly.catculus.adt.calculus
2+
3+
import pl.writeonly.catculus.adt.calculus.Combinator.generateC
4+
import pl.writeonly.catculus.adt.tree.BinaryTree
5+
import pl.writeonly.catculus.adt.tree.BinaryTree.{Leaf, Node}
6+
import spire.math.Natural
7+
8+
object Fruit {
9+
10+
def generateFruitBT(tree: BinaryTree[Fruit]): String = tree match {
11+
case Leaf(a) => generateFruit(a)
12+
case Node(a, b) => s"`${generateFruitBT(a)} ${generateFruitBT(b)}"
13+
}
14+
15+
def generateFruit(f: Fruit): String = f match {
16+
case Com(c) => generateC(c)
17+
case Nat(n) => s"$n "
18+
case Succ => ":"
19+
}
20+
21+
def fromLambda(l: Lambda): BinaryTree[Fruit] = l match {
22+
case Lambda.Com(c) => Leaf(Com(c))
23+
case Lambda.App(f, x) => Node(fromLambda(f), fromLambda(x))
24+
}
25+
26+
final case class Com(c: Combinator) extends Fruit
27+
final case class Nat(n: Natural) extends Fruit
28+
final case object Succ extends Fruit
29+
}
30+
31+
sealed trait Fruit
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package pl.writeonly.catculus.adt.calculus
2+
3+
import cats.data.NonEmptyList
4+
import pl.writeonly.catculus.Extras.fix
5+
import pl.writeonly.catculus.adt.tree.BinaryTree
6+
import pl.writeonly.catculus.adt.tree.BinaryTree._
7+
import spire.math.Natural
8+
9+
object Lambda {
10+
11+
// val thrushVariable: Lambda = Var(";")
12+
val vireoVariable: Lambda = Var(",")
13+
val nilVariable: Lambda = Var(".")
14+
val succVariable: Lambda = Var(":")
15+
val zeroVariable: Lambda = Var("0")
16+
val falseVariable: Lambda = Var("false")
17+
val trueVariable: Lambda = Var("true")
18+
19+
// def wrapAppThrush(name: String, l1: Lambda, l2: Lambda): Lambda = App(thrushVariable, App(l1, Abs(name, l2)))
20+
def wrapAppVireoApp(l1: Lambda, l2: Lambda): Lambda = App(App (vireoVariable, l1), l2)
21+
def appSuccVariable(l: Lambda): Lambda = App(succVariable, l)
22+
23+
def generate(l: Lambda): String = l match {
24+
case Com(c) => Combinator.generateC(c)
25+
case Var(n) => n
26+
case Abs(n, f) => s"\\$n ${generate(f)}"
27+
case App(f, x) => s"`${generate(f)} ${generate(x)}"
28+
case MultiApp(fs) => s"(${fs.map(generate).toList.mkString(" ")})"
29+
case LocalScope(fs) => s"{${fs.map(generate).toList.mkString(" ")}}"
30+
case NilList(fs) => s"[${fs.map(generate).mkString(" ")}]"
31+
case CharStr(s) => s"\"$s\""
32+
case NatNum(n) => n.toString
33+
case IntNum(s, n) => Sign.generate(s) + n.toString
34+
}
35+
36+
def toCombinators(l: Lambda): BinaryTree[Combinator] = l match {
37+
case Com(c) => Leaf(c)
38+
case App(f, x) => Node(toCombinators(f), toCombinators(x))
39+
}
40+
41+
// def apps1(head: Lambda, tail: List[Lambda]): Lambda = Apps(NonEmptyList(head, tail))
42+
43+
//I know it is crazy, but I wanted to check it is possible
44+
private val isOnlyCombinatorStep: (Lambda => Boolean) => Lambda => Boolean = rec => {
45+
case Com(_) => true
46+
case App(f, g) => rec(f) && rec(g)
47+
case _ => false
48+
}
49+
50+
//I know it is crazy, but I wanted to check it is possible
51+
val isOnlyCombinator: Lambda => Boolean = fix(isOnlyCombinatorStep)
52+
53+
def multi1(head: Lambda, tail: List[Lambda]): Lambda = MultiApp(NonEmptyList(head, tail))
54+
def local1(head: Lambda, tail: List[Lambda]): Lambda = LocalScope(NonEmptyList(head, tail))
55+
56+
def natNumFromString(s: String): Lambda = NatNum(Natural(s))
57+
58+
def intNumFromString(sing: Sign, s: String): Lambda = IntNum(sing, Natural(s))
59+
60+
final case class Com(c: Combinator) extends Lambda
61+
final case class Var(name: String) extends Lambda
62+
final case class Abs(param: String, body: Lambda) extends Lambda
63+
final case class App(f: Lambda, x: Lambda) extends Lambda
64+
final case class MultiApp(fs: NonEmptyList[Lambda]) extends Lambda
65+
final case class LocalScope(xs: NonEmptyList[Lambda])extends Lambda
66+
final case class NilList(xs: List[Lambda]) extends Lambda
67+
final case class CharStr(s: String) extends Lambda
68+
final case class NatNum(n: Natural) extends Lambda
69+
final case class IntNum(s: Sign, n: Natural) extends Lambda
70+
}
71+
72+
sealed trait Lambda
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package pl.writeonly.catculus.interpreter
2+
3+
object FruitInterpreter {
4+
5+
6+
7+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package pl.writeonly.catculus.adt.calculus
2+
3+
import org.scalatest.prop.TableFor3
4+
import pl.writeonly.catculus.TableDrivenPropertySpec
5+
import pl.writeonly.catculus.adt.calculus.Lambda._
6+
import pl.writeonly.catculus.parsers.LambdaParser
7+
import pl.writeonly.catculus.reducer.AbstractionReducer.reduceAbstraction
8+
import pl.writeonly.catculus.reducer.SugarReducer.reduceSugar
9+
10+
class LambdaSpec extends TableDrivenPropertySpec {
11+
12+
val basicLambda: TableFor3[String, Lambda, String] = Table(
13+
("lambda", "ast", "combinators"),
14+
("a", Var("a"), "a"),
15+
("\\a a", Abs("a", Var("a")), "I"),
16+
("`a a", App(Var("a"), Var("a")), "`a a"),
17+
("\\a `a a", Abs("a", App(Var("a"), Var("a"))), "``S I I"),
18+
("\\a \\a a", Abs("a", Abs("a", Var("a"))), "`K I"),
19+
("\\a \\b `a b", Abs("a", Abs("b", App(Var("a"), Var("b")))), "``S ``S `K S ``S `K K I `K I"),
20+
("\\a \\b `b a", Abs("a", Abs("b", App(Var("b"), Var("a")))), "``S `K `S I ``S `K K I"),
21+
)
22+
23+
val advancedLambda: TableFor3[String, String, String] =
24+
Table(
25+
("lambda", "desugared", "combinators"),
26+
("(a a)", "`a a", "`a a"),
27+
("((a a))", "`a a", "`a a"),
28+
("(a b c)", "``a b c", "``a b c"),
29+
("{a b c}", "``a b c", "``a b c"),
30+
("{; (a b) \\c (c d)}", "``; `a b \\c `c d", "``; `a b ``S I `K d"),
31+
("(, a .)", "``, a .", "``, a ."),
32+
("(, a (, b .))", "``, a ``, b .", "``, a ``, b ."),
33+
("[]", ".", "."),
34+
("[a]", "``, a .", "``, a ."),
35+
("[a b]", "``, a ``, b .", "``, a ``, b ."),
36+
("\"\"", ".", "."),
37+
("\" \"", "``, , ``, `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: 0 .", "``, , ``, `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: `: 0 ."),
38+
("0", "0", "0"),
39+
("1", "`: 0", "`: 0"),
40+
("+0", "``, false 0", "``, false 0"),
41+
("-0", "``, true 0", "``, true 0"),
42+
("+1", "``, false `: 0", "``, false `: 0"),
43+
("-1", "``, true `: 0", "``, true `: 0"),
44+
)
45+
46+
it should "parse basic Lambda and save ATS" in {
47+
forAll(basicLambda) { (lambda, ast, _) =>
48+
LambdaParser.parse(lambda).value shouldBe ast
49+
}
50+
}
51+
52+
it should "compile basic Lambda" in {
53+
forAll(basicLambda) { (lambda, _, combinators) =>
54+
LambdaParser.parse(lambda).map(reduceSugar).map(reduceAbstraction).map(generate).value shouldBe combinators
55+
}
56+
}
57+
58+
it should "parse advanced Lambda" in {
59+
forAll(advancedLambda) { (lambda, _, _) =>
60+
LambdaParser.parse(lambda).map(generate).value shouldBe lambda
61+
}
62+
}
63+
64+
it should "desugar advanced Lambda" in {
65+
forAll(advancedLambda) { (lambda, desugared, _) =>
66+
LambdaParser.parse(lambda).map(reduceSugar).map(generate).value shouldBe desugared
67+
}
68+
}
69+
70+
it should "compile advanced Lambda" in {
71+
forAll(advancedLambda) { (sugar, _, combinators) =>
72+
LambdaParser.parse(sugar).map(reduceSugar).map(reduceAbstraction).map(generate).value shouldBe combinators
73+
}
74+
}
75+
}

0 commit comments

Comments
 (0)