Skip to content

Commit

Permalink
Add Reducer for LazyK
Browse files Browse the repository at this point in the history
  • Loading branch information
kamil-adam committed May 14, 2024
1 parent 29f2aad commit ab0f5ac
Show file tree
Hide file tree
Showing 19 changed files with 153 additions and 204 deletions.
2 changes: 1 addition & 1 deletion .scalafmt.conf
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
maxColumn = 80
maxColumn = 160
version = 3.7.14
runner.dialect = scala3
preset = IntelliJ
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@ import cats.data.NonEmptyList

object Extras {

def foldNonEmpty[A](l: NonEmptyList[A])(f: (A, A) => A): A = l
.tail
.fold(l.head)(f)
def foldNonEmpty[A](l: NonEmptyList[A])(f: (A, A) => A): A = l.tail.fold(l.head)(f)

def fix[T, R](f: (T => R) => (T => R)): (T => R) = new Function1[T, R] {
def apply(t: T): R = f(this)(t)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,11 @@ import pl.writeonly.catculator.core.adt.calculus.Lambda
import pl.writeonly.catculator.core.adt.calculus.Lambda._

object LambdaConfig {
val haskellConfig: LambdaConfig = LambdaConfig(
apply = "apply",
pair = "pair",
nil = "nil",
succ = "succ",
zero = "zero",
)
val lambdaConfig: LambdaConfig =
LambdaConfig(apply = ";", pair = ",", nil = ".", succ = ":", zero = "0")
val haskellConfig: LambdaConfig = LambdaConfig(apply = "apply", pair = "pair", nil = "nil", succ = "succ", zero = "zero")
val lambdaConfig: LambdaConfig = LambdaConfig(apply = ";", pair = ",", nil = ".", succ = ":", zero = "0")
}

case class LambdaConfig(
apply: String,
pair: String,
nil: String,
succ: String,
zero: String,
) {
case class LambdaConfig(apply: String, pair: String, nil: String, succ: String, zero: String) {

val thrushVariable: Var = Var(apply)
val vireoVariable: Lambda = Var(pair)
Expand All @@ -40,17 +27,13 @@ case class LambdaConfig(
l |> appAppAbs(applyBody, applyBody, apply)
}

def appAppAbs(l1: Lambda, l2: Lambda, name: String)(l3: Lambda): Lambda =
App(l1, App(l2, Abs(name, l3)))
def appAppAbs(l1: Lambda, l2: Lambda, name: String)(l3: Lambda): Lambda = App(l1, App(l2, Abs(name, l3)))

def wrapAppThrush(l1: Lambda, name: String)(l2: Lambda): Lambda =
appAppAbs(thrushVariable, l1, name)(l2)
def wrapAppThrush(l1: Lambda, name: String)(l2: Lambda): Lambda = appAppAbs(thrushVariable, l1, name)(l2)

def reThrush(oldName: String, newName: String)(l: Lambda): Lambda =
wrapAppThrush(Var(oldName), newName)(l)
def reThrush(oldName: String, newName: String)(l: Lambda): Lambda = wrapAppThrush(Var(oldName), newName)(l)

def wrapAppVireoApp(l1: Lambda, l2: Lambda): Lambda =
App(App(vireoVariable, l1), l2)
def wrapAppVireoApp(l1: Lambda, l2: Lambda): Lambda = App(App(vireoVariable, l1), l2)

def appSuccVariable(l: Lambda): Lambda = App(succVariable, l)
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,9 @@ object Constants {

def appK(a: CombinatorBT): Node[Combinator] = Node(kCom, a)

def app4(
c1: CombinatorBT,
c2: CombinatorBT,
c3: CombinatorBT,
c4: CombinatorBT,
): CombinatorBT = Node(c1, app3(c2, c3, c4))

def app3(c1: CombinatorBT, c2: CombinatorBT, c3: CombinatorBT): CombinatorBT =
Node(c1, Node(c2, c3))
def app4(c1: CombinatorBT, c2: CombinatorBT, c3: CombinatorBT, c4: CombinatorBT): CombinatorBT = Node(c1, app3(c2, c3, c4))

def app3(c1: CombinatorBT, c2: CombinatorBT, c3: CombinatorBT): CombinatorBT = Node(c1, Node(c2, c3))

def com(c: Combinator): CombinatorBT = Leaf(c)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,11 @@ object InputEncoder {
},
)

def encodeInput(input: List[Natural]): CombinatorBT = input
.foldRight(falseCom) { case (n, l) =>
cons(church(n), l)
}
def encodeInput(input: List[Natural]): CombinatorBT = input.foldRight(falseCom) { case (n, l) =>
cons(church(n), l)
}

def cons(a: CombinatorBT, b: CombinatorBT): CombinatorBT =
app3(sCom, Constants.app3SI(appK(a)), appK(b))
def cons(a: CombinatorBT, b: CombinatorBT): CombinatorBT = app3(sCom, Constants.app3SI(appK(a)), appK(b))

def church(n: Natural): CombinatorBT = n.toBigInt match {
case n if n === BigInt(0) => falseCom
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,25 +28,21 @@ object Lambda {
.mkString

// 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
}
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 let1(t: (String, Lambda), body: Lambda): Lambda = Let(t._1, t._2, body)

def multi(params: List[String], body: NonEmptyList[Lambda]): Lambda =
MultiAbs(params, MultiApp(body))
def multi(params: List[String], body: NonEmptyList[Lambda]): Lambda = MultiAbs(params, MultiApp(body))

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,5 @@ enum Tree[A]:
case Node(children: NonEmptyList[Tree[A]])

object Tree {
def node[A](head: Tree[A], tail: Tree[A]*): Tree[A] =
Node(NonEmptyList(head, tail.toList))
def node[A](head: Tree[A], tail: Tree[A]*): Tree[A] = Node(NonEmptyList(head, tail.toList))
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@ package pl.writeonly.catculator.core.calculators.lazyk

import pl.writeonly.catculator.core.adt.calculus.Combinator
import pl.writeonly.catculator.core.adt.calculus.Combinator.CombinatorBT
import pl.writeonly.catculator.core.adt.calculus.Constants
import pl.writeonly.catculator.core.adt.tree.BinaryTree
import pl.writeonly.catculator.core.adt.tree.BinaryTree._

import pl.writeonly.catculator.core.adt.calculus.Constants

import spire.math.Natural

enum ADT:
Expand All @@ -17,16 +15,18 @@ enum ADT:
object ADT {

type ADTBT = BinaryTree[ADT]
type ADTBTSafe = Either[String, ADTBT]

val number0: ADTBT = Leaf(ADT.Num(Natural(0)))
val number0: ADTBT = Leaf(ADT.Num(Natural.zero))
val number1: ADTBT = Leaf(ADT.Num(Natural.one))
val trueVar: ADTBT = fromCombinatorBT(Constants.trueCom)
val falseVar: ADTBT = fromCombinatorBT(Constants.falseCom)

def fromCombinatorBT(c: CombinatorBT): ADTBT = c match {
case Node(a, b) => Node(fromCombinatorBT(a), fromCombinatorBT(b))
case Leaf(a) => Leaf(fromCombinator(a))
case Leaf(a) => Leaf(fromCombinator(a))
}

private def fromCombinator(c: Combinator): ADT = ADT.Com(c)

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package pl.writeonly.catculator.core.calculators.lazyk

import pl.writeonly.catculator.core.adt.calculus.Combinator
import pl.writeonly.catculator.core.adt.calculus.Combinator._
import pl.writeonly.catculator.core.adt.tree.BinaryTree
import pl.writeonly.catculator.core.adt.tree.BinaryTree._
import pl.writeonly.catculator.core.calculators.lazyk.ADT._
import spire.math.Natural

import scala.util.Right

object Reducer {
def reduce(f: ADTBT): ADTBTSafe = f match {
case Node(x, y) => applyM(reduce(x), reduce(y))
case x => Right(x)
}

def applyM(fM: ADTBTSafe, xM: ADTBTSafe): ADTBTSafe =
for
f <- fM
x <- xM
r <- apply(f, x)
yield r

def flippedApply(x: ADTBT, y: ADTBT): ADTBTSafe = apply(y, x)

def apply(f: ADTBT, x: ADTBT): ADTBTSafe = f match {
case Leaf(ADT.Succ()) => succ(x)
case Node(Node(Leaf(ADT.Com(S)), z), y) => applyM(apply(z, x), apply(y, x))
case Node(Leaf(ADT.Com(K)), y) => Right(y)
case Leaf(ADT.Com(I)) => Right(x)
case _ => Right(Node(f, x))
}

private def succ(x: ADTBT) = x match {
case Leaf(ADT.Num(x)) => Right(Leaf(ADT.Num(x + Natural.one)))
case _ => Left(s"attempted to apply inc to a non-number $x")
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ object HaskellParser {
c.isLetterOrDigit || c === '_'
}

private val identifier: P[String] =
horizontalSymbol((identifierStart ~ identifierContinue.rep0).string)
private val identifier: P[String] = horizontalSymbol((identifierStart ~ identifierContinue.rep0).string)

// format: off
private val lambda: P[Lambda] = P.defer(
Expand All @@ -38,44 +37,33 @@ object HaskellParser {

private val application0: P[Lambda] = lambda.rep.map(MultiApp.apply)

private val application: P[Lambda] = charSymbol('(') *> application0 <*
charHorizontalSymbol(')')
private val application: P[Lambda] = charSymbol('(') *> application0 <* charHorizontalSymbol(')')

private val let: P[Lambda] =
(
stringSymbol("let") *>
((identifier <* stringSymbol("=")) ~ lambda) ~
(stringSymbol("in") *> lambda)
).map(let1)
private val let: P[Lambda] = (stringSymbol("let") *> ((identifier <* stringSymbol("=")) ~ lambda) ~ (stringSymbol("in") *> lambda)).map(let1)

private val abstraction0 = charSymbol('\\') *> identifier.rep0 <*
stringSymbol("->")
private val abstraction0 = charSymbol('\\') *> identifier.rep0 <* stringSymbol("->")

private val abstraction: P[Lambda] = (abstraction0 ~ application0)
.map(MultiAbs.apply)
private val abstraction: P[Lambda] = (abstraction0 ~ application0).map(MultiAbs.apply)

val charStr: P[Lambda] = horizontalSymbol(jsonString.map(CharStr.apply))

private val apostrophe = P.char('\'')

val char: P[Lambda] = horizontalSymbol(apostrophe *> P.anyChar <* apostrophe)
.map { c =>
natNumFromLong(c.toLong)
}
val char: P[Lambda] = horizontalSymbol(apostrophe *> P.anyChar <* apostrophe).map { c =>
natNumFromLong(c.toLong)
}

val natNum: P[Lambda] = horizontalSymbol(digits.map(natNumFromString))

private val function: P[Func] =
((identifier <* charSymbol('=')) ~ symbol(lambda)).map(Func.apply)
private val function: P[Func] = ((identifier <* charSymbol('=')) ~ symbol(lambda)).map(Func.apply)

private val functionParser: P[Func] = function <* P.end

private val functionsParser = whitespaces *> function.rep <* P.end

val parseFunction: String => Either[P.Error, Func] = functionParser.parseAll

val parseFunctions: String => Either[P.Error, NonEmptyList[Func]] =
functionsParser.parseAll
val parseFunctions: String => Either[P.Error, NonEmptyList[Func]] = functionsParser.parseAll

val parse3: String => Either[P.Error, NonEmptyList[Func]] = (s) =>
parseFunctions(s) match {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ object LambdaParser {
c.isLetterOrDigit || c === '_'
}

val identifier: P[String] =
symbol((identifierStart ~ identifierContinue.rep0).string)
val identifier: P[String] = symbol((identifierStart ~ identifierContinue.rep0).string)

// format: off
val lambda: P[Lambda] = P.defer(
Expand All @@ -38,26 +37,19 @@ object LambdaParser {

val variable: P[Lambda] = identifier.map(Var.apply)

val abstraction: P[Lambda] = (charSymbol('\\') *> identifier ~ lambda)
.map(Abs.apply)
val abstraction: P[Lambda] = (charSymbol('\\') *> identifier ~ lambda).map(Abs.apply)

val application: P[Lambda] = (charSymbol('`') *> lambda ~ lambda)
.map(App.apply)
val application: P[Lambda] = (charSymbol('`') *> lambda ~ lambda).map(App.apply)

val mautiApplicationChildren: P[Lambda] = (lambda ~ lambda.rep0)
.map((multi1 _).tupled)
val mautiApplicationChildren: P[Lambda] = (lambda ~ lambda.rep0).map((multi1 _).tupled)

val multiApplication: P[Lambda] =
charSymbol('(') *> mautiApplicationChildren <* charSymbol(')')
val multiApplication: P[Lambda] = charSymbol('(') *> mautiApplicationChildren <* charSymbol(')')

val localScopeChildren: P[Lambda] = (lambda ~ lambda.rep0)
.map((local1 _).tupled)
val localScopeChildren: P[Lambda] = (lambda ~ lambda.rep0).map((local1 _).tupled)

val localScope: P[Lambda] = charSymbol('{') *> localScopeChildren <*
charSymbol('}')
val localScope: P[Lambda] = charSymbol('{') *> localScopeChildren <* charSymbol('}')

val nilList: P[Lambda] = charSymbol('[') *> lambda.rep0.map(NilList.apply) <*
charSymbol(']')
val nilList: P[Lambda] = charSymbol('[') *> lambda.rep0.map(NilList.apply) <* charSymbol(']')

val charStr: P[Lambda] = jsonString.map(CharStr.apply)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,17 @@ object AbstractionReducer {
case l if isOnlyCombinator(l) => wrapAppK(l)
case Var(n1) => reduceVar(p0, n1)
case Abs(p1, b1) => reduceAbs(p0, p1, b1)
case App(f, g) =>
wrapAppAppS(reduceAbstraction1(p0, f), reduceAbstraction1(p0, g))
case lambda => lambda
case App(f, g) => wrapAppAppS(reduceAbstraction1(p0, f), reduceAbstraction1(p0, g))
case lambda => lambda
}

private def reduceVar(n0: String, n1: String): Lambda =
ifElse(n0 === n1)(Com(I))(wrapAppK(Var(n1)))
private def reduceVar(n0: String, n1: String): Lambda = ifElse(n0 === n1)(Com(I))(wrapAppK(Var(n1)))

private def reduceAbs(p0: String, p1: String, b1: Lambda): Lambda =
reduceAbs1(p0, p1, reduceAbstraction1(p1, b1))
private def reduceAbs(p0: String, p1: String, b1: Lambda): Lambda = reduceAbs1(p0, p1, reduceAbstraction1(p1, b1))

private def reduceAbs1(p0: String, p1: String, c: Lambda): Lambda =
ifElse(p0 === p1)(wrapAppK(c))(reduceAbstraction1(p0, c))
private def reduceAbs1(p0: String, p1: String, c: Lambda): Lambda = ifElse(p0 === p1)(wrapAppK(c))(reduceAbstraction1(p0, c))

private def wrapAppK(c: Lambda): Lambda = App(Com(K), c)

private def wrapAppAppS(c1: Lambda, c2: Lambda): Lambda =
App(App(Com(S), c1), c2)
private def wrapAppAppS(c1: Lambda, c2: Lambda): Lambda = App(App(Com(S), c1), c2)
}
Loading

0 comments on commit ab0f5ac

Please sign in to comment.