Initial commit
This commit is contained in:
commit
d4389b6f50
12 changed files with 356 additions and 0 deletions
110
.gitignore
vendored
Normal file
110
.gitignore
vendored
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
|
||||||
|
# Created by https://www.gitignore.io/api/sbt,scala,intellij+all
|
||||||
|
# Edit at https://www.gitignore.io/?templates=sbt,scala,intellij+all
|
||||||
|
|
||||||
|
### Intellij+all ###
|
||||||
|
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
|
||||||
|
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||||
|
|
||||||
|
# User-specific stuff
|
||||||
|
.idea/**/workspace.xml
|
||||||
|
.idea/**/tasks.xml
|
||||||
|
.idea/**/usage.statistics.xml
|
||||||
|
.idea/**/dictionaries
|
||||||
|
.idea/**/shelf
|
||||||
|
|
||||||
|
# Generated files
|
||||||
|
.idea/**/contentModel.xml
|
||||||
|
|
||||||
|
# Sensitive or high-churn files
|
||||||
|
.idea/**/dataSources/
|
||||||
|
.idea/**/dataSources.ids
|
||||||
|
.idea/**/dataSources.local.xml
|
||||||
|
.idea/**/sqlDataSources.xml
|
||||||
|
.idea/**/dynamic.xml
|
||||||
|
.idea/**/uiDesigner.xml
|
||||||
|
.idea/**/dbnavigator.xml
|
||||||
|
|
||||||
|
# Gradle
|
||||||
|
.idea/**/gradle.xml
|
||||||
|
.idea/**/libraries
|
||||||
|
|
||||||
|
# Gradle and Maven with auto-import
|
||||||
|
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||||
|
# since they will be recreated, and may cause churn. Uncomment if using
|
||||||
|
# auto-import.
|
||||||
|
# .idea/modules.xml
|
||||||
|
# .idea/*.iml
|
||||||
|
# .idea/modules
|
||||||
|
# *.iml
|
||||||
|
# *.ipr
|
||||||
|
|
||||||
|
# CMake
|
||||||
|
cmake-build-*/
|
||||||
|
|
||||||
|
# Mongo Explorer plugin
|
||||||
|
.idea/**/mongoSettings.xml
|
||||||
|
|
||||||
|
# File-based project format
|
||||||
|
*.iws
|
||||||
|
|
||||||
|
# IntelliJ
|
||||||
|
out/
|
||||||
|
|
||||||
|
# mpeltonen/sbt-idea plugin
|
||||||
|
.idea_modules/
|
||||||
|
|
||||||
|
# JIRA plugin
|
||||||
|
atlassian-ide-plugin.xml
|
||||||
|
|
||||||
|
# Cursive Clojure plugin
|
||||||
|
.idea/replstate.xml
|
||||||
|
|
||||||
|
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||||
|
com_crashlytics_export_strings.xml
|
||||||
|
crashlytics.properties
|
||||||
|
crashlytics-build.properties
|
||||||
|
fabric.properties
|
||||||
|
|
||||||
|
# Editor-based Rest Client
|
||||||
|
.idea/httpRequests
|
||||||
|
|
||||||
|
# Android studio 3.1+ serialized cache file
|
||||||
|
.idea/caches/build_file_checksums.ser
|
||||||
|
|
||||||
|
### Intellij+all Patch ###
|
||||||
|
# Ignores the whole .idea folder and all .iml files
|
||||||
|
# See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360
|
||||||
|
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
# Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023
|
||||||
|
|
||||||
|
*.iml
|
||||||
|
modules.xml
|
||||||
|
.idea/misc.xml
|
||||||
|
*.ipr
|
||||||
|
|
||||||
|
# Sonarlint plugin
|
||||||
|
.idea/sonarlint
|
||||||
|
|
||||||
|
### SBT ###
|
||||||
|
# Simple Build Tool
|
||||||
|
# http://www.scala-sbt.org/release/docs/Getting-Started/Directories.html#configuring-version-control
|
||||||
|
|
||||||
|
dist/*
|
||||||
|
target/
|
||||||
|
lib_managed/
|
||||||
|
src_managed/
|
||||||
|
project/boot/
|
||||||
|
project/plugins/project/
|
||||||
|
.history
|
||||||
|
.cache
|
||||||
|
.lib/
|
||||||
|
|
||||||
|
### Scala ###
|
||||||
|
*.class
|
||||||
|
*.log
|
||||||
|
*.metals
|
||||||
|
|
||||||
|
# End of https://www.gitignore.io/api/sbt,scala,intellij+all
|
14
build.sbt
Normal file
14
build.sbt
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
lazy val core = (project in file("core")).settings(
|
||||||
|
organization := "tf.bug",
|
||||||
|
name := "fancadetagless",
|
||||||
|
version := "0.1.0",
|
||||||
|
scalaVersion := "2.13.1",
|
||||||
|
libraryDependencies ++= Seq(
|
||||||
|
"org.scala-graph" %% "graph-core" % "1.13.2",
|
||||||
|
"com.chuusai" %% "shapeless" % "2.3.3",
|
||||||
|
"org.typelevel" %% "cats-core" % "2.1.1",
|
||||||
|
"org.typelevel" %% "cats-effect" % "2.1.2",
|
||||||
|
"io.chrisdavenport" %% "fuuid" % "0.3.0",
|
||||||
|
),
|
||||||
|
addCompilerPlugin("org.typelevel" %% "kind-projector" % "0.11.0" cross CrossVersion.full),
|
||||||
|
)
|
19
core/src/main/scala/tf/bug/fancadetagless/Block.scala
Normal file
19
core/src/main/scala/tf/bug/fancadetagless/Block.scala
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
package tf.bug.fancadetagless
|
||||||
|
|
||||||
|
import cats.effect.Sync
|
||||||
|
import cats.implicits._
|
||||||
|
import io.chrisdavenport.fuuid.FUUID
|
||||||
|
|
||||||
|
case class Block(uuid: FUUID, make: Make, pins: Set[Pin])
|
||||||
|
|
||||||
|
object Block {
|
||||||
|
|
||||||
|
def fromMake[F[_]](make: Make)(implicit s: Sync[F]): F[Block] = {
|
||||||
|
val uuid = FUUID.randomFUUID[F]
|
||||||
|
val pins = make.pins.traverse[F, Pin] { case (tpe, dir) => Pin.fromMake(tpe, dir) }
|
||||||
|
(uuid, pins).mapN {
|
||||||
|
case (u, v) => Block(u, make, v.toSet)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
41
core/src/main/scala/tf/bug/fancadetagless/Encoding.scala
Normal file
41
core/src/main/scala/tf/bug/fancadetagless/Encoding.scala
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
package tf.bug.fancadetagless
|
||||||
|
|
||||||
|
import cats.effect.Sync
|
||||||
|
import shapeless._
|
||||||
|
|
||||||
|
trait Encoding[A] {
|
||||||
|
|
||||||
|
def pins: Vector[PinType]
|
||||||
|
|
||||||
|
def encodeConstant(a: A): Vector[Make]
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
object Encoding extends ProductTypeClassCompanion[Encoding] {
|
||||||
|
|
||||||
|
object typeClass extends ProductTypeClass[Encoding] {
|
||||||
|
|
||||||
|
override def product[H, T <: HList](ch: Encoding[H], ct: Encoding[T]): Encoding[H :: T] = new Encoding[H :: T] {
|
||||||
|
override def pins: Vector[PinType] = ch.pins ++ ct.pins
|
||||||
|
override def encodeConstant(a: H :: T): Vector[Make] = ch.encodeConstant(a.head) ++ ct.encodeConstant(a.tail)
|
||||||
|
}
|
||||||
|
|
||||||
|
override def emptyProduct: Encoding[HNil] = new Encoding[HNil] {
|
||||||
|
override def pins: Vector[PinType] = Vector.empty
|
||||||
|
override def encodeConstant(a: HNil): Vector[Make] = Vector.empty
|
||||||
|
}
|
||||||
|
|
||||||
|
override def project[F, G](instance: => Encoding[G], to: F => G, from: G => F): Encoding[F] = new Encoding[F] {
|
||||||
|
override def pins: Vector[PinType] = instance.pins
|
||||||
|
override def encodeConstant(a: F): Vector[Make] = instance.encodeConstant(to(a))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
implicit val floatEncoding: Encoding[Float] = new Encoding[Float] {
|
||||||
|
override def pins: Vector[PinType] = Vector(PinType.Number)
|
||||||
|
override def encodeConstant(a: Float): Vector[Make] =
|
||||||
|
Vector(Make.Builtin(s"Value[Number]($a)", pins.map((_, PinDirection.Outward))))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
9
core/src/main/scala/tf/bug/fancadetagless/Make.scala
Normal file
9
core/src/main/scala/tf/bug/fancadetagless/Make.scala
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
package tf.bug.fancadetagless
|
||||||
|
|
||||||
|
sealed trait Make {
|
||||||
|
def pins: Vector[(PinType, PinDirection)]
|
||||||
|
}
|
||||||
|
object Make {
|
||||||
|
case class Builtin(name: String, pins: Vector[(PinType, PinDirection)]) extends Make
|
||||||
|
case class Custom(world: World, pins: Vector[(PinType, PinDirection)]) extends Make
|
||||||
|
}
|
29
core/src/main/scala/tf/bug/fancadetagless/Pin.scala
Normal file
29
core/src/main/scala/tf/bug/fancadetagless/Pin.scala
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
package tf.bug.fancadetagless
|
||||||
|
|
||||||
|
import cats.effect.Sync
|
||||||
|
import cats.implicits._
|
||||||
|
import io.chrisdavenport.fuuid.FUUID
|
||||||
|
|
||||||
|
case class Pin(uuid: FUUID, tpe: PinType, dir: PinDirection)
|
||||||
|
object Pin {
|
||||||
|
|
||||||
|
def fromMake[F[_]](tpe: PinType, dir: PinDirection)(implicit s: Sync[F]): F[Pin] = {
|
||||||
|
val uuid: F[FUUID] = FUUID.randomFUUID[F]
|
||||||
|
uuid.map(Pin(_, tpe, dir))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed trait PinType
|
||||||
|
object PinType {
|
||||||
|
case object Pull extends PinType
|
||||||
|
case object Number extends PinType
|
||||||
|
case object Truth extends PinType
|
||||||
|
case class Quoted[T <: PinType](v: T) extends PinType
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed trait PinDirection
|
||||||
|
object PinDirection {
|
||||||
|
case object Inward extends PinDirection
|
||||||
|
case object Outward extends PinDirection
|
||||||
|
}
|
3
core/src/main/scala/tf/bug/fancadetagless/Pins.scala
Normal file
3
core/src/main/scala/tf/bug/fancadetagless/Pins.scala
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
package tf.bug.fancadetagless
|
||||||
|
|
||||||
|
case class Pins[A](pins: Vector[Pin])(implicit enc: Encoding[A])
|
6
core/src/main/scala/tf/bug/fancadetagless/World.scala
Normal file
6
core/src/main/scala/tf/bug/fancadetagless/World.scala
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
package tf.bug.fancadetagless
|
||||||
|
|
||||||
|
import scalax.collection.Graph
|
||||||
|
import scalax.collection.GraphEdge.DiHyperEdge
|
||||||
|
|
||||||
|
case class World(blocks: Set[Block], connections: Graph[Pin, DiHyperEdge])
|
42
core/src/main/scala/tf/bug/fancadetagless/package.scala
Normal file
42
core/src/main/scala/tf/bug/fancadetagless/package.scala
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
package tf.bug
|
||||||
|
|
||||||
|
import cats.data.StateT
|
||||||
|
import cats.effect.Sync
|
||||||
|
import cats.implicits._
|
||||||
|
import io.chrisdavenport.fuuid.FUUID
|
||||||
|
import scalax.collection.GraphEdge.DiHyperEdge
|
||||||
|
|
||||||
|
package object fancadetagless {
|
||||||
|
|
||||||
|
type FancadeT[F[_], A] = StateT[F, World, Pins[A]]
|
||||||
|
object FancadeT {
|
||||||
|
def make[F[_]](make: Make)(implicit s: Sync[F]): FancadeT[F, Unit] = {
|
||||||
|
val block = Block.fromMake[F](make)
|
||||||
|
StateT.apply { w =>
|
||||||
|
block.map { b =>
|
||||||
|
(w.copy(w.blocks + b), Pins(b.pins.toVector))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def constant[F[_], A](a: A)(implicit encoding: Encoding[A], s: Sync[F]): FancadeT[F, A] = {
|
||||||
|
val makes = encoding.encodeConstant(a)
|
||||||
|
val blocks = makes.traverse[F, Block](Block.fromMake[F])
|
||||||
|
StateT.apply { world =>
|
||||||
|
for {
|
||||||
|
b <- blocks
|
||||||
|
s = b.toSet
|
||||||
|
nw = world.copy(blocks = world.blocks ++ s)
|
||||||
|
} yield (nw, Pins(b.flatMap(_.pins)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def connect[F[_]](from: Pin, to: Pin)(implicit s: Sync[F]): FancadeT[F, Unit] = {
|
||||||
|
StateT.apply { w =>
|
||||||
|
val newConn = DiHyperEdge(from, to)
|
||||||
|
s.pure(w.copy(connections = w.connections incl newConn), Pins(Vector.empty))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
59
core/src/main/scala/tf/bug/fancadetagless/test/Calc.scala
Normal file
59
core/src/main/scala/tf/bug/fancadetagless/test/Calc.scala
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
package tf.bug.fancadetagless.test
|
||||||
|
|
||||||
|
import cats.effect.Sync
|
||||||
|
import tf.bug.fancadetagless.{FancadeT, Make, PinDirection, PinType, Pins}
|
||||||
|
|
||||||
|
trait Calc[W[_]] {
|
||||||
|
|
||||||
|
def lift(f: Float): W[Float]
|
||||||
|
|
||||||
|
def add(a: W[Float], b: W[Float]): W[Float]
|
||||||
|
def sub(a: W[Float], b: W[Float]): W[Float]
|
||||||
|
def mul(a: W[Float], b: W[Float]): W[Float]
|
||||||
|
def div(a: W[Float], b: W[Float]): W[Float]
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
object Calc {
|
||||||
|
|
||||||
|
trait Program[R] {
|
||||||
|
def apply[F[_]](int: Calc[F]): F[R]
|
||||||
|
}
|
||||||
|
|
||||||
|
case class FancadeCalc[F[_]]()(implicit s: Sync[F]) extends Calc[FancadeT[F, *]] {
|
||||||
|
|
||||||
|
override def lift(f: Float): FancadeT[F, Float] = FancadeT.constant(f)
|
||||||
|
|
||||||
|
override def add(a: FancadeT[F, Float], b: FancadeT[F, Float]): FancadeT[F, Float] =
|
||||||
|
for {
|
||||||
|
addBlock <- FancadeT.make(Make.Builtin("Add[Number]", Vector(
|
||||||
|
(PinType.Number, PinDirection.Inward),
|
||||||
|
(PinType.Number, PinDirection.Inward),
|
||||||
|
(PinType.Number, PinDirection.Outward)
|
||||||
|
)))
|
||||||
|
ab <- a
|
||||||
|
bb <- b
|
||||||
|
_ <- FancadeT.connect(ab.pins.head, addBlock.pins(0))
|
||||||
|
_ <- FancadeT.connect(bb.pins.head, addBlock.pins(1))
|
||||||
|
} yield Pins(addBlock.pins.drop(2))
|
||||||
|
|
||||||
|
override def sub(a: FancadeT[F, Float], b: FancadeT[F, Float]): FancadeT[F, Float] = ???
|
||||||
|
|
||||||
|
override def mul(a: FancadeT[F, Float], b: FancadeT[F, Float]): FancadeT[F, Float] = ???
|
||||||
|
|
||||||
|
override def div(a: FancadeT[F, Float], b: FancadeT[F, Float]): FancadeT[F, Float] =
|
||||||
|
for {
|
||||||
|
addBlock <- FancadeT.make(Make.Builtin("Divide[Number]", Vector(
|
||||||
|
(PinType.Number, PinDirection.Inward),
|
||||||
|
(PinType.Number, PinDirection.Inward),
|
||||||
|
(PinType.Number, PinDirection.Outward)
|
||||||
|
)))
|
||||||
|
ab <- a
|
||||||
|
bb <- b
|
||||||
|
_ <- FancadeT.connect(ab.pins.head, addBlock.pins(0))
|
||||||
|
_ <- FancadeT.connect(bb.pins.head, addBlock.pins(1))
|
||||||
|
} yield Pins(addBlock.pins.drop(2))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
23
core/src/main/scala/tf/bug/fancadetagless/test/Main.scala
Normal file
23
core/src/main/scala/tf/bug/fancadetagless/test/Main.scala
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
package tf.bug.fancadetagless.test
|
||||||
|
|
||||||
|
import cats.effect.{ExitCode, IO, IOApp}
|
||||||
|
import cats.implicits._
|
||||||
|
import scalax.collection.Graph
|
||||||
|
import tf.bug.fancadetagless.World
|
||||||
|
|
||||||
|
object Main extends IOApp {
|
||||||
|
override def run(args: List[String]): IO[ExitCode] = {
|
||||||
|
object TwoPlusThreeOverFour extends Calc.Program[Float] {
|
||||||
|
override def apply[F[_]](int: Calc[F]): F[Float] =
|
||||||
|
int.div(
|
||||||
|
int.add(
|
||||||
|
int.lift(2.0f),
|
||||||
|
int.lift(3.0f)
|
||||||
|
),
|
||||||
|
int.lift(4.0f)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
val ft = TwoPlusThreeOverFour(Calc.FancadeCalc[IO])
|
||||||
|
ft.runS(World(Set.empty, Graph.empty)).flatMap(w => IO(println(w))).as(ExitCode.Success)
|
||||||
|
}
|
||||||
|
}
|
1
project/build.properties
Normal file
1
project/build.properties
Normal file
|
@ -0,0 +1 @@
|
||||||
|
sbt.version = 1.3.9
|
Loading…
Reference in a new issue