Skip to content

Commit

Permalink
Generate Fruit
Browse files Browse the repository at this point in the history
  • Loading branch information
kamil-adam committed May 23, 2024
1 parent 8200cab commit 553741f
Show file tree
Hide file tree
Showing 4 changed files with 185 additions and 0 deletions.
31 changes: 31 additions & 0 deletions core/src/main/scala/pl/writeonly/catculus/adt/calculus/Fruit.scala
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
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package pl.writeonly.catculus.interpreter

object FruitInterpreter {



}
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
}
}
}

0 comments on commit 553741f

Please sign in to comment.