From 2ef584a42a86f50e65650136c83b8d0709cfbb07 Mon Sep 17 00:00:00 2001 From: Anthony Cerruti Date: Sun, 26 Jul 2020 14:54:02 -0700 Subject: [PATCH] An ADT for this recursion scheme that should finally work --- .../tf/bug/fancadetagless/FancadeF.scala | 127 +++++++----------- .../tf/bug/fancadetagless/Fanscript.scala | 114 ++++++++-------- .../scala/tf/bug/fancadetagless/Main.scala | 2 +- 3 files changed, 108 insertions(+), 135 deletions(-) diff --git a/tagless/src/main/scala/tf/bug/fancadetagless/FancadeF.scala b/tagless/src/main/scala/tf/bug/fancadetagless/FancadeF.scala index 3e5c4e1..1fd30fa 100644 --- a/tagless/src/main/scala/tf/bug/fancadetagless/FancadeF.scala +++ b/tagless/src/main/scala/tf/bug/fancadetagless/FancadeF.scala @@ -4,110 +4,77 @@ import cats._ import cats.implicits._ import higherkindness.droste.data._ import polymorphic._ -import scalax.collection.Graph -import scalax.collection.GraphEdge.DiHyperEdge -import tf.bug.fancadegraph.Block import tf.bug.fancadegraph.Level -import tf.bug.fancadegraph.Pin import tf.bug.fancadegraph.PinDefinition import tf.bug.fancadegraph.Template -import tf.bug.fancadescodec.Position sealed trait FancadeF[A] object FancadeF { - case class Inspect[A]( - uses: Vector[A], - template: Exists[Template], - inputs: Vector[PinDefinition], - outputs: Vector[PinDefinition] - ) extends FancadeF[A] - case class Modify[A]( - uses: Vector[A], - template: Exists[Template], - inputs: Vector[PinDefinition], - before: PinDefinition, - after: PinDefinition, - outputs: Vector[PinDefinition] - ) extends FancadeF[A] + case class Create[A](from: Vector[A], template: Exists[Template], imports: Vector[PinDefinition], exports: Vector[PinDefinition]) extends FancadeF[A] + case class Select[A](from: A, indicies: Vector[Int]) extends FancadeF[A] + case class Combine[A](from: Vector[A]) extends FancadeF[A] + case class Sequence[A](first: A, afterPin: PinDefinition, next: A) extends FancadeF[A] + case class Noop[A]() extends FancadeF[A] implicit val fancadeTraverse: Traverse[FancadeF] = new Traverse[FancadeF] { override def traverse[G[_]: Applicative, A, B](fa: FancadeF[A])(f: A => G[B]): G[FancadeF[B]] = fa match { - case Inspect(u, t, i, o) => u.traverse(f).map { v => Inspect(v, t, i, o) } - case Modify(u, t, i, b, a, o) => u.traverse(f).map { v => Modify(v, t, i, b, a, o) } + case Create(v, t, i, e) => v.traverse(f).map(w => Create(w, t, i, e)) + case Select(a, i) => f(a).map(b => Select(b, i)) + case Combine(v) => v.traverse(f).map(w => Combine(w)) + case Sequence(i, p, n) => (f(i), f(n)).mapN((j, o) => Sequence(j, p, o)) + case Noop() => Noop[B]().pure[G].widen } override def foldLeft[A, B](fa: FancadeF[A], b: B)(f: (B, A) => B): B = fa match { - case Inspect(u, _, _, _) => u.foldl(b)(f) - case Modify(u, _, _, _, _, _) => u.foldl(b)(f) + case Create(v, _, _, _) => v.foldLeft(b)(f) + case Select(a, _) => f(b, a) + case Combine(v) => v.foldLeft(b)(f) + case Sequence(i, _, n) => f(f(b, i), n) + case Noop() => b } override def foldRight[A, B](fa: FancadeF[A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = fa match { - case Inspect(u, _, _, _) => u.foldr(lb)(f) + case Create(v, _, _, _) => v.foldr(lb)(f) + case Select(a, _) => f(a, lb) + case Combine(v) => v.foldr(lb)(f) + case Sequence(i, _, n) => f(i, f(n, lb)) + case Noop() => lb } } + def origins(root: Int, stack: Vector[FancadeF[Int]]): Vector[(Int, PinDefinition)] = { + stack(root) match { + case Create(_, _, _, pins) => + pins.map((root, _)) + case Select(f, i) => + val original = origins(f, stack) + i.map(original(_)) + case Combine(f) => + f.flatMap(origins(_, stack)) + case Sequence(_, _, n) => + origins(n, stack) + case Noop() => + Vector.empty + } + } + + def flatStack(vertices: Vector[FancadeF[Int]]): (Vector[Exists[Template]], Int => Option[Int]) = { + val blocks = vertices.collect(_ => ???) + (blocks, ())._2 + ??? + } + def render(f: Fix[FancadeF]): Level = { - val pc = PointerChain.deduplicate[Id, FancadeF](f) - val pcvi = pc.vertices.zipWithIndex - val blocks: Set[Block] = pcvi.map { - case (block, y) => - Block( - Position(0, y, 0), - block.template - ) - }.toSet - val wires: Graph[Pin, DiHyperEdge] = - pcvi.foldLeft(Graph.empty[Pin, DiHyperEdge]) { - case (graph, (block, y)) => - block match { - case Capture(_, _, _) => graph - case Use(children, template, inputs, _, _) => - val thisBlock = Block( - Position(0, y, 0), - template - ) - val thesePins = inputs.map(Pin(thisBlock, _)) - val childrenPins: Vector[Pin] = children.flatMap { child => - val childInst = pc.vertices(child) - val childBlock = Block( - Position(0, child, 0), - childInst.template - ) - childInst.pins.map(Pin(childBlock, _)) - } - val newEdges: Vector[DiHyperEdge[Pin]] = childrenPins.zip(thesePins).map { - case (from, to) => DiHyperEdge(from, to) - } - println(newEdges) - graph ++ newEdges - case Select(_, _) => graph - case AndThen(original, next, beforePinDef) => - val beforePin = Pin( - Block( - Position(0, y, 0), - next.template - ), - beforePinDef - ) - val originalInst = pc.vertices(original) - graph ++ originalInst.after.map { afterPinDef => - val afterPin = Pin( - Block( - Position(0, original, 0), - originalInst.template - ), - afterPinDef - ) - DiHyperEdge(beforePin, afterPin) - } - } - } - Level(blocks, wires) + val pc: PointerChain[Id, FancadeF] = PointerChain.deduplicate[Id, FancadeF](f) + val (stack, stackLookup) = flatStack(pc.vertices) + (stack, ())._2 + (stackLookup, ())._2 + ??? } } diff --git a/tagless/src/main/scala/tf/bug/fancadetagless/Fanscript.scala b/tagless/src/main/scala/tf/bug/fancadetagless/Fanscript.scala index 83812fe..05db602 100644 --- a/tagless/src/main/scala/tf/bug/fancadetagless/Fanscript.scala +++ b/tagless/src/main/scala/tf/bug/fancadetagless/Fanscript.scala @@ -9,38 +9,40 @@ import tf.bug.fancadegraph.Template trait Fanscript[F[_]] { + def unit: F[Unit] + def lift(value: Float): F[Float] def lift(value: Vector3): F[Vector3] def lift(value: Rotation): F[Rotation] def lift(value: Boolean): F[Boolean] - def inspect(value: F[Float]): F[Unit] + def inspect(value: F[Float], after: () => F[Unit]): F[Unit] - def win(stop: Boolean): F[Unit] - def lose(stop: Boolean): F[Unit] - def setScore(score: F[Float]): F[Unit] - def setCamera(position: F[Vector3], rotation: F[Rotation], distance: F[Float]): F[Unit] - def setLight(position: F[Vector3], rotation: F[Rotation]): F[Unit] + def win(stop: Boolean)(after: () => F[Unit]): F[Unit] + def lose(stop: Boolean)(after: () => F[Unit]): F[Unit] + def setScore(score: F[Float], after: () => F[Unit]): F[Unit] + def setCamera(position: F[Vector3], rotation: F[Rotation], distance: F[Float], after: () => F[Unit]): F[Unit] + def setLight(position: F[Vector3], rotation: F[Rotation], after: () => F[Unit]): F[Unit] def screenSize: F[Fanscript.ScreenSize] def accelerometer: F[Vector3] def getPosition(obj: F[Obj]): F[Fanscript.Position] - def setPosition(obj: F[Obj], position: F[Vector3], rotation: F[Rotation]): F[Unit] + def setPosition(obj: F[Obj], position: F[Vector3], rotation: F[Rotation], after: () => F[Unit]): F[Unit] def raycast(from: F[Vector3], to: F[Vector3]): F[Fanscript.Raycast] def getSize(obj: F[Obj]): F[Fanscript.Size] - def setVisible(obj: F[Obj], visible: F[Boolean]): F[Unit] - def createObj(original: F[Obj]): F[Obj] - def destroyObj(obj: F[Obj]): F[Obj] + def setVisible(obj: F[Obj], visible: F[Boolean], after: () => F[Unit]): F[Unit] + def createObj(original: F[Obj], after: F[Obj] => F[Unit]): F[Unit] + def destroyObj(obj: F[Obj], after: () => F[Unit]): F[Unit] - def playSound(loop: Boolean, sound: Sample)(volume: F[Float], pitch: F[Float]): F[Float] - def stopSound(channel: F[Float]): F[Unit] - def volumePitch(channel: F[Float], volume: F[Float], pitch: F[Float]): F[Unit] + def playSound(loop: Boolean, sound: Sample)(volume: F[Float], pitch: F[Float], after: F[Float] => F[Unit]): F[Unit] + def stopSound(channel: F[Float], after: () => F[Unit]): F[Unit] + def volumePitch(channel: F[Float], volume: F[Float], pitch: F[Float], after: () => F[Unit]): F[Unit] - def addForce(obj: F[Obj], force: F[Vector3], applyAt: F[Vector3], torque: F[Vector3]): F[Unit] + def addForce(obj: F[Obj], force: F[Vector3], applyAt: F[Vector3], torque: F[Vector3], after: () => F[Unit]): F[Unit] def getVelocity(obj: F[Obj]): F[Fanscript.Velocity] - def setVelocity(obj: F[Obj], velocity: F[Vector3], spin: F[Vector3]): F[Unit] - def setLocked(obj: F[Obj], position: F[Vector3], rotation: F[Vector3]): F[Unit] - def setMass(obj: F[Obj], mass: F[Float]): F[Unit] + def setVelocity(obj: F[Obj], velocity: F[Vector3], spin: F[Vector3], after: () => F[Unit]): F[Unit] + def setLocked(obj: F[Obj], position: F[Vector3], rotation: F[Vector3], after: () => F[Unit]): F[Unit] + def setMass(obj: F[Obj], mass: F[Float], after: () => F[Unit]): F[Unit] def setFriction(obj: F[Obj], friction: F[Float]): F[Unit] def setBounciness(obj: F[Obj], bounciness: F[Float]): F[Unit] def setGravity(gravity: F[Vector3]): F[Unit] @@ -75,8 +77,6 @@ trait Fanscript[F[_]] { def velocityVelocity(velocity: F[Fanscript.Velocity]): F[Vector3] def velocitySpin(velocity: F[Fanscript.Velocity]): F[Vector3] - def andThen[A, B](before: F[A], next: F[A] => F[B]): F[B] - } object Fanscript { @@ -87,8 +87,11 @@ object Fanscript { implicit object fancade extends Fanscript[Fancade] { + override def unit: Fancade[Unit] = + Fix(FancadeF.Noop()) + override def lift(value: Float): Fancade[Float] = - Fix(FancadeF.Inspect( + Fix(FancadeF.Create( Vector(), Exists(Template( BlockDefinition.NumberValue, @@ -101,62 +104,66 @@ object Fanscript { override def lift(value: Rotation): Fancade[Rotation] = ??? override def lift(value: Boolean): Fancade[Boolean] = ??? - override def inspect(value: Fancade[Float]): Fancade[Unit] = - Fix(FancadeF.Modify( + override def inspect(value: Fancade[Float], after: () => Fancade[Unit]): Fancade[Unit] = { + val us = Fix(FancadeF.Create( Vector(value), Exists(Template( BlockDefinition.InspectNumber, () )), Vector(BlockDefinition.InspectNumber.value), - BlockDefinition.InspectNumber.before, - BlockDefinition.InspectNumber.after, - Vector() + Vector(BlockDefinition.InspectNumber.before) )) + Fix(FancadeF.Sequence( + us, + BlockDefinition.InspectNumber.after, + after() + )) + } - override def win(stop: Boolean): Fancade[Unit] = ??? - override def lose(stop: Boolean): Fancade[Unit] = ??? - override def setScore(score: Fancade[Float]): Fancade[Unit] = ??? - override def setCamera(position: Fancade[Vector3], rotation: Fancade[Rotation], distance: Fancade[Float]): Fancade[Unit] = ??? - override def setLight(position: Fancade[Vector3], rotation: Fancade[Rotation]): Fancade[Unit] = ??? + override def win(stop: Boolean)(after: () => Fancade[Unit]): Fancade[Unit] = ??? + override def lose(stop: Boolean)(after: () => Fancade[Unit]): Fancade[Unit] = ??? + override def setScore(score: Fancade[Float], after: () => Fancade[Unit]): Fancade[Unit] = ??? + override def setCamera(position: Fancade[Vector3], rotation: Fancade[Rotation], distance: Fancade[Float], after: () => Fancade[Unit]): Fancade[Unit] = ??? + override def setLight(position: Fancade[Vector3], rotation: Fancade[Rotation], after: () => Fancade[Unit]): Fancade[Unit] = ??? override def screenSize: Fancade[ScreenSize] = - Fix(FancadeF.Inspect( + Fix(FancadeF.Create( + Vector(), Exists(Template( BlockDefinition.ScreenSize, () )), + Vector(), Vector(BlockDefinition.ScreenSize.screenWidth, BlockDefinition.ScreenSize.screenHeight), - None )) override def accelerometer: Fancade[Vector3] = ??? override def getPosition(obj: Fancade[Obj]): Fancade[Position] = - Fix(FancadeF.Use( + Fix(FancadeF.Create( Vector(obj), Exists(Template( BlockDefinition.GetPosition, () )), Vector(BlockDefinition.GetPosition.obj), - Vector(BlockDefinition.GetPosition.position), - None + Vector(BlockDefinition.GetPosition.position) )) - override def setPosition(obj: Fancade[Obj], position: Fancade[Vector3], rotation: Fancade[Rotation]): Fancade[Unit] = ??? + override def setPosition(obj: Fancade[Obj], position: Fancade[Vector3], rotation: Fancade[Rotation], after: () => Fancade[Unit]): Fancade[Unit] = ??? override def raycast(from: Fancade[Vector3], to: Fancade[Vector3]): Fancade[Raycast] = ??? override def getSize(obj: Fancade[Obj]): Fancade[Size] = ??? - override def setVisible(obj: Fancade[Obj], visible: Fancade[Boolean]): Fancade[Unit] = ??? - override def createObj(original: Fancade[Obj]): Fancade[Obj] = ??? - override def destroyObj(obj: Fancade[Obj]): Fancade[Obj] = ??? + override def setVisible(obj: Fancade[Obj], visible: Fancade[Boolean], after: () => Fancade[Unit]): Fancade[Unit] = ??? + override def createObj(original: Fancade[Obj], after: (Fancade[Obj]) => Fancade[Unit]): Fancade[Unit] = ??? + override def destroyObj(obj: Fancade[Obj], after: () => Fancade[Unit]): Fancade[Unit] = ??? - override def playSound(loop: Boolean, sound: Sample)(volume: Fancade[Float], pitch: Fancade[Float]): Fancade[Float] = ??? - override def stopSound(channel: Fancade[Float]): Fancade[Unit] = ??? - override def volumePitch(channel: Fancade[Float], volume: Fancade[Float], pitch: Fancade[Float]): Fancade[Unit] = ??? + override def playSound(loop: Boolean, sound: Sample)(volume: Fancade[Float], pitch: Fancade[Float], after: Fancade[Float] => Fancade[Unit]): Fancade[Unit] = ??? + override def stopSound(channel: Fancade[Float], after: () => Fancade[Unit]): Fancade[Unit] = ??? + override def volumePitch(channel: Fancade[Float], volume: Fancade[Float], pitch: Fancade[Float], after: () => Fancade[Unit]): Fancade[Unit] = ??? - override def addForce(obj: Fancade[Obj], force: Fancade[Vector3], applyAt: Fancade[Vector3], torque: Fancade[Vector3]): Fancade[Unit] = ??? - override def getVelocity(obj: Fancade[Obj]): Fancade[Velocity] = ??? - override def setVelocity(obj: Fancade[Obj], velocity: Fancade[Vector3], spin: Fancade[Vector3]): Fancade[Unit] = ??? - override def setLocked(obj: Fancade[Obj], position: Fancade[Vector3], rotation: Fancade[Vector3]): Fancade[Unit] = ??? - override def setMass(obj: Fancade[Obj], mass: Fancade[Float]): Fancade[Unit] = ??? + override def addForce(obj: Fancade[Obj], force: Fancade[Vector3], applyAt: Fancade[Vector3], torque: Fancade[Vector3], after: () => Fancade[Unit]): Fancade[Unit] = ??? + override def getVelocity(obj: Fancade[Obj]): Fancade[Fanscript.Velocity] = ??? + override def setVelocity(obj: Fancade[Obj], velocity: Fancade[Vector3], spin: Fancade[Vector3], after: () => Fancade[Unit]): Fancade[Unit] = ??? + override def setLocked(obj: Fancade[Obj], position: Fancade[Vector3], rotation: Fancade[Vector3], after: () => Fancade[Unit]): Fancade[Unit] = ??? + override def setMass(obj: Fancade[Obj], mass: Fancade[Float], after: () => Fancade[Unit]): Fancade[Unit] = ??? override def setFriction(obj: Fancade[Obj], friction: Fancade[Float]): Fancade[Unit] = ??? override def setBounciness(obj: Fancade[Obj], bounciness: Fancade[Float]): Fancade[Unit] = ??? override def setGravity(gravity: Fancade[Vector3]): Fancade[Unit] = ??? @@ -174,26 +181,25 @@ object Fanscript { override def onTouch(onTouch: Fancade[Touch] => Fancade[Unit]): Fancade[Unit] = ??? override def addNumbers(a: Fancade[Float], b: Fancade[Float]): Fancade[Float] = - Fix(FancadeF.Use( + Fix(FancadeF.Create( Vector(a, b), Exists(Template( BlockDefinition.AddNumbers, () )), Vector(BlockDefinition.AddNumbers.input1, BlockDefinition.AddNumbers.input2), - Vector(BlockDefinition.AddNumbers.output), - None + Vector(BlockDefinition.AddNumbers.output) )) override def screenSizeWidth(screenSize: Fancade[ScreenSize]): Fancade[Float] = Fix(FancadeF.Select( - Fix.un(screenSize), - (0 to 0) + screenSize, + Vector(0) )) override def screenSizeHeight(screenSize: Fancade[ScreenSize]): Fancade[Float] = Fix(FancadeF.Select( - Fix.un(screenSize), - (1 to 1) + screenSize, + Vector(1) )) override def positionPosition(position: Fancade[Position]): Fancade[Vector3] = ??? diff --git a/tagless/src/main/scala/tf/bug/fancadetagless/Main.scala b/tagless/src/main/scala/tf/bug/fancadetagless/Main.scala index 095744d..ea0fb23 100644 --- a/tagless/src/main/scala/tf/bug/fancadetagless/Main.scala +++ b/tagless/src/main/scala/tf/bug/fancadetagless/Main.scala @@ -19,7 +19,7 @@ object Main extends IOApp { override def run[G[_]](implicit interp: Fanscript[G]): G[Unit] = { val screenSize = interp.screenSize val screenWidth = interp.screenSizeWidth(screenSize) - val inspectWidth = interp.inspect(screenWidth) + val inspectWidth = interp.inspect(screenWidth, () => interp.unit) inspectWidth } }