diff --git a/build.sbt b/build.sbt
index cd9bca7dc..518a53cde 100644
--- a/build.sbt
+++ b/build.sbt
@@ -55,12 +55,6 @@ lazy val bench = commonProject("bench", "vapors")
Test / parallelExecution := false,
)
-lazy val core = commonProject("core")
- .dependsOn(`core-v1`)
- .settings(
- libraryDependencies ++= CoreProject.all(scalaVersion.value),
- )
-
lazy val `core-v1` = commonProject("core-v1", "vapors.v1")
.settings(
libraryDependencies ++= CoreV1Project.all,
diff --git a/core/src/main/scala/vapors/algebra/CaptureP.scala b/core/src/main/scala/vapors/algebra/CaptureP.scala
deleted file mode 100644
index d5dfee25c..000000000
--- a/core/src/main/scala/vapors/algebra/CaptureP.scala
+++ /dev/null
@@ -1,141 +0,0 @@
-package com.rallyhealth
-
-package vapors.algebra
-
-import vapors.data.TypedFact
-import vapors.interpreter.{ExprInput, ExprOutput}
-
-import cats.{Eval, Monoid}
-
-import scala.annotation.implicitNotFound
-
-@implicitNotFound(
- """
-Missing implicit CaptureP[${V}, ${R}, P] (where P is a custom parameter type that you choose via implicit).
-Currently, P is inferred as ${P}.
-
-Expression builders rely on the implicit CaptureP in scope to determine the concrete type of P.
-CaptureP.unit will be used by default unless another implicit is in scope and P will be inferred as Unit.
-However, if the compiler has trouble inferring other arguments, such as V or R, then it may also fail to infer P.
-
-Is the compiler is unable to infer either V (${V}) or R (${R})?
-If so, you may need to check the types of your expression and make sure they match.
-
-Failed to find a CaptureP for the following expression:
-""",
-)
-trait CaptureP[V, R, P] {
-
- /**
- * Folds the captured parameters of the sub-expressions with the captured parameter of this expression.
- *
- * @param expr the expression that is being evaluated
- * @param input the input to the expression
- * @param output the output of the expression given the input
- * @param subExprParams the captured parameters of the sub-expressions.
- * NOTE: This is not a good data structure for parameters because you cannot tell where they
- * come from.
- */
- def foldToParam(
- expr: Expr[V, R, P],
- input: ExprInput[V],
- output: ExprOutput[R],
- subExprParams: List[Eval[P]],
- ): Eval[P]
-}
-
-object CaptureP extends CaptureUnitLowPriorityImplicit {
-
- /**
- * Captures the type parameter from facts with a value of type [[T]].
- */
- trait FromFactsOfType[T, R, P] extends CaptureP[Seq[TypedFact[T]], R, P]
-
- /**
- * Captures the type parameter from facts with a value of type [[T]] (assuming [[P]] is a [[Monoid]])
- *
- * @see [[AsMonoid]]
- */
- abstract class AsMonoidFromFactsOfType[T, R, P : Monoid]
- extends AsMonoid[Seq[TypedFact[T]], R, P] // TODO: Use Iterable instead of Seq?
- with FromFactsOfType[T, R, P]
-
- // TODO: This is not very safe. Nodes will often combine the params of their input expressions and sub expressions.
- // It might not be safe to assume that Monoid is enough to capture the expected behavior for combining the
- // parameters in this situation. Maybe there is a way to group sub-expressions better than List?
- /**
- * Capture a [[Monoid]]-like parameter and combine all captured params of the current node's children.
- *
- * You must still define how to extract the parameter from the current node and combine it with its children.
- *
- * @note some [[Expr]] nodes lump params from different sub-expressions into the same list. If this doesn't
- * work for you, then you must define a [[CaptureP]] and handle combining these sub-expression results
- * in whatever way works for you.
- *
- * @note this can be used in conjunction with extending [[AsMonoidCompanion]] in the surrounding object
- * to define a standard fallback for unmatched types (assuming your parameter is a [[Monoid]]).
- */
- abstract class AsMonoid[V, R, P : Monoid] extends CaptureP[V, R, P] {
-
- protected val empty: P = Monoid[P].empty
-
- override def foldToParam(
- expr: Expr[V, R, P],
- input: ExprInput[V],
- output: ExprOutput[R],
- subExprParams: List[Eval[P]],
- ): Eval[P] = {
- val combinedChildren = Monoid[Eval[P]].combineAll(subExprParams)
- combinedChildren.flatMap(foldWithParentParam(expr, input, output, _))
- }
-
- protected def foldWithParentParam(
- expr: Expr[V, R, P],
- input: ExprInput[V],
- output: ExprOutput[R],
- processedChildren: P,
- ): Eval[P]
- }
-
- /**
- * Captures all child node params, combines them, and passes them up as this node's param.
- *
- * @note this ignores the context of the node it matches. This should only be used as a fallback
- * for having no definition of how to capture a parameter with the given types, but needing
- * to pass the captured params from this node's children up to the next parent.
- */
- final class AsMonoidAndPass[V, R, P : Monoid] extends AsMonoid[V, R, P] {
-
- override protected def foldWithParentParam(
- expr: Expr[V, R, P],
- input: ExprInput[V],
- output: ExprOutput[R],
- processedChildren: P,
- ): Eval[P] = Eval.now(processedChildren)
-
- override def toString: String = "captureParamAndPass"
- }
-
- /**
- * Extend this in your companion object to get a low-priority implicit for capturing your [[Monoid]] parameter
- * for types that you don't specifically select.
- */
- abstract class AsMonoidCompanion[P](protected implicit final val P: Monoid[P]) {
- implicit def captureParamAndPass[V, R]: CaptureP[V, R, P] = new AsMonoidAndPass[V, R, P]
- }
-}
-
-sealed trait CaptureUnitLowPriorityImplicit {
-
- implicit def captureUnit[V, R]: CaptureP[V, R, Unit] = new CaptureP[V, R, Unit] {
-
- override final def foldToParam(
- expr: Expr[V, R, Unit],
- input: ExprInput[V],
- output: ExprOutput[R],
- subExprParams: List[Eval[Unit]],
- ): Eval[Unit] = Eval.Unit
-
- override final def toString: String = "captureUnit"
- }
-}
diff --git a/core/src/main/scala/vapors/algebra/Expr.scala b/core/src/main/scala/vapors/algebra/Expr.scala
deleted file mode 100644
index 4c56d380d..000000000
--- a/core/src/main/scala/vapors/algebra/Expr.scala
+++ /dev/null
@@ -1,594 +0,0 @@
-package com.rallyhealth
-
-package vapors.algebra
-
-import vapors.data._
-import vapors.interpreter.{ExprOutput, InterpretExprAsResultFn}
-import vapors.lens.NamedLens
-import vapors.logic.{Conjunction, Disjunction, Negation}
-import vapors.math._
-
-import cats._
-import cats.data.NonEmptyList
-import shapeless.{HList, Typeable}
-
-import scala.collection.MapView
-
-/**
- * The core expression algebra.
- *
- * In essence, you can view this as a function from F[V] => R with a custom parameter that you can capture at each
- * point in the expression using a [[CaptureP]].
- *
- * This expression is folded over to produce serialized versions of the expression as well as the evaluator function.
- *
- * @see [[InterpretExprAsResultFn]]
- *
- * V = Input Value type
- * R = Return type
- * P = Captured param
- */
-sealed abstract class Expr[V, R, P] {
-
- def visit[G[_]](v: Expr.Visitor[V, P, G]): G[R]
-
- def capture: CaptureP[V, R, P]
-}
-
-object Expr {
-
- import cats.{~>, Id}
-
- trait Visitor[V, P, G[_]] extends (Expr[V, *, P] ~> G) {
- // Please keep the following methods in alphabetical order
- override final def apply[R](fa: Expr[V, R, P]): G[R] = fa.visit(this)
- def visitAddOutputs[R : Addition](expr: AddOutputs[V, R, P]): G[R]
- def visitAnd[R : Conjunction : ExtractBoolean](expr: And[V, R, P]): G[R]
- def visitCollectSomeOutput[M[_] : Foldable, U, R : Monoid](expr: CollectFromOutput[V, M, U, R, P]): G[R]
- def visitConcatOutput[M[_] : MonoidK, R](expr: ConcatOutput[V, M, R, P]): G[M[R]]
- def visitConstOutput[R](expr: ConstOutput[V, R, P]): G[R]
- def visitCustomFunction[A, R](expr: CustomFunction[V, A, R, P]): G[R]
- def visitDefine[M[_] : Foldable, T](expr: Define[M, T, P]): G[FactSet]
- def visitDivideOutputs[R : Division](expr: DivideOutputs[V, R, P]): G[R]
- def visitEmbed[R](expr: Embed[V, R, P]): G[R]
- def visitExistsInOutput[M[_] : Foldable, U](expr: ExistsInOutput[V, M, U, P]): G[Boolean]
- def visitExponentiateOutputs(expr: ExponentiateOutputs[V, P]): G[Double]
- def visitFilterOutput[M[_] : Foldable : FunctorFilter, R](expr: FilterOutput[V, M, R, P]): G[M[R]]
- def visitFlatMapOutput[M[_] : Foldable : FlatMap, U, X](expr: FlatMapOutput[V, M, U, X, P]): G[M[X]]
- def visitGroupOutput[M[_] : Foldable, U : Order, K](expr: GroupOutput[V, M, U, K, P]): G[MapView[K, Seq[U]]]
- def visitMapOutput[M[_] : Foldable : Functor, U, R](expr: MapOutput[V, M, U, R, P]): G[M[R]]
- def visitMultiplyOutputs[R : Multiplication](expr: MultiplyOutputs[V, R, P]): G[R]
- def visitNegativeOutput[R : Negative](expr: NegativeOutput[V, R, P]): G[R]
- def visitNot[R : Negation](expr: Not[V, R, P]): G[R]
- def visitOr[R : Disjunction : ExtractBoolean](expr: Or[V, R, P]): G[R]
- def visitOutputIsEmpty[M[_] : Foldable, R](expr: OutputIsEmpty[V, M, R, P]): G[Boolean]
- def visitOutputWithinSet[R](expr: OutputWithinSet[V, R, P]): G[Boolean]
- def visitOutputWithinWindow[R](expr: OutputWithinWindow[V, R, P]): G[Boolean]
- def visitFoldOutput[M[_] : Foldable, R : Monoid](expr: FoldOutput[V, M, R, P]): G[R]
- def visitReturnInput(expr: ReturnInput[V, P]): G[V]
- def visitSelectFromOutput[S, R](expr: SelectFromOutput[V, S, R, P]): G[R]
- def visitSortOutput[M[_], R](expr: SortOutput[V, M, R, P]): G[M[R]]
- def visitSubtractOutputs[R : Subtraction](expr: SubtractOutputs[V, R, P]): G[R]
- def visitTakeFromOutput[M[_] : Traverse : TraverseFilter, R](expr: TakeFromOutput[V, M, R, P]): G[M[R]]
- def visitUsingDefinitions[R](expr: UsingDefinitions[V, R, P]): G[R]
- def visitWhen[R](expr: When[V, R, P]): G[R]
- def visitWrapOutput[L, R](expr: WrapOutput[V, L, R, P]): G[R]
- def visitWrapOutputHList[T <: HList, R](expr: WrapOutputHList[V, T, R, P]): G[R]
- def visitWrapOutputSeq[R](expr: WrapOutputSeq[V, R, P]): G[Seq[R]]
- def visitWithFactsOfType[T, R](expr: WithFactsOfType[T, R, P]): G[R]
- def visitZipOutput[M[_] : Align : FunctorFilter, L <: HList, R](expr: ZipOutput[V, M, L, R, P]): G[M[R]]
- }
-
- /*
- * Please keep the following expressions in the same order in Expr.scala and ExprResult.scala.
- * It makes it easier to find the mirror node.
- *
- * While alphabetical seems like the best way to organize these classes, in practice
- * certain nodes that are related to each other (like addition and subtraction) will have
- * very similar implementations and will likely need to be refactored in identical ways.
- *
- * The Visitor and its subclasses use alphabetical sorting because their definitions
- * are derivative and it is practically impossible to forget to update their implementation
- * without the compiler complaining.
- */
-
- // TODO: Should constants always act as their own evidence?
- /**
- * Uses the given value as the output of this expression and ignores the input.
- */
- final case class ConstOutput[V, R, P](
- value: R,
- evidence: Evidence,
- capture: CaptureP[V, R, P],
- ) extends Expr[V, R, P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[R] = v.visitConstOutput(this)
- }
-
- /**
- * Returns the input [[V]] values as the output of this expression node.
- *
- * Essentially, this is the [[identity]] function represented as an [[Expr]].
- *
- * @note many of the other [[Expr]] nodes will take an `inputExpr`. This is useful for passing a selected value
- * from the input into an expression operation, so that you can operate on it as the output parameter.
- * This is useful to avoid needing to define separate nodes for the input / output sides of an expression.
- * Instead, you just take an `inputExpr` and you can pass this node to move the input into the output.
- */
- final case class ReturnInput[V, P](capture: CaptureP[V, V, P]) extends Expr[V, V, P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[V] = v.visitReturnInput(this)
- }
-
- /**
- * The input of the expression is replaced with the [[FactTable]] and the output of the [[embeddedExpr]]
- * is returned.
- *
- * This makes it possible to embed separate / reusable sub-expressions that don't depend on any contextual input
- * into any sub-expression to substitute or defer the result to a separate computation.
- *
- * Typically, these nodes only exist to satisfy the type system and are skipped by visitors, however, the
- * input to the [[Embed]] node can be captured via the input parameters and folded into the final result.
- */
- final case class Embed[V, R, P](
- embeddedExpr: Expr[FactTable, R, P],
- capture: CaptureP[V, R, P],
- ) extends Expr[V, R, P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[R] = v.visitEmbed(this)
- }
-
- /**
- * A common top-level expression that defines an output without any input beyond the initial [[FactTable]].
- *
- * The given [[FactTypeSet]] is used to select the matching facts from the [[FactTable]] and provide them
- * as both the input value and [[Evidence]] to the [[subExpr]].
- *
- * @note these expressions can be easily dropped into any place that accepts the [[subExpr]] output type `R`
- * by wrapping the expression in an [[Embed]].
- */
- final case class WithFactsOfType[T, R, P](
- factTypeSet: FactTypeSet[T],
- subExpr: Expr[Seq[TypedFact[T]], R, P],
- capture: CaptureP[FactTable, R, P],
- ) extends Expr[FactTable, R, P] {
- override def visit[G[_]](v: Visitor[FactTable, P, G]): G[R] = v.visitWithFactsOfType(this)
- }
-
- /**
- * Same as [[Define]], but captures and hides common type parameters to avoid issues with wild-cards on
- * higher-kinded type parameters.
- *
- * @note I'm using a sealed trait instead of a type alias to avoid expressions from matching the type
- * that do not supply the requisite metadata (provided by the only subclass [[Define]]).
- *
- * @see https://github.com/scala/bug/issues/8039 for more info
- */
- sealed trait Definition[P] extends Expr[FactTable, FactSet, P]
-
- /**
- * Define or add another source for a [[FactType]].
- *
- * When used in conjunction with [[UsingDefinitions]], this node allows you to update the [[FactTable]]
- * used by sub-expressions so that they can now have access to the fact values returned by the [[definitionExpr]].
- */
- final case class Define[M[_] : Foldable, T, P](
- factType: FactType[T],
- definitionExpr: Expr[FactTable, M[T], P],
- capture: CaptureP[FactTable, FactSet, P],
- ) extends Definition[P] {
- override def visit[G[_]](v: Visitor[FactTable, P, G]): G[FactSet] = v.visitDefine(this)
- }
-
- /**
- * Combines all [[Definition]]s and adds the resulting facts to the [[FactTable]], which is then provided
- * to the [[subExpr]] during evaluation.
- *
- * @note this is a way to sequence the evaluation of an expression to occur after the fact definitions it
- * depends on have been evaluated and added to the [[FactTable]] as input. If your fact definitions
- * require other facts to be defined for their computation, then you must wrap them with a
- * [[UsingDefinitions]] expression node as well. Repeating this process until the directed acyclic
- * graph of dependencies has been sequenced properly. Including the same fact definition twice is
- * likely idempotent, however, there is no currently machinery to avoid unnecessary re-computation.
- */
- final case class UsingDefinitions[V, R, P](
- definitions: Vector[Definition[P]],
- subExpr: Expr[V, R, P],
- capture: CaptureP[V, R, P],
- ) extends Expr[V, R, P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[R] = v.visitUsingDefinitions(this)
- }
-
- /**
- * A custom (ideally) pure total function.
- *
- * In practice, it is possible for custom functions to throw exceptions. This is something
- * I hope to address in the future, but it will be up to convention to handle exceptions
- * by lifting them into the expression language. It is always possible to define them wrong.
- *
- * @param inputExpr an expression that produces the argument value
- * @param name the name of the expression for debugging purposes
- * @param evaluate an (ideally) pure total function to apply to the argument type
- */
- final case class CustomFunction[V, A : Typeable, R, P](
- inputExpr: Expr[V, A, P],
- name: String,
- evaluate: A => R,
- capture: CaptureP[V, R, P],
- ) extends Expr[V, R, P] { // TODO: Should this return a Try[R]? Either[Failure, R]?
- override def visit[G[_]](v: Visitor[V, P, G]): G[R] = v.visitCustomFunction(this)
- }
-
- /**
- * Returns the [[Conjunction]] of all results of the given input expressions.
- *
- * All evidence is tracked using the logic defined in [[ExprOutput.conjunction]]
- *
- * @note this does not short-circuit.
- * [[Evidence]] for all input values are used in deciding the evidence for the result.
- *
- * If you want to apply short-circuiting, you must implement it within the algebra using sorting,
- * filtering, and limiting operators.
- */
- final case class And[V, R : Conjunction : ExtractBoolean, P](
- inputExprList: NonEmptyList[Expr[V, R, P]],
- capture: CaptureP[V, R, P],
- ) extends Expr[V, R, P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[R] = v.visitAnd(this)
- }
-
- /**
- * Returns the [[Disjunction]] of all results of the given input expressions.
- *
- * All evidence is tracked using the logic defined in [[ExprOutput.disjunction]]
- *
- * @note this does not short-circuit.
- * [[Evidence]] for all input values are used in deciding the evidence for the result.
- *
- * If you want to apply short-circuiting, you must implement it within the algebra using sorting,
- * filtering, and limiting operators.
- */
- final case class Or[V, R : Disjunction : ExtractBoolean, P](
- inputExprList: NonEmptyList[Expr[V, R, P]],
- capture: CaptureP[V, R, P],
- ) extends Expr[V, R, P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[R] = v.visitOr(this)
- }
-
- /**
- * Negates the output from the given [[inputExpr]], but keeps the same evidence.
- *
- * Negation has no impact on the [[Evidence]]. Negation of a false value with evidence
- * becomes a true value with the same evidence, and negation of a true value with no
- * evidence becomes a false value with no evidence. How the [[Evidence.none]] is interpreted
- * is up to the caller, but any boolean-like outcome with no Evidence should be treated
- * identically.
- */
- final case class Not[V, R : Negation, P](
- inputExpr: Expr[V, R, P],
- capture: CaptureP[V, R, P],
- ) extends Expr[V, R, P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[R] = v.visitNot(this)
- }
-
- /**
- * Conditional expression that depends on the output of a given boolean expression to determine whether to
- * evaluate the [[conditionBranches]] or the [[defaultExpr]].
- *
- * @note this expression does short-circuit on the first branch whose condition is met
- */
- final case class When[V, R, P](
- conditionBranches: NonEmptyList[ConditionBranch[V, R, P]],
- defaultExpr: Expr[V, R, P],
- capture: CaptureP[V, R, P],
- ) extends Expr[V, R, P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[R] = v.visitWhen(this)
- }
-
- /**
- * Uses a [[NamedLens]] to select a value from the output of the given [[inputExpr]] and returns it as output.
- *
- * @note if you want to select from the input [[V]], you can pass [[ReturnInput]] as the [[inputExpr]].
- */
- final case class SelectFromOutput[V, S, R, P](
- inputExpr: Expr[V, S, P],
- lens: NamedLens[S, R],
- capture: CaptureP[V, R, P],
- ) extends Expr[V, R, P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[R] = v.visitSelectFromOutput(this)
- }
-
- final case class FilterOutput[V, M[_] : Foldable : FunctorFilter, R, P](
- inputExpr: Expr[V, M[R], P],
- condExpr: Expr[R, Boolean, P],
- capture: CaptureP[V, M[R], P],
- ) extends Expr[V, M[R], P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[M[R]] = v.visitFilterOutput(this)
- }
-
- /**
- * [[Foldable.collectFoldSome]] every element in the output of the given [[inputExpr]].
- *
- * @note if you want to apply this to the input (i.e. `F[V]`), you can pass [[ReturnInput]] as the [[inputExpr]].
- */
- // TODO: Rename to CollectFoldSomeOutput?
- final case class CollectFromOutput[V, M[_] : Foldable, U, R : Monoid, P](
- inputExpr: Expr[V, M[U], P],
- collectExpr: Expr[U, Option[R], P],
- capture: CaptureP[V, R, P],
- ) extends Expr[V, R, P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[R] = v.visitCollectSomeOutput(this)
- }
-
- /**
- * [[FlatMap.flatMap]] every element in the output of the given [[inputExpr]].
- *
- * @note if you want to apply this to the input (i.e. `F[V]`), you can pass [[ReturnInput]] as the [[inputExpr]].
- */
- final case class FlatMapOutput[V, M[_] : Foldable : FlatMap, U, R, P](
- inputExpr: Expr[V, M[U], P],
- flatMapExpr: Expr[U, M[R], P],
- capture: CaptureP[V, M[R], P],
- ) extends Expr[V, M[R], P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[M[R]] = v.visitFlatMapOutput(this)
- }
-
- /**
- * [[Functor.map]] every element in the output of the given [[inputExpr]].
- *
- * @note if you want to apply this to the input (i.e. `F[V]`), you can pass [[ReturnInput]] as the [[inputExpr]].
- */
- final case class MapOutput[V, M[_] : Foldable : Functor, U, R, P](
- inputExpr: Expr[V, M[U], P],
- mapExpr: Expr[U, R, P],
- capture: CaptureP[V, M[R], P],
- ) extends Expr[V, M[R], P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[M[R]] = v.visitMapOutput(this)
- }
-
- /**
- * Group the output of a given expression into a Map of some hashable key type.
- *
- * @note this uses the default (_: K).## method for hashing because it uses the standard Scala Map collection.
- */
- final case class GroupOutput[V, M[_] : Foldable, U : Order, K, P](
- inputExpr: Expr[V, M[U], P],
- groupByLens: NamedLens[U, K],
- capture: CaptureP[V, MapView[K, Seq[U]], P],
- ) extends Expr[V, MapView[K, Seq[U]], P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[MapView[K, Seq[U]]] = v.visitGroupOutput(this)
- }
-
- /**
- * Sort the elements in the output of the given [[inputExpr]] using the provided [[ExprSorter]].
- *
- * @note if you want to apply this to the input (i.e. `F[V]`), you can pass [[ReturnInput]] as the [[inputExpr]].
- */
- final case class SortOutput[V, M[_], R, P](
- inputExpr: Expr[V, M[R], P],
- sorter: ExprSorter[M, R],
- capture: CaptureP[V, M[R], P],
- ) extends Expr[V, M[R], P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[M[R]] = v.visitSortOutput(this)
- }
-
- /**
- * Concatenate the outputs of all the given expressions into a single expression of the concatenated monoid.
- *
- * @note if you want the output to be evaluated only as needed, then you should use a LazyList for the
- * [[inputExprList]] param sequence type.
- */
- final case class ConcatOutput[V, M[_] : MonoidK, R, P](
- inputExprList: Seq[Expr[V, M[R], P]],
- capture: CaptureP[V, M[R], P],
- ) extends Expr[V, M[R], P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[M[R]] = v.visitConcatOutput(this)
- }
-
- /**
- * Fold the output of the input expression by combining all the elements as pairs or with
- * the empty result value.
- */
- final case class FoldOutput[V, M[_] : Foldable, R : Monoid, P](
- inputExpr: Expr[V, M[R], P],
- capture: CaptureP[V, R, P],
- ) extends Expr[V, R, P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[R] = v.visitFoldOutput(this)
- }
-
- /**
- * Apply an [[ExprConverter]] to the output of a single expression.
- *
- * This is a bit of an escape hatch for automatically converting one type to another in a manner that
- * is restricted to what [[ExprConverter]] supports. In the future, I hope to come up with a more
- * general purpose mechanism for doing this that works across all different types, including custom
- * user-defined types.
- */
- final case class WrapOutput[V, L, R, P](
- inputExpr: Expr[V, L, P],
- converter: ExprConverter[L, R],
- capture: CaptureP[V, R, P],
- ) extends Expr[V, R, P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[R] = v.visitWrapOutput(this)
- }
-
- /**
- * Wrap a sequence of expressions into a single expression of a lazy sequence that evaluates only the
- * expressions needed to produce the values used in subsequent expression nodes.
- */
- final case class WrapOutputSeq[V, R, P](
- inputExprList: Seq[Expr[V, R, P]],
- capture: CaptureP[V, Seq[R], P],
- ) extends Expr[V, Seq[R], P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[Seq[R]] = v.visitWrapOutputSeq(this)
- }
-
- /**
- * Convert a non-empty HList of expressions into an expression of HList, then map a [[converter]] function.
- *
- * This is very similar to [[ZipOutput]], except that for concrete types, there is no possibility of having
- * anything other than a single instance of the expected type, so you don't need any type-classes for the
- * return type.
- */
- final case class WrapOutputHList[V, L <: HList, R, P](
- inputExprHList: NonEmptyExprHList[V, Id, L, P],
- converter: ExprConverter[L, R],
- capture: CaptureP[V, R, P],
- ) extends Expr[V, R, P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[R] = v.visitWrapOutputHList(this)
- }
-
- /**
- * Apply a given [[converter]] to every HList produced by zipping the outputs of expressions that return the
- * same higher-kinded sequence, stopping at the shortest sequence.
- */
- final case class ZipOutput[V, M[_] : Align : FunctorFilter, L <: HList, R, P](
- inputExprHList: NonEmptyExprHList[V, M, L, P],
- converter: ExprConverter[L, R],
- capture: CaptureP[V, M[R], P],
- ) extends Expr[V, M[R], P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[M[R]] = v.visitZipOutput(this)
- }
-
- /**
- * Return true if the output of the given [[inputExpr]] is an empty collection.
- */
- final case class OutputIsEmpty[V, M[_] : Foldable, R, P](
- inputExpr: Expr[V, M[R], P],
- capture: CaptureP[V, Boolean, P],
- ) extends Expr[V, Boolean, P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[Boolean] = v.visitOutputIsEmpty(this)
- }
-
- /**
- * Take a given number of elements from the input sequence.
- *
- * If the number to take is positive, it will pull that number of elements from the start of the sequence.
- * If negative, it will pull that number of elements from the tail of the sequence. If zero, it will return
- * an empty sequence.
- */
- final case class TakeFromOutput[V, M[_] : Traverse : TraverseFilter, R, P](
- inputExpr: Expr[V, M[R], P],
- take: Int,
- capture: CaptureP[V, M[R], P],
- ) extends Expr[V, M[R], P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[M[R]] = v.visitTakeFromOutput(this)
- }
-
- /**
- * Returns `true` if at least one element in the output of the given [[inputExpr]] meets the given [[conditionExpr]].
- *
- * @note this does not short-circuit. [[Evidence]] for all elements that match (or do not match) the
- * [[conditionExpr]] will be retained as evidence of the whole result.
- * @note if you want to apply this to the input (i.e. `F[V]`), you can pass [[ReturnInput]] as the [[inputExpr]].
- * @see [[Foldable.exists]] for more details.
- */
- final case class ExistsInOutput[V, M[_] : Foldable, U, P](
- inputExpr: Expr[V, M[U], P],
- conditionExpr: Expr[U, Boolean, P],
- capture: CaptureP[V, Boolean, P],
- ) extends Expr[V, Boolean, P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[Boolean] = v.visitExistsInOutput(this)
- }
-
- /**
- * Adds the results of all expressions in [[inputExprList]] using the provided definition for [[Addition]].
- */
- final case class AddOutputs[V, R : Addition, P](
- inputExprList: NonEmptyList[Expr[V, R, P]],
- capture: CaptureP[V, R, P],
- ) extends Expr[V, R, P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[R] = v.visitAddOutputs(this)
- }
-
- /**
- * Subtracts the results of all expressions in [[inputExprList]] using the provided definition for [[Subtraction]].
- *
- * @note the order of expressions matters for subtraction, so all subtraction is applied left-to-right.
- */
- final case class SubtractOutputs[V, R : Subtraction, P](
- inputExprList: NonEmptyList[Expr[V, R, P]],
- capture: CaptureP[V, R, P],
- ) extends Expr[V, R, P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[R] = v.visitSubtractOutputs(this)
- }
-
- /**
- * Multiply the results of all expressions in [[inputExprList]] using the provided definition for [[Addition]].
- */
- final case class MultiplyOutputs[V, R : Multiplication, P](
- inputExprList: NonEmptyList[Expr[V, R, P]],
- capture: CaptureP[V, R, P],
- ) extends Expr[V, R, P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[R] = v.visitMultiplyOutputs(this)
- }
-
- /**
- * Divides the results of all expressions in [[inputExprList]] using the provided definition for [[Division]].
- *
- * @note the order of expressions matters for division, so all division is applied left-to-right.
- */
- final case class DivideOutputs[V, R : Division, P](
- inputExprList: NonEmptyList[Expr[V, R, P]],
- capture: CaptureP[V, R, P],
- ) extends Expr[V, R, P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[R] = v.visitDivideOutputs(this)
- }
-
- /**
- * Raise the given base expression to the result of the given power exponent expression.
- */
- final case class ExponentiateOutputs[V, P](
- baseExpr: Expr[V, Double, P],
- exponentExpr: Expr[V, Double, P],
- capture: CaptureP[V, Double, P],
- ) extends Expr[V, Double, P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[Double] = v.visitExponentiateOutputs(this)
- }
-
- /**
- * Returns the negative result value of [[inputExpr]] using the provided definition for [[Negative]].
- */
- final case class NegativeOutput[V, R : Negative, P](
- inputExpr: Expr[V, R, P],
- capture: CaptureP[V, R, P],
- ) extends Expr[V, R, P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[R] = v.visitNegativeOutput(this)
- }
-
- /**
- * Checks if the result of the [[inputExpr]] is contained within the given set of [[accepted]] values.
- */
- final case class OutputWithinSet[V, R, P](
- inputExpr: Expr[V, R, P],
- accepted: Set[R],
- capture: CaptureP[V, Boolean, P],
- ) extends Expr[V, Boolean, P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[Boolean] = v.visitOutputWithinSet(this)
- }
-
- /**
- * Checks if the result of the [[inputExpr]] is contained within the given [[windowExpr]].
- *
- * This is effectively how comparison checks are made.
- *
- * @see [[Window]] for more details.
- */
- final case class OutputWithinWindow[V, R, P](
- inputExpr: Expr[V, R, P],
- windowExpr: Expr[V, Window[R], P],
- capture: CaptureP[V, Boolean, P],
- ) extends Expr[V, Boolean, P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[Boolean] = v.visitOutputWithinWindow(this)
- }
-}
-
-/**
- * A container for a condition and an expression to compute if the condition is met.
- *
- * @see [[Expr.When]] for usage.
- *
- * @param whenExpr a conditional expression that guards the resulting [[thenExpr]]
- * @param thenExpr an expression to compute the result if the [[whenExpr]] returns true
- */
-final case class ConditionBranch[V, R, P](
- whenExpr: Expr[V, Boolean, P],
- thenExpr: Expr[V, R, P],
-)
diff --git a/core/src/main/scala/vapors/algebra/ExprConverter.scala b/core/src/main/scala/vapors/algebra/ExprConverter.scala
deleted file mode 100644
index 9fdddbf99..000000000
--- a/core/src/main/scala/vapors/algebra/ExprConverter.scala
+++ /dev/null
@@ -1,50 +0,0 @@
-package com.rallyhealth
-
-package vapors.algebra
-
-import vapors.data.Window
-
-import cats.Order
-import shapeless.ops.hlist.Tupler
-import shapeless.{Generic, HList}
-
-/**
- * A serializable description of a total conversion function from one type to another.
- */
-sealed trait ExprConverter[L, R] extends (L => R) {
-
- /**
- * The type of conversion applied.
- */
- def conversionType: String
-
- /**
- * Apply the conversion.
- *
- * @note this should never throw an exception.
- */
- override def apply(inputValue: L): R
-}
-
-object ExprConverter {
-
- // TODO: Capture type information about R for debugging?
- private final class Impl[L, R](
- override val conversionType: String,
- convert: L => R,
- ) extends ExprConverter[L, R] {
- override def apply(in: L): R = convert(in)
- override val toString: String = s"ExprConverter.$conversionType"
- }
-
- def asHListIdentity[R <: HList]: ExprConverter[R, R] = new Impl("asHList", identity)
-
- def asProductType[L <: HList, R](implicit gen: Generic.Aux[R, L]): ExprConverter[L, R] =
- new Impl("asProduct", gen.from)
-
- def asTuple[L <: HList, R](implicit tupler: Tupler.Aux[L, R]): ExprConverter[L, R] =
- new Impl("asTuple", tupler.apply)
-
- def asWindow[R : Order](buildWindow: R => Window[R]): ExprConverter[R, Window[R]] =
- new Impl("asWindow", buildWindow)
-}
diff --git a/core/src/main/scala/vapors/algebra/ExprResult.scala b/core/src/main/scala/vapors/algebra/ExprResult.scala
deleted file mode 100644
index 4ecbd5196..000000000
--- a/core/src/main/scala/vapors/algebra/ExprResult.scala
+++ /dev/null
@@ -1,384 +0,0 @@
-package com.rallyhealth
-
-package vapors.algebra
-
-import vapors.data.{FactSet, FactTable, TypedFact}
-import vapors.interpreter.{ExprInput, ExprOutput}
-
-import cats._
-import cats.kernel.Monoid
-import shapeless.HList
-
-import scala.collection.{BitSet, MapView}
-
-/**
- * The result of evaluating an [[Expr]] with some given [[ExprInput]].
- *
- * You can fold over this result to see the input, output, value, and captured custom parameter at each node in the
- * original expression. Every node of this algebra matches to the [[Expr]] subclass with the same name.
- */
-sealed trait ExprResult[V, R, P] {
-
- def context: ExprResult.Context[V, R, P]
-
- @inline final def input: ExprInput[V] = context.input
-
- @inline final def output: ExprOutput[R] = context.output
-
- @inline final def param: Eval[P] = context.param
-
- def convertOutputToInput: ExprInput[R] = input.withValue(output.value, output.evidence)
-
- def visit[G[_]](v: ExprResult.Visitor[V, P, G]): G[R]
-}
-
-object ExprResult {
-
- final case class Context[V, R, P](
- input: ExprInput[V],
- output: ExprOutput[R],
- param: Eval[P],
- )
-
- trait Visitor[V, P, G[_]] extends (ExprResult[V, *, P] ~> G) {
- // Please keep the following methods in alphabetical order
- override final def apply[R](fa: ExprResult[V, R, P]): G[R] = fa.visit(this)
- def visitAddOutputs[R](result: AddOutputs[V, R, P]): G[R]
- def visitAnd[R](result: And[V, R, P]): G[R]
- def visitCollectFromOutput[M[_] : Foldable, U, R : Monoid](result: CollectFromOutput[V, M, U, R, P]): G[R]
- def visitConcatOutput[M[_] : MonoidK, R](result: ConcatOutput[V, M, R, P]): G[M[R]]
- def visitConstOutput[R](result: ConstOutput[V, R, P]): G[R]
- def visitCustomFunction[A, R](result: CustomFunction[V, A, R, P]): G[R]
- def visitDeclare[M[_], T](result: Define[V, M, T, P]): G[FactSet]
- def visitDivideOutputs[R](result: DivideOutputs[V, R, P]): G[R]
- def visitEmbed[R](result: Embed[V, R, P]): G[R]
- def visitExistsInOutput[M[_] : Foldable, U](result: ExistsInOutput[V, M, U, P]): G[Boolean]
- def visitExponentiateOutputs(result: ExponentiateOutputs[V, P]): G[Double]
- def visitFilterOutput[M[_] : Foldable : FunctorFilter, R](result: FilterOutput[V, M, R, P]): G[M[R]]
- def visitFlatMapOutput[M[_], U, R](result: FlatMapOutput[V, M, U, R, P]): G[M[R]]
- def visitGroupOutput[M[_] : Foldable, U : Order, K](result: GroupOutput[V, M, U, K, P]): G[MapView[K, Seq[U]]]
- def visitMapOutput[M[_], U, R](result: MapOutput[V, M, U, R, P]): G[M[R]]
- def visitMultiplyOutputs[R](result: MultiplyOutputs[V, R, P]): G[R]
- def visitNegativeOutput[R](result: NegativeOutput[V, R, P]): G[R]
- def visitNot[R](result: Not[V, R, P]): G[R]
- def visitOr[R](result: Or[V, R, P]): G[R]
- def visitOutputIsEmpty[M[_] : Foldable, R](result: OutputIsEmpty[V, M, R, P]): G[Boolean]
- def visitOutputWithinSet[R](result: OutputWithinSet[V, R, P]): G[Boolean]
- def visitOutputWithinWindow[R](result: OutputWithinWindow[V, R, P]): G[Boolean]
- def visitFoldOutput[M[_] : Foldable, R : Monoid](result: FoldOutput[V, M, R, P]): G[R]
- def visitReturnInput(result: ReturnInput[V, P]): G[V]
- def visitSelectFromOutput[S, R](result: SelectFromOutput[V, S, R, P]): G[R]
- def visitSortOutput[M[_], R](result: SortOutput[V, M, R, P]): G[M[R]]
- def visitSubtractOutputs[R](result: SubtractOutputs[V, R, P]): G[R]
- def visitTakeFromOutput[M[_] : Traverse : TraverseFilter, R](result: TakeFromOutput[V, M, R, P]): G[M[R]]
- def visitUsingDefinitions[R](result: UsingDefinitions[V, R, P]): G[R]
- def visitWhen[R](result: When[V, R, P]): G[R]
- def visitWrapOutput[L, R](result: WrapOutput[V, L, R, P]): G[R]
- def visitWrapOutputHList[T <: HList, R](result: WrapOutputHList[V, T, R, P]): G[R]
- def visitWrapOutputSeq[R](result: WrapOutputSeq[V, R, P]): G[Seq[R]]
- def visitWithFactsOfType[T, R](result: WithFactsOfType[V, T, R, P]): G[R]
- def visitZipOutput[M[_] : Align : FunctorFilter, L <: HList, R](result: ZipOutput[V, M, L, R, P]): G[M[R]]
- }
-
- /*
- * Please keep the following expressions in the same order in Expr.scala and ExprResult.scala.
- * It makes it easier to find the mirror node.
- *
- * While alphabetical seems like the best way to organize these classes, in practice
- * certain nodes that are related to each other (like addition and subtraction) will have
- * very similar implementations and will likely need to be refactored in identical ways.
- *
- * The Visitor and its subclasses use alphabetical sorting because their definitions
- * are derivative and it is practically impossible to forget to update their implementation
- * without the compiler complaining.
- */
-
- final case class ConstOutput[V, R, P](
- expr: Expr.ConstOutput[V, R, P],
- context: Context[V, R, P],
- ) extends ExprResult[V, R, P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[R] = v.visitConstOutput(this)
- }
-
- final case class ReturnInput[V, P](
- expr: Expr.ReturnInput[V, P],
- context: Context[V, V, P],
- ) extends ExprResult[V, V, P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[V] = v.visitReturnInput(this)
- }
-
- final case class Embed[V, R, P](
- expr: Expr.Embed[V, R, P],
- context: Context[V, R, P],
- embeddedResult: ExprResult[FactTable, R, P],
- ) extends ExprResult[V, R, P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[R] = v.visitEmbed(this)
- }
-
- final case class CustomFunction[V, A, R, P](
- expr: Expr.CustomFunction[V, A, R, P],
- context: Context[V, R, P],
- argResult: ExprResult[V, A, P],
- ) extends ExprResult[V, R, P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[R] = v.visitCustomFunction(this)
- }
-
- final case class WithFactsOfType[V, T, R, P](
- expr: Expr.WithFactsOfType[T, R, P],
- context: Context[V, R, P],
- subResult: ExprResult[Seq[TypedFact[T]], R, P],
- ) extends ExprResult[V, R, P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[R] = v.visitWithFactsOfType(this)
- }
-
- final case class Define[V, M[_], T, P](
- expr: Expr.Define[M, T, P],
- context: Context[V, FactSet, P],
- definitionResult: ExprResult[FactTable, M[T], P],
- ) extends ExprResult[V, FactSet, P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[FactSet] = v.visitDeclare(this)
- }
-
- final case class UsingDefinitions[V, R, P](
- expr: Expr.UsingDefinitions[V, R, P],
- context: Context[V, R, P],
- subResult: ExprResult[V, R, P],
- ) extends ExprResult[V, R, P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[R] = v.visitUsingDefinitions(this)
- }
-
- final case class And[V, R, P](
- expr: Expr.And[V, R, P],
- context: Context[V, R, P],
- subResultList: List[ExprResult[V, R, P]],
- ) extends ExprResult[V, R, P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[R] = v.visitAnd(this)
- }
-
- final case class Or[V, R, P](
- expr: Expr.Or[V, R, P],
- context: Context[V, R, P],
- subResultList: List[ExprResult[V, R, P]],
- ) extends ExprResult[V, R, P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[R] = v.visitOr(this)
- }
-
- final case class Not[V, R, P](
- expr: Expr.Not[V, R, P],
- context: Context[V, R, P],
- subResult: ExprResult[V, R, P],
- ) extends ExprResult[V, R, P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[R] = v.visitNot(this)
- }
-
- final case class When[V, R, P](
- expr: Expr.When[V, R, P],
- context: Context[V, R, P],
- matchedBranch: Option[ConditionBranch[V, R, P]],
- subResult: ExprResult[V, R, P],
- ) extends ExprResult[V, R, P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[R] = v.visitWhen(this)
- val thenExpr: Expr[V, R, P] = matchedBranch.map(_.thenExpr).getOrElse(expr.defaultExpr)
- }
-
- final case class SelectFromOutput[V, S, R, P](
- expr: Expr.SelectFromOutput[V, S, R, P],
- context: Context[V, R, P],
- inputResult: ExprResult[V, S, P],
- ) extends ExprResult[V, R, P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[R] = v.visitSelectFromOutput(this)
- }
-
- final case class FilterOutput[V, M[_] : Foldable : FunctorFilter, R, P](
- expr: Expr.FilterOutput[V, M, R, P],
- context: Context[V, M[R], P],
- inputResult: ExprResult[V, M[R], P],
- condResultList: List[ExprResult[R, Boolean, P]],
- ) extends ExprResult[V, M[R], P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[M[R]] = v.visitFilterOutput(this)
- }
-
- final case class CollectFromOutput[V, M[_] : Foldable, U, R : Monoid, P](
- expr: Expr.CollectFromOutput[V, M, U, R, P],
- context: Context[V, R, P],
- inputResult: ExprResult[V, M[U], P],
- ) extends ExprResult[V, R, P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[R] = v.visitCollectFromOutput(this)
- }
-
- final case class FlatMapOutput[V, M[_], U, R, P](
- expr: Expr.FlatMapOutput[V, M, U, R, P],
- context: Context[V, M[R], P],
- inputResult: ExprResult[V, M[U], P],
- subResultList: List[ExprResult[U, M[R], P]],
- ) extends ExprResult[V, M[R], P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[M[R]] = v.visitFlatMapOutput(this)
- }
-
- final case class MapOutput[V, M[_], U, R, P](
- expr: Expr.MapOutput[V, M, U, R, P],
- context: Context[V, M[R], P],
- inputResult: ExprResult[V, M[U], P],
- subResultList: List[ExprResult[U, R, P]],
- ) extends ExprResult[V, M[R], P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[M[R]] = v.visitMapOutput(this)
- }
-
- final case class GroupOutput[V, M[_] : Foldable, U : Order, K, P](
- expr: Expr.GroupOutput[V, M, U, K, P],
- context: Context[V, MapView[K, Seq[U]], P],
- inputResult: ExprResult[V, M[U], P],
- ) extends ExprResult[V, MapView[K, Seq[U]], P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[MapView[K, Seq[U]]] = v.visitGroupOutput(this)
- }
-
- final case class SortOutput[V, M[_], R, P](
- expr: Expr.SortOutput[V, M, R, P],
- context: Context[V, M[R], P],
- inputResult: ExprResult[V, M[R], P],
- ) extends ExprResult[V, M[R], P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[M[R]] = v.visitSortOutput(this)
- }
-
- final case class ConcatOutput[V, M[_] : MonoidK, R, P](
- expr: Expr.ConcatOutput[V, M, R, P],
- context: Context[V, M[R], P],
- inputResultList: Seq[ExprResult[V, M[R], P]],
- ) extends ExprResult[V, M[R], P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[M[R]] = v.visitConcatOutput(this)
- }
-
- final case class FoldOutput[V, M[_] : Foldable, R : Monoid, P](
- expr: Expr.FoldOutput[V, M, R, P],
- context: Context[V, R, P],
- inputResult: ExprResult[V, M[R], P],
- ) extends ExprResult[V, R, P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[R] = v.visitFoldOutput(this)
- }
-
- final case class OutputIsEmpty[V, M[_] : Foldable, R, P](
- expr: Expr.OutputIsEmpty[V, M, R, P],
- context: Context[V, Boolean, P],
- inputResult: ExprResult[V, M[R], P],
- ) extends ExprResult[V, Boolean, P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[Boolean] = v.visitOutputIsEmpty(this)
- }
-
- final case class TakeFromOutput[V, M[_] : Traverse : TraverseFilter, R, P](
- expr: Expr.TakeFromOutput[V, M, R, P],
- context: Context[V, M[R], P],
- inputResult: ExprResult[V, M[R], P],
- ) extends ExprResult[V, M[R], P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[M[R]] = v.visitTakeFromOutput(this)
- }
-
- final case class ExistsInOutput[V, M[_] : Foldable, U, P](
- expr: Expr.ExistsInOutput[V, M, U, P],
- context: Context[V, Boolean, P],
- inputResult: ExprResult[V, M[U], P],
- conditionResultList: List[ExprResult[U, Boolean, P]],
- matchedIndexes: BitSet,
- ) extends ExprResult[V, Boolean, P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[Boolean] = v.visitExistsInOutput(this)
- }
-
- final case class AddOutputs[V, R, P](
- expr: Expr.AddOutputs[V, R, P],
- context: Context[V, R, P],
- subResultList: List[ExprResult[V, R, P]],
- ) extends ExprResult[V, R, P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[R] = v.visitAddOutputs(this)
- }
-
- final case class SubtractOutputs[V, R, P](
- expr: Expr.SubtractOutputs[V, R, P],
- context: Context[V, R, P],
- subResultList: List[ExprResult[V, R, P]],
- ) extends ExprResult[V, R, P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[R] = v.visitSubtractOutputs(this)
- }
-
- final case class MultiplyOutputs[V, R, P](
- expr: Expr.MultiplyOutputs[V, R, P],
- context: Context[V, R, P],
- subResultList: List[ExprResult[V, R, P]],
- ) extends ExprResult[V, R, P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[R] = v.visitMultiplyOutputs(this)
- }
-
- final case class DivideOutputs[V, R, P](
- expr: Expr.DivideOutputs[V, R, P],
- context: Context[V, R, P],
- subResultList: List[ExprResult[V, R, P]],
- ) extends ExprResult[V, R, P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[R] = v.visitDivideOutputs(this)
- }
-
- final case class ExponentiateOutputs[V, P](
- expr: Expr.ExponentiateOutputs[V, P],
- context: Context[V, Double, P],
- baseResult: ExprResult[V, Double, P],
- exponentResult: ExprResult[V, Double, P],
- ) extends ExprResult[V, Double, P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[Double] = v.visitExponentiateOutputs(this)
- }
-
- final case class WrapOutput[V, L, R, P](
- expr: Expr.WrapOutput[V, L, R, P],
- context: Context[V, R, P],
- inputResult: ExprResult[V, L, P],
- ) extends ExprResult[V, R, P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[R] = v.visitWrapOutput(this)
- }
-
- // TODO: This seems redundant with WrapOutput... maybe we can boil these "wrap" operations into
- // a single operation... or a smaller subset. In essence these are all just a single function.
- // The only major difference is their typeclass dependencies and how we serialize them, which
- // could be baked into an operation metadata object to sit alongside a function.
- final case class WrapOutputSeq[V, R, P](
- expr: Expr.WrapOutputSeq[V, R, P],
- context: Context[V, Seq[R], P],
- inputResultList: Seq[ExprResult[V, R, P]],
- ) extends ExprResult[V, Seq[R], P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[Seq[R]] = v.visitWrapOutputSeq(this)
- }
-
- final case class WrapOutputHList[V, T <: HList, R, P](
- expr: Expr.WrapOutputHList[V, T, R, P],
- context: Context[V, R, P],
- ) extends ExprResult[V, R, P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[R] = v.visitWrapOutputHList(this)
- }
-
- final case class ZipOutput[V, M[_] : Align : FunctorFilter, L <: HList, R, P](
- expr: Expr.ZipOutput[V, M, L, R, P],
- context: Context[V, M[R], P],
- ) extends ExprResult[V, M[R], P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[M[R]] = v.visitZipOutput(this)
- }
-
- final case class NegativeOutput[V, R, P](
- expr: Expr.NegativeOutput[V, R, P],
- context: Context[V, R, P],
- inputResult: ExprResult[V, R, P],
- ) extends ExprResult[V, R, P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[R] = v.visitNegativeOutput(this)
- }
-
- final case class OutputWithinSet[V, R, P](
- expr: Expr.OutputWithinSet[V, R, P],
- context: Context[V, Boolean, P],
- inputResult: ExprResult[V, R, P],
- ) extends ExprResult[V, Boolean, P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[Boolean] = v.visitOutputWithinSet(this)
- }
-
- final case class OutputWithinWindow[V, R, P](
- expr: Expr.OutputWithinWindow[V, R, P],
- context: Context[V, Boolean, P],
- inputResult: ExprResult[V, R, P],
- ) extends ExprResult[V, Boolean, P] {
- override def visit[G[_]](v: Visitor[V, P, G]): G[Boolean] = v.visitOutputWithinWindow(this)
- }
-
-}
diff --git a/core/src/main/scala/vapors/algebra/ExprSorter.scala b/core/src/main/scala/vapors/algebra/ExprSorter.scala
deleted file mode 100644
index 80f6d8db3..000000000
--- a/core/src/main/scala/vapors/algebra/ExprSorter.scala
+++ /dev/null
@@ -1,59 +0,0 @@
-package com.rallyhealth
-
-package vapors.algebra
-
-import vapors.lens.NamedLens
-
-import cats.Order
-import cats.syntax.contravariant._
-import cats.syntax.show._
-
-import scala.collection.Factory
-import scala.reflect.runtime.universe.{typeOf, TypeTag}
-
-/**
- * Defines a closed set of operations for sorting elements of the given arity-1 type constructor.
- *
- * This is basically like an [[Order]], except it exists only for serialization and debugging purposes.
- */
-sealed trait ExprSorter[M[_], R] extends (M[R] => M[R]) {
-
- /**
- * A description of how the elements are sorted for serialization and debugging purposes.
- */
- def sortDescription: String
-
- /**
- * Sort the given collection.
- */
- override def apply(collection: M[R]): M[R]
-}
-
-object ExprSorter {
-
- private final class Impl[M[_], R](
- override val sortDescription: String,
- op: M[R] => M[R],
- ) extends ExprSorter[M, R] {
- override def apply(collection: M[R]): M[R] = op(collection)
- }
-
- def byNaturalOrder[M[_], R : Order : TypeTag](
- implicit
- ev: M[R] <:< Seq[R],
- factory: Factory[R, M[R]],
- ): ExprSorter[M, R] =
- new Impl(s"natural order of ${typeOf[R]}", _.sorted(Order[R].toOrdering).to(factory))
-
- def byField[M[_], S : TypeTag, R : Order](
- lens: NamedLens[S, R],
- )(implicit
- ev: M[S] <:< Seq[S],
- factory: Factory[S, M[S]],
- ): ExprSorter[M, S] =
- new Impl(
- s"sort using ${typeOf[S]}${lens.path.show}",
- _.sorted(Order[R].contramap(lens.get).toOrdering).to(factory),
- )
-
-}
diff --git a/core/src/main/scala/vapors/algebra/HExprList.scala b/core/src/main/scala/vapors/algebra/HExprList.scala
deleted file mode 100644
index 1fa409958..000000000
--- a/core/src/main/scala/vapors/algebra/HExprList.scala
+++ /dev/null
@@ -1,134 +0,0 @@
-package com.rallyhealth
-
-package vapors.algebra
-
-import cats.data.Ior
-import cats.syntax.all._
-import cats.{Align, Functor, FunctorFilter, Id, Semigroupal}
-import shapeless.{::, HList, HNil}
-
-/**
- * A helpful short-hand for an HList of expressions that all share the same input, effect, and parameter types.
- *
- * This not only provides syntactic sugar by fixing some of the type arguments to avoid repetition, it also
- * provides implementation for some recursive operations that produce HList outputs.
- */
-sealed trait NonEmptyExprHList[V, M[_], L <: HList, P] {
-
- /**
- * Prepends an expression that accepts the same input and outputs a value wrapped in the same effect as
- * all the other expressions.
- */
- def ::[H](other: Expr[V, M[H], P]): NonEmptyExprHList[V, M, H :: L, P] =
- new ExprHCons[V, M, H, L, P](other, this)
-
- /**
- * Visits each expression in the HList, applies the given visitor, and combines the results by applying a
- * product operation on the effectful container of results to produce every possible combination of HList
- * from the given input.
- *
- * @note If given the [[Id]] effect, this is equivalent to mapping over each given expression to produce
- * an expression that takes the same input and produces a single HList combining every result type.
- *
- * @example NonEmptyExprHList.of(const("A"), const(1)).visitProduct(g) == const("A" :: 1 :: HNil).visit(g)
- *
- * @note If given a [[List]], this will combine the resulting lists of each expression into a list of
- * every permutation of HList that can be produced from the output lists.
- *
- * @example NonEmptyExprHList.of(const(List("A", "B")), const(List(1, 2))).visitProduct(g) == const(
- * List("A" :: 1 :: HNil, "A" :: 2 :: HNil, "B" :: 1 :: HNil, "C" :: 2 :: HNil)
- * ).visit(g)
- *
- * @example NonEmptyExprHList.of(const(List("A")), const(Nil)).visitProduct(g) == const(Nil).visit(g)
- */
- def visitProduct[G[_] : Functor : Semigroupal](
- v: Expr.Visitor[V, P, G],
- )(implicit
- functorM: Functor[M],
- semigroupalM: Semigroupal[M],
- ): G[M[L]]
-
- /**
- * Visits each expression in the HList, applies the given visitor, zips over every element in the resulting
- * functor-wrapped values (stopping at the length of the first sequence to run out of elements), and then
- * combines the elements into an HList.
- *
- * @example NonEmptyExprHList.of(const(List("A", "B", "C"), const(List(1, 2, 3, 4, 5))).visitZippedToShortest(g) ==
- * const(List("A" :: 1 :: HNil, "B" :: 2 :: HNil, "C" :: 3 :: HNil)).visit(g)
- *
- * @example NonEmptyExprHList.of(const(List("A", "B", "C"), const(Nil)).visitZippedToShortest(g) ==
- * const(Nil).visit(g)
- */
- def visitZippedToShortest[G[_] : Functor : Semigroupal](
- v: Expr.Visitor[V, P, G],
- )(implicit
- alignM: Align[M],
- filterM: FunctorFilter[M],
- ): G[M[L]]
-}
-
-object NonEmptyExprHList {
-
- def tail[V, R, P](expr: Expr[V, R, P]): ExprLast[V, Id, R, P] =
- ExprLast[V, Id, R, P](expr)
-
- def tailK[V, M[_], R, P](expr: Expr[V, M[R], P]): ExprLast[V, M, R, P] =
- ExprLast(expr)
-}
-
-final case class ExprHCons[V, M[_], H, T <: HList, P](
- head: Expr[V, M[H], P],
- tail: NonEmptyExprHList[V, M, T, P],
-) extends NonEmptyExprHList[V, M, H :: T, P] {
-
- override def visitProduct[G[_] : Functor : Semigroupal](
- v: Expr.Visitor[V, P, G],
- )(implicit
- functorM: Functor[M],
- semigroupalM: Semigroupal[M],
- ): G[M[H :: T]] = {
- Semigroupal[G].product(head.visit(v), tail.visitProduct(v)).map {
- _.mapN(_ :: _)
- }
- }
-
- override def visitZippedToShortest[G[_] : Functor : Semigroupal](
- v: Expr.Visitor[V, P, G],
- )(implicit
- alignM: Align[M],
- filterM: FunctorFilter[M],
- ): G[M[H :: T]] = {
- Semigroupal[G].product(head.visit(v), tail.visitZippedToShortest(v)).map {
- case (hs, ts) =>
- Align[M]
- .alignWith(hs, ts) {
- case Ior.Both(h, t) => Some(h :: t)
- case _ => None
- }
- .collect {
- case Some(hlist) => hlist
- }
- }
- }
-}
-
-final case class ExprLast[V, M[_], H, P](last: Expr[V, M[H], P]) extends NonEmptyExprHList[V, M, H :: HNil, P] {
-
- override def visitProduct[G[_] : Functor : Semigroupal](
- v: Expr.Visitor[V, P, G],
- )(implicit
- functorM: Functor[M],
- semigroupalM: Semigroupal[M],
- ): G[M[H :: HNil]] = {
- last.visit(v).map(_.map(_ :: HNil))
- }
-
- override def visitZippedToShortest[G[_] : Functor : Semigroupal](
- v: Expr.Visitor[V, P, G],
- )(implicit
- alignM: Align[M],
- filterM: FunctorFilter[M],
- ): G[M[H :: HNil]] = {
- last.visit(v).map(filterM.functor.map(_)(_ :: HNil))
- }
-}
diff --git a/core/src/main/scala/vapors/data/Bounded.scala b/core/src/main/scala/vapors/data/Bounded.scala
deleted file mode 100644
index 7315c9f08..000000000
--- a/core/src/main/scala/vapors/data/Bounded.scala
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.rallyhealth
-
-package vapors.data
-
-import cats.Functor
-
-/**
- * Represents a boundary on a 1-dimensional line at a specific position.
- *
- * It has two directions: [[Bounded.Below]] and [[Bounded.Above]].
- */
-sealed trait Bounded[A]
-
-object Bounded {
-
- final case class Above[A](
- lowerBound: A,
- inclusiveLowerBound: Boolean,
- ) extends Bounded[A]
-
- final case class Below[A](
- upperBound: A,
- inclusiveUpperBound: Boolean,
- ) extends Bounded[A]
-
- implicit final object AboveFunctorLike extends Functor[Above] {
- override def map[A, B](fa: Above[A])(f: A => B): Above[B] =
- fa.copy[B](lowerBound = f(fa.lowerBound))
- }
-
- implicit final object BelowFunctorLike extends Functor[Below] {
- override def map[A, B](fa: Below[A])(f: A => B): Below[B] =
- fa.copy[B](upperBound = f(fa.upperBound))
- }
-
-}
diff --git a/core/src/main/scala/vapors/data/Evidence.scala b/core/src/main/scala/vapors/data/Evidence.scala
deleted file mode 100644
index 521057e46..000000000
--- a/core/src/main/scala/vapors/data/Evidence.scala
+++ /dev/null
@@ -1,125 +0,0 @@
-package com.rallyhealth
-
-package vapors.data
-
-import cats.Monoid
-import cats.data.NonEmptySet
-import cats.instances.order._
-
-import scala.annotation.tailrec
-import scala.collection.immutable.SortedSet
-
-/**
- * A set of [[Fact]]s used to derive an evaluated expression result.
- *
- * If the resulting evidence is empty, then you should treat the value as identical to its negation.
- *
- * TODO: there are some bugs with evidence tracking of collection-level operations and how constants
- * are handled, so you probably shouldn't rely on this right now.
- */
-final class Evidence private (val factSet: Set[Fact]) extends AnyVal {
-
- def isEmpty: Boolean = factSet.isEmpty
- def nonEmpty: Boolean = factSet.nonEmpty
-
- @inline def ++(that: Evidence): Evidence = union(that)
- @inline def |(that: Evidence): Evidence = union(that)
-
- def ofType[T](factTypeSet: FactTypeSet[T]): Option[NonEmptySet[TypedFact[T]]] = {
- val matchingFacts = SortedSet.from(this.factSet.iterator.collect(factTypeSet.collector))
- NonEmptySet.fromSet(matchingFacts)
- }
-
- /**
- * Union of the two sets of results.
- */
- def union(that: Evidence): Evidence = this.factSet match {
- case Evidence.none.factSet | that.factSet => that
- case _ => Evidence(this.factSet | that.factSet)
- }
-
- @inline def &(that: Evidence): Evidence = combineNonEmpty(that)
-
- /**
- * If either side contains empty evidence then the result contains no evidence.
- */
- def combineNonEmpty(that: Evidence): Evidence = {
- if (this.isEmpty || that.isEmpty) Evidence.none
- else this.union(that)
- }
-
- def derivedFromSources: Evidence = {
- @tailrec def loop(
- mixed: Iterable[Fact],
- source: FactSet,
- ): FactSet = {
- if (mixed.isEmpty) source
- else {
- val (remainingEvidence, sourceFacts) = mixed.partitionMap {
- case DerivedFact(_, _, evidence) => Left(evidence.factSet)
- case source => Right(source)
- }
- loop(remainingEvidence.flatten, source ++ sourceFacts)
- }
- }
- val allSourceFacts = loop(this.factSet, FactSet.empty)
- new Evidence(allSourceFacts)
- }
-
- override def toString: String =
- if (this.factSet.isEmpty) "Evidence()"
- else s"Evidence${factSet.mkString("(", ", ", ")")}"
-}
-
-object Evidence {
-
- def unapply(evidence: Evidence): Some[Set[Fact]] = Some(evidence.factSet)
-
- @inline final def apply(facts: FactOrFactSet*): Evidence = {
- if (facts.isEmpty) none
- else new Evidence(FactOrFactSet.flatten(facts))
- }
-
- final val none = new Evidence(Set.empty)
-
- /**
- * Convert any given value into [[Evidence]] by inspecting whether it is a fact or valid collection of facts.
- *
- * This is used by the library when iterating over a collection of facts, where the facts can be used as their own
- * evidence in the subexpression.
- */
- def fromAny(any: Any): Option[Evidence] = any match {
- case ev: Evidence => Some(ev)
- case fact: Fact => Some(Evidence(fact))
- case map: collection.Map[_, _] => fromAnyIterable(map.valuesIterator)
- case iter: IterableOnce[_] => fromAnyIterable(iter)
- case _ => None
- }
-
- @inline def fromAnyOrNone(any: Any): Evidence = fromAny(any).getOrElse(none)
-
- private[this] def fromAnyIterable(anyIter: IterableOnce[_]): Option[Evidence] = {
- val iter = anyIter.iterator
- if (iter.isEmpty) None
- else Some(Evidence(FactSet.from(iter.collect { case fact: Fact => fact })))
- }
-
- /**
- * Unions evidence as a standard definition for monoid.
- *
- * This is the right behavior to satify [[Monoid]], however if you need to do evidence tracking,
- * you wlil probably want to be more specific if you need to represent the behavior of merging
- * evidence from the output of various expressions (or their input).
- *
- * @see [[InterpretExprAsResultFn.Output.monoid]]
- */
- implicit val monoid: Monoid[Evidence] = {
- new Monoid[Evidence] {
- override def empty: Evidence = Evidence.none
- override def combine(
- x: Evidence,
- y: Evidence,
- ): Evidence = x.union(y)
- }
- }
-}
diff --git a/core/src/main/scala/vapors/data/ExtractInstant.scala b/core/src/main/scala/vapors/data/ExtractInstant.scala
deleted file mode 100644
index 6bd2d4994..000000000
--- a/core/src/main/scala/vapors/data/ExtractInstant.scala
+++ /dev/null
@@ -1,29 +0,0 @@
-package com.rallyhealth
-
-package vapors.data
-
-import java.time._
-
-/**
- * Special case of [[ExtractValue]] that extracts an [[Instant]].
- *
- * TODO: This should be replaced by a type alias to [[ExtractValue]] in the same way [[ExtractBoolean]] was.
- */
-trait ExtractInstant[-T] extends ExtractValue[T, Instant]
-
-object ExtractInstant {
-
- def apply[T](implicit instance: ExtractInstant[T]): ExtractInstant[T] = instance
-
- def from[T, V : ExtractInstant](extractField: T => V): ExtractInstant[T] = { obj =>
- ExtractInstant[V].extractValue(extractField(obj))
- }
-
- implicit def instantFromLocalDate(implicit zone: ZoneId): ExtractInstant[LocalDate] = _.atStartOfDay(zone).toInstant
-
- implicit def instantFromLocalDateTime(implicit zone: ZoneId): ExtractInstant[LocalDateTime] = _.atZone(zone).toInstant
-
- implicit val instantFromZonedDate: ExtractInstant[ZonedDateTime] = _.toInstant
-
- implicit val instantFromZonedDateTime: ExtractInstant[ZonedDateTime] = _.toInstant
-}
diff --git a/core/src/main/scala/vapors/data/ExtractValue.scala b/core/src/main/scala/vapors/data/ExtractValue.scala
deleted file mode 100644
index 71b111fbe..000000000
--- a/core/src/main/scala/vapors/data/ExtractValue.scala
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.rallyhealth
-
-package vapors.data
-
-/**
- * Extracts a value from some starting value.
- *
- * This is useful for defining [[CaptureP]] based on some input
- * type, without having to share a common supertype. Although, because of variance rules, this makes it
- * easy to define an [[ExtractValue]] for a supertype, if desired.
- */
-trait ExtractValue[-T, +V] {
- def extractValue(obj: T): V
-}
-
-object ExtractValue {
- @inline final def apply[V]: Of[V] = new Of[V]
- final class Of[V] private[ExtractValue] (private val dummy: Boolean = true) extends AnyVal {
-
- def apply[T](input: T)(implicit extractor: ExtractValue[T, V]): V = extractor.extractValue(input)
-
- def from[T](implicit extractor: ExtractValue[T, V]): ExtractValue[T, V] = extractor
- }
-
- implicit def id[T]: ExtractValue[T, T] = identity[T]
-
- implicit class ExtractBooleanOps[T](private val extractBoolean: ExtractBoolean[T]) extends AnyVal {
-
- @deprecated("Use ExtractValue[Boolean](value) or .extractValue(value) instead.", "0.14.1")
- def isTrue(value: T): Boolean = extractBoolean.extractValue(value)
- }
-}
diff --git a/core/src/main/scala/vapors/data/Fact.scala b/core/src/main/scala/vapors/data/Fact.scala
deleted file mode 100644
index c41d13ba2..000000000
--- a/core/src/main/scala/vapors/data/Fact.scala
+++ /dev/null
@@ -1,162 +0,0 @@
-package com.rallyhealth
-
-package vapors.data
-
-import vapors.lens.{DataPath, NamedLens}
-
-import cats.Order
-import cats.syntax.all._
-
-/**
- * An untyped fact for putting many different facts into collections without causing issues
- * with variance.
- *
- * Typically, you will work with [[TypedFact]]s.
- *
- * The [[FactType]] and `value` inside share the same type member [[Value]].
- */
-sealed abstract class Fact {
- type Value
-
- val typeInfo: FactType[Value]
- val value: Value
-}
-
-object Fact {
-
- /**
- * Builds a fact given a [[FactType]] and a `value` of the same type.
- */
- def apply[T](
- factType: FactType[T],
- value: T,
- ): Fact = SourceFactOfType(factType, value)
-
- def unapply(fact: Fact): Some[(FactType[fact.Value], fact.Value)] = Some((fact.typeInfo, fact.value))
-
- val orderByFactValue: Order[Fact] = { (x, y) =>
- def maybeXCompared =
- x.typeInfo
- .cast(y)
- .map(yAsX => x.typeInfo.order.compare(x.value, yAsX.value))
-
- def maybeYCompared =
- y.typeInfo
- .cast(x)
- .map(xAsY => y.typeInfo.order.compare(xAsY.value, y.value))
-
- def fallbackToCompareAsStrings =
- if (x.value == y.value) 0
- else Order[String].compare(x.value.toString, y.value.toString)
-
- maybeXCompared.orElse(maybeYCompared).getOrElse(fallbackToCompareAsStrings)
- }
-
- def orderByFactName(nameOrder: Order[String]): Order[Fact] = {
- nameOrder.contramap(_.typeInfo.name)
- }
-
- // This will be used a lot, so cache it
- private final val defaultOrder: Order[Fact] = orderByFactName(Order[String])
-
- implicit def order(implicit orderFactNames: Order[String]): Order[Fact] = {
- if (orderFactNames == cats.instances.string.catsKernelStdOrderForString) defaultOrder
- else Order.whenEqual(orderByFactName(orderFactNames), orderByFactValue)
- }
-}
-
-/**
- * A typed [[Fact]], for when you know the type of fact or need to know it.
- *
- * @see [[Fact]]
- */
-sealed trait TypedFact[A] extends Fact {
- type Value = A
-}
-
-object TypedFact {
-
- def apply[A](
- typeInfo: FactType[A],
- value: A,
- ): TypedFact[A] = SourceFactOfType(typeInfo, value)
-
- def apply[A](
- typeInfo: FactType[A],
- value: A,
- evidence: Evidence,
- ): TypedFact[A] with DerivedFact = DerivedFactOfType(typeInfo, value, evidence)
-
- def unapply[A](fact: TypedFact[A]): Some[(FactType[A], A)] = fact match {
- case SourceFactOfType(typeInfo, value) => Some((typeInfo, value))
- case DerivedFactOfType(typeInfo, value, _) => Some((typeInfo, value))
- }
-
- def orderTypedFactByValue[T]: Order[TypedFact[T]] = { (x, y) =>
- x.typeInfo.order.compare(x.value, y.value)
- }
-
- implicit def orderFactByNameThenValue[T](implicit orderFactNames: Order[String]): Order[TypedFact[T]] = { (x, y) =>
- orderFactNames.compare(x.typeInfo.name, y.typeInfo.name) match {
- case 0 => orderTypedFactByValue[T].compare(x, y)
- case orderByName => orderByName
- }
- }
-
- def lens[A]: NamedLens.Id[TypedFact[A]] = NamedLens.id[TypedFact[A]]
-
- def value[A]: NamedLens[TypedFact[A], A] = {
- NamedLens[TypedFact[A], A](DataPath.empty.atField("value"), _.value)
- }
-}
-
-/**
- * A [[Fact]] this is derived from other [[Fact]]s via an expression.
- *
- * The [[Evidence]] is tracked from the original set of [[Fact]]s based on the expression.
- */
-sealed trait DerivedFact extends Fact {
- def evidence: Evidence
-}
-
-object DerivedFact {
-
- def apply[A](
- typeInfo: FactType[A],
- value: A,
- evidence: Evidence,
- ): DerivedFact =
- DerivedFactOfType(typeInfo, value, evidence)
-
- def unapply(fact: Fact): Option[(FactType[fact.Value], fact.Value, Evidence)] = fact match {
- case DerivedFactOfType(_, _, evidence) =>
- Some((fact.typeInfo, fact.value, evidence))
- case _ => None
- }
-}
-
-/**
- * A [[TypedFact]] that is provided in the initial [[FactTable]] by the caller.
- */
-final case class SourceFactOfType[A](
- typeInfo: FactType[A],
- value: A,
-) extends TypedFact[A] {
-
- override def toString: String = s"SourceFact(${typeInfo.fullName} = $value)"
-}
-
-/**
- * A [[TypedFact]] that is derived from the initial [[FactTable]] by some interpreted expression.
- *
- * @see [[DerivedFact]]
- */
-final case class DerivedFactOfType[A](
- typeInfo: FactType[A],
- value: A,
- evidence: Evidence,
-) extends TypedFact[A]
- with DerivedFact {
-
- override def toString: String = s"DerivedFact(${typeInfo.fullName} = $value, evidence = $evidence)"
-}
diff --git a/core/src/main/scala/vapors/data/FactOrFactSet.scala b/core/src/main/scala/vapors/data/FactOrFactSet.scala
deleted file mode 100644
index c3202fa21..000000000
--- a/core/src/main/scala/vapors/data/FactOrFactSet.scala
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.rallyhealth
-
-package vapors.data
-
-/**
- * A magnet type for passing individual [[Fact]]s and collections of [[Fact]]s into the same variable argument list.
- */
-final class FactOrFactSet private[FactOrFactSet] (val toSet: Set[Fact]) extends AnyVal
-
-object FactOrFactSet {
-
- implicit def setOfOneFact(fact: Fact): FactOrFactSet = new FactOrFactSet(Set(fact))
-
- implicit def iterableSetOfFacts(facts: Iterable[Fact]): FactOrFactSet =
- new FactOrFactSet(Set.from(facts))
-
- def flatten(factOrFactSets: Iterable[FactOrFactSet]): FactSet = {
- factOrFactSets.foldLeft(FactSet.empty)(_ | _.toSet)
- }
-}
diff --git a/core/src/main/scala/vapors/data/FactSet.scala b/core/src/main/scala/vapors/data/FactSet.scala
deleted file mode 100644
index 2086bf5d8..000000000
--- a/core/src/main/scala/vapors/data/FactSet.scala
+++ /dev/null
@@ -1,33 +0,0 @@
-package com.rallyhealth
-
-package vapors.data
-
-import cats.Foldable
-
-/**
- * @see [[FactSet]]
- */
-object FactSet {
-
- final val empty: FactSet = Set.empty[Fact]
-
- @inline final def apply(facts: Fact*): FactSet = Set.from(facts)
-
- @inline final def from(facts: IterableOnce[Fact]): FactSet = Set.from(facts)
-
- @inline final def fromFoldable[F[_] : Foldable](facts: F[Fact]): FactSet = {
- Set.from(Foldable[F].toIterable(facts))
- }
-}
-
-/**
- * @see [[TypedFactSet]]
- */
-object TypedFactSet {
-
- @inline final def empty[T]: TypedFactSet[T] = Set.empty[TypedFact[T]]
-
- @inline final def apply[T](facts: TypedFact[T]*): TypedFactSet[T] = Set.from(facts)
-
- @inline final def from[T](facts: Iterable[TypedFact[T]]): TypedFactSet[T] = Set.from(facts)
-}
diff --git a/core/src/main/scala/vapors/data/FactTable.scala b/core/src/main/scala/vapors/data/FactTable.scala
deleted file mode 100644
index fd70ed5ad..000000000
--- a/core/src/main/scala/vapors/data/FactTable.scala
+++ /dev/null
@@ -1,79 +0,0 @@
-package com.rallyhealth
-
-package vapors.data
-
-import vapors.lens.Indexed
-
-import cats.instances.order._
-import cats.{Eq, Monoid}
-
-import scala.collection.immutable.SortedMap
-
-/**
- * The current state of all the facts in an expression.
- *
- * @note some expressions can update the fact table for sub-expressions.
- */
-final case class FactTable(factsByName: SortedMap[String, FactSet]) extends AnyVal {
-
- def add(fact: Fact): FactTable = addAll(FactSet(fact))
-
- def addAll(facts: Iterable[Fact]): FactTable = {
- import cats.syntax.semigroup._
- val newFactTable = FactTable(facts)
- new FactTable(this.factsByName.combine(newFactTable.factsByName))
- }
-
- def getSortedSeq[T](factTypeSet: FactTypeSet[T]): IndexedSeq[TypedFact[T]] = {
- val sortedArray = getSet(factTypeSet).toArray.sortInPlace()
- sortedArray.toIndexedSeq
- }
-
- def getSet[T](factTypeSet: FactTypeSet[T]): TypedFactSet[T] = {
- val matchingFacts = for {
- factName <- factTypeSet.typeMap.toSortedMap.keys
- matchingFactsByName <- this.factsByName.get(factName)
- } yield matchingFactsByName.collect {
- case factTypeSet(matchingByType) => matchingByType
- }
- matchingFacts.reduceOption(_ | _).map(TypedFactSet.from).getOrElse(Set.empty)
- }
-}
-
-object FactTable {
-
- final val empty = new FactTable(SortedMap.empty)
-
- def apply(facts: FactOrFactSet*): FactTable = {
- val factSet = FactOrFactSet.flatten(facts)
- if (factSet.isEmpty) empty
- else new FactTable(SortedMap.from(factSet.groupBy(_.typeInfo.fullName)))
- }
-
- implicit object MonoidInstance extends Monoid[FactTable] {
- override def empty: FactTable = FactTable.empty
- override def combine(
- x: FactTable,
- y: FactTable,
- ): FactTable = {
- import cats.syntax.semigroup._
- new FactTable(x.factsByName |+| y.factsByName)
- }
- }
-
- implicit val eq: Eq[FactTable] = Eq.fromUniversalEquals
-
- implicit def indexedByFactType[T]: Indexed[FactTable, FactType[T], TypedFactSet[T]] = {
- new Indexed[FactTable, FactType[T], TypedFactSet[T]] {
- override def get(container: FactTable)(key: FactType[T]): TypedFactSet[T] = {
- container.getSet(key)
- }
- }
- }
-
- implicit def indexedByFactTypeSet[T]: Indexed[FactTable, FactTypeSet[T], TypedFactSet[T]] = {
- new Indexed[FactTable, FactTypeSet[T], TypedFactSet[T]] {
- override def get(container: FactTable)(key: FactTypeSet[T]): TypedFactSet[T] = container.getSet(key)
- }
- }
-}
diff --git a/core/src/main/scala/vapors/data/FactType.scala b/core/src/main/scala/vapors/data/FactType.scala
deleted file mode 100644
index c315fc98a..000000000
--- a/core/src/main/scala/vapors/data/FactType.scala
+++ /dev/null
@@ -1,104 +0,0 @@
-package com.rallyhealth
-
-package vapors.data
-
-import vapors.lens.{NamedLens, ValidDataPathKey}
-
-import cats.Order
-
-import scala.reflect.ClassTag
-import scala.reflect.runtime.universe.TypeTag
-
-/**
- * Type information required to construct a [[Fact]].
- */
-trait FactType[T] extends (T => TypedFact[T]) {
-
- /**
- * The unique name for this fact type.
- */
- def name: String
-
- /**
- * Definition for how to order fact values.
- */
- def order: Order[T]
-
- /**
- * The unique type name plus type information.
- */
- final lazy val fullName: String = s"'$name' as ${tt.tpe}"
-
- protected[vapors] implicit val ct: ClassTag[T]
- protected[vapors] implicit val tt: TypeTag[T]
-
- /**
- * Validates the value is the correct type, but packages it as an [[Fact]] to avoid
- * issues with the compiler attempting to find the LUB of the [[TypedFact]] type parameter using
- * a wildcard.
- *
- * If you need the specific type of fact for some reason, you can use the standard [[TypedFact]]
- * factory method and supply this fact type as the first parameter.
- */
- override def apply(value: T): TypedFact[T] = TypedFact(this, value)
-
- def unapply(value: Fact): Option[TypedFact[T]] = cast(value)
-
- /**
- * Safely cast the given fact to this type.
- */
- def cast(fact: Fact): Option[TypedFact[T]] = {
- fact match {
- // Justification: This checks validity of the FactType and safely casts the fact value using a class tag
- case f @ TypedFact(ft, _: T) if ft.tt.tpe <:< this.tt.tpe =>
- Some(f.asInstanceOf[TypedFact[T]])
- case f: Fact if f.typeInfo.tt.tpe <:< this.tt.tpe =>
- f.value match {
- case v: T => Some(TypedFact[T](f.typeInfo.asInstanceOf[FactType[T]], v))
- case _ => None
- }
- case _ => None
- }
- }
-
- /**
- * Defines FactType equality as "both types have the same name and compiled type."
- */
- override final def equals(o: Any): Boolean = o match {
- case that: FactType[_] =>
- this.fullName == that.fullName && this.tt.tpe =:= that.tt.tpe
- case _ => false
- }
-
- override final def hashCode: Int = this.fullName.hashCode()
-
- def productPrefix: String = "CustomFactType"
-
- override def toString: String = s"$productPrefix($fullName)"
-}
-
-object FactType {
-
- def apply[T : ClassTag : TypeTag : Order](name: String): FactType[T] = Simple(name)
-
- private final case class Simple[T : ClassTag : TypeTag : Order](name: String) extends FactType[T] {
- override val order: Order[T] = Order[T]
- override protected[vapors] val ct: ClassTag[T] = implicitly
- override protected[vapors] val tt: TypeTag[T] = implicitly
- override def productPrefix: String = "FactType"
- override def productElementName(n: Int): String = n match {
- case 0 => "name"
- case _ => super.productElementName(n)
- }
- }
-
- implicit class ToLens[T](private val ft: FactType[T]) extends AnyVal {
- def lens: NamedLens[TypedFact[T], T] = TypedFact.value[T]
- }
-
- implicit def orderingByName[T]: Ordering[FactType[T]] = Ordering.by(_.fullName)
-
- implicit def orderByName[T]: Order[FactType[T]] = Order.by(_.fullName)
-
- implicit def validDataPathKey[T]: ValidDataPathKey[FactType[T]] = _.fullName
-}
diff --git a/core/src/main/scala/vapors/data/FactTypeSet.scala b/core/src/main/scala/vapors/data/FactTypeSet.scala
deleted file mode 100644
index 9d7f6801e..000000000
--- a/core/src/main/scala/vapors/data/FactTypeSet.scala
+++ /dev/null
@@ -1,87 +0,0 @@
-package com.rallyhealth
-
-package vapors.data
-
-import cats.data.{NonEmptyList, NonEmptyMap, NonEmptySet}
-
-import scala.collection.immutable.{SortedMap, SortedSet}
-
-// TODO: Is there a better way to do this?
-// Maybe we can use something like the Has[_] data type to combine multiple fact types?
-
-/**
- * A set of [[FactType]]s that all share a common Scala type.
- *
- * This can be used to safely cast facts into a required type (lower-bounded by the type parameter of this object).
- *
- * @param typeMap a map of type names to [[FactType]]s, used for constant-time look-up
- */
-final case class FactTypeSet[A] private (typeMap: NonEmptyMap[String, FactType[A]]) extends AnyVal {
-
- def typeList: NonEmptyList[FactType[A]] = NonEmptyList.fromListUnsafe(typeMap.toSortedMap.values.toList)
-
- def typeSet: NonEmptySet[FactType[A]] = NonEmptySet.fromSetUnsafe(SortedSet.from(typeMap.toSortedMap.values))
-
- def unapply(fact: Fact): Option[TypedFact[A]] = collector.lift(fact)
-
- /**
- * Checks the [[FactType]] for equality with one of the types in this set.
- *
- * @return the [[TypedFact]] as the expected type.
- */
- def cast(fact: Fact): Option[TypedFact[A]] = collector.lift(fact)
-
- /**
- *
- * @return a partial function for collecting facts of a specific type
- */
- def collector: PartialFunction[Fact, TypedFact[A]] = {
- // Justification: This checks equality of the FactType at runtime, so it should be safe to cast
- case fact @ TypedFact(factType, _) if typeMap(factType.fullName).contains(factType) =>
- fact.asInstanceOf[TypedFact[A]]
- }
-
-}
-
-object FactTypeSet {
-
- /** Automatically wrap a single [[FactType]] into a [[FactTypeSet]] */
- implicit def one[A](factType: FactType[A]): FactTypeSet[A] = of(factType)
-
- /** Build a [[FactTypeSet]] from multiple [[FactType]]s that all share the same Scala type */
- def of[A](
- one: FactType[A],
- others: FactType[A]*,
- ): FactTypeSet[A] =
- new FactTypeSet(NonEmptyMap.of(one.fullName -> one, others.map(a => (a.fullName, a)): _*))
-
- def fromFactsNel[A](facts: NonEmptyList[TypedFact[A]]): FactTypeSet[A] = fromNel(facts.map(_.typeInfo))
-
- def fromNel[A](types: NonEmptyList[FactType[A]]): FactTypeSet[A] = of(types.head, types.tail: _*)
-
- def fromNes[A](types: NonEmptySet[FactType[A]]): FactTypeSet[A] = of(types.head, types.tail.toSeq: _*)
-
- def validateSet[A](types: Set[FactType[A]]): Either[String, FactTypeSet[A]] = validateList(types.toList)
-
- def validateList[A](types: List[FactType[A]]): Either[String, FactTypeSet[A]] = {
- val m = types.groupBy(_.fullName)
- val (duplicates, uniqueTypes) = m.partitionMap {
- case (name, one :: Nil) => Right((name, one))
- case (name, tooMany) => Left((name, tooMany))
- }
- if (duplicates.isEmpty) {
- NonEmptyMap
- .fromMap(SortedMap.from(uniqueTypes))
- .map(new FactTypeSet(_))
- .toRight("types list cannot be empty.")
- } else {
- Left(
- s"types list contains duplicate fact types: ${duplicates.map(_._1).mkString("'", "', '", "'")}",
- )
- }
- }
-
- def fromListOrThrow[A](types: List[FactType[A]]): FactTypeSet[A] = {
- validateList(types).fold(message => throw new IllegalArgumentException(message), identity)
- }
-}
diff --git a/core/src/main/scala/vapors/data/TimeOrder.scala b/core/src/main/scala/vapors/data/TimeOrder.scala
deleted file mode 100644
index 70eafa161..000000000
--- a/core/src/main/scala/vapors/data/TimeOrder.scala
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.rallyhealth
-
-package vapors.data
-
-object TimeOrder {
-
- @deprecated("This is confusingly named, please use com.rallyhealth.vapors.v1.data.YoungestFirst instead", "1.0.0")
- final val LatestFirst = vapors.v1.data.TimeOrder.YoungestFirst
-
- @deprecated(
- "This was implemented incorrectly, please use com.rallyhealth.vapors.v1.data.OldestFirst for the correct behavior",
- "1.0.0",
- )
- final val EarliestFirst = vapors.v1.data.TimeOrder.YoungestFirst
-}
diff --git a/core/src/main/scala/vapors/data/Window.scala b/core/src/main/scala/vapors/data/Window.scala
deleted file mode 100644
index 759f41021..000000000
--- a/core/src/main/scala/vapors/data/Window.scala
+++ /dev/null
@@ -1,148 +0,0 @@
-package com.rallyhealth
-
-package vapors.data
-
-import alleycats.Empty
-import cats.data.Ior
-import cats.{Invariant, Order, Show}
-
-import scala.collection.immutable.NumericRange
-
-/**
- * Represents an open or closed range with either 1 or 2 boundaries.
- *
- * A window can be bounded from below or above or both, and it can tell if a value is contained within
- * those boundaries.
- */
-trait Window[A] {
- def order: Order[A]
- def contains(value: A): Boolean
- def bounds: Ior[Bounded.Above[A], Bounded.Below[A]]
-}
-
-object Window {
- import Bounded._
- import cats.syntax.functor._
- import cats.syntax.order._
- import cats.syntax.show._
-
- def empty[A : Order : Empty]: Window[A] = new EmptyWindow[A]
-
- private final class EmptyWindow[A : Order : Empty] extends Window[A] {
- private val zero = Empty[A].empty
- override val order: Order[A] = Order[A]
- override def contains(value: A): Boolean = false
- override def bounds: Ior[Above[A], Below[A]] =
- Ior.Both(Above(zero, inclusiveLowerBound = false), Below(zero, inclusiveUpperBound = false))
- override def toString: String = s"Window.empty($zero)"
- }
-
- implicit object InvariantWindow extends Invariant[Window] {
- override def imap[A, B](fa: Window[A])(f: A => B)(g: B => A): Window[B] = {
- implicit val o: Order[B] = Order.by(g)(fa.order)
- val newBounds = fa.bounds.bimap(a => a.map(f), b => b.map(f))
- KnownWindow(newBounds)
- }
- }
-
- def showWindowWithTerm[A : Show](term: String): Show[Window[A]] = Show.show { window =>
- val (op1, op2) = window.bounds
- .bimap(
- b => (if (b.inclusiveLowerBound) ">=" else ">", ""),
- b => ("", if (b.inclusiveUpperBound) "<=" else "<"),
- )
- .merge
- window.bounds match {
- case Ior.Left(lb) => s"$term $op1 ${lb.lowerBound.show}"
- case Ior.Right(ub) => s"$term $op2 ${ub.upperBound.show}"
- case Ior.Both(lb, ub) =>
- s"$term $op1 ${lb.lowerBound.show} and $term $op2 ${ub.upperBound.show}"
- }
- }
-
- implicit def showWindow[A : Show]: Show[Window[A]] = showWindowWithTerm("x")
-
- def fromBounds[A : Order](bounds: Ior[Bounded.Above[A], Bounded.Below[A]]): Window[A] = KnownWindow(bounds)
-
- def fromRange(range: Range): Window[Int] =
- Window.between(range.start, includeMin = true, range.end, includeMax = range.isInclusive)
-
- def fromRange[A : Order](range: NumericRange[A]): Window[A] =
- Window.between(range.start, includeMin = true, range.end, includeMax = range.isInclusive)
-
- def equalTo[A : Order](value: A): Window[A] =
- Window.betweenInclusive(value, value)
-
- def lessThan[A : Order](
- max: A,
- inclusive: Boolean,
- ): Window[A] = KnownWindow(Ior.Right(Below(max, inclusive)))
-
- /** (-infinity, max) */
- def lessThan[A : Order](max: A): Window[A] = lessThan(max, inclusive = false)
-
- /** (-infinity, max] */
- def lessThanOrEqual[A : Order](max: A): Window[A] = lessThan(max, inclusive = true)
-
- /** Generally defined range with configurable open or lower bound. */
- def greaterThan[A : Order](
- min: A,
- inclusive: Boolean,
- ): Window[A] = KnownWindow(Ior.Left(Above(min, inclusiveLowerBound = inclusive)))
-
- /** (min, +infinity) */
- def greaterThan[A : Order](min: A): Window[A] = greaterThan(min, inclusive = false)
-
- /** [min, +infinity) */
- def greaterThanOrEqual[A : Order](min: A): Window[A] = greaterThan(min, inclusive = true)
-
- /** Generally defined bounded range with the ability to set open or closed at each end of the range.*/
- def between[A : Order](
- min: A,
- includeMin: Boolean,
- max: A,
- includeMax: Boolean,
- ): Window[A] =
- KnownWindow(Ior.Both(Above(min, includeMin), Below(max, includeMax)))
-
- /** [min,max) */
- def between[A : Order](
- min: A,
- max: A,
- ): Window[A] = between(min, includeMin = true, max, includeMax = false)
-
- /** [min,max] */
- def betweenInclusive[A : Order](
- min: A,
- max: A,
- ): Window[A] = between(min, includeMin = true, max, includeMax = true)
-
- private[Window] final case class KnownWindow[A](
- bounds: Ior[Above[A], Below[A]],
- )(implicit
- override val order: Order[A],
- ) extends Window[A] {
-
- private val checkBetween: A => Boolean = bounds match {
- case Ior.Left(lb) if lb.inclusiveLowerBound => _ >= lb.lowerBound
- case Ior.Left(lb) => _ > lb.lowerBound
-
- case Ior.Right(ub) if ub.inclusiveUpperBound => _ <= ub.upperBound
- case Ior.Right(ub) => _ < ub.upperBound
-
- case Ior.Both(lb, ub) if lb.lowerBound == ub.upperBound && (lb.inclusiveLowerBound || ub.inclusiveUpperBound) =>
- a => a == lb.lowerBound
- case Ior.Both(lb, ub) if lb.inclusiveLowerBound && ub.inclusiveUpperBound =>
- a => a >= lb.lowerBound && a <= ub.upperBound
- case Ior.Both(lb, ub) if ub.inclusiveUpperBound =>
- a => a > lb.lowerBound && a <= ub.upperBound
- case Ior.Both(lb, ub) if lb.inclusiveLowerBound =>
- a => a >= lb.lowerBound && a < ub.upperBound
- case Ior.Both(lb, ub) =>
- a => a > lb.lowerBound && a < ub.upperBound
- }
-
- override def contains(value: A): Boolean = checkBetween(value)
- }
-
-}
diff --git a/core/src/main/scala/vapors/data/package.scala b/core/src/main/scala/vapors/data/package.scala
deleted file mode 100644
index 176e6c115..000000000
--- a/core/src/main/scala/vapors/data/package.scala
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.rallyhealth
-
-package vapors
-
-package object data {
-
- /**
- * Special case of [[ExtractValue]] that extracts a [[Boolean]] value.
- */
- final type ExtractBoolean[-T] = ExtractValue[T, Boolean]
-
- object ExtractBoolean {
-
- @deprecated("Use ExtractValue[Boolean].from[T]", "0.14.1")
- @inline final def apply[T](implicit instance: ExtractBoolean[T]): ExtractBoolean[T] = instance
- }
-
- /**
- * An ordered set of untyped [[Fact]]s.
- */
- final type FactSet = Set[Fact]
-
- /**
- * An ordered set of [[TypedFact]]s.
- *
- * @note not to be confused with a [[FactTypeSet]] (which is a set of [[FactType]]s, with not values)
- */
- final type TypedFactSet[T] = Set[TypedFact[T]]
-
- @deprecated("Use com.rallyhealth.vapors.v1.data.TimeOrder instead.", "1.0.0")
- type TimeOrder = vapors.v1.data.TimeOrder
-}
diff --git a/core/src/main/scala/vapors/dsl/ConcatOutputExprBuilder.scala b/core/src/main/scala/vapors/dsl/ConcatOutputExprBuilder.scala
deleted file mode 100644
index 6ad134df4..000000000
--- a/core/src/main/scala/vapors/dsl/ConcatOutputExprBuilder.scala
+++ /dev/null
@@ -1,70 +0,0 @@
-package com.rallyhealth
-
-package vapors.dsl
-
-import vapors.algebra.{CaptureP, Expr}
-import vapors.lens.NamedLens
-
-import cats.MonoidK
-
-import scala.collection.Factory
-
-final class ConcatOutputExprBuilder[V, M[_], R, P](private val expressions: LazyList[Expr[V, M[R], P]]) extends AnyVal {
-
- /**
- * Concatenates the results of all the expressions into a single [[LazyList]].
- *
- * This requires that the return type is an [[IterableOnce]] scala collection.
- *
- * This is generally preferable as a data structure because you probably don't want to compute things
- * that are not used.
- *
- * @example
- * {{{
- * assert(eval(concat(Some(1), None, Some(2)).toLazyList).output.value == LazyList(1, 2))
- * }}}
- */
- def toLazyList(
- implicit
- ev: M[R] <:< IterableOnce[R],
- captureResult: CaptureP[V, LazyList[R], P],
- ): Expr.ConcatOutput[V, LazyList, R, P] =
- Expr.ConcatOutput(
- expressions.map { expr =>
- Expr.SelectFromOutput(
- expr,
- NamedLens.id[M[R]].asIterable[R].to(LazyList: Factory[R, LazyList[R]]),
- captureResult,
- )
- },
- captureResult,
- )
-
- /**
- * Combines all the results of the expressions using the definition of monoid for the return type.
- *
- * This requires that the return type constructor has a standard definition for [[MonoidK]].
- *
- * @example
- * {{{
- * assert(eval(concat(List(1, 2), List(3, 4)).toOutputMonoid).output.value == List(1, 2, 3, 4))
- * }}}
- */
- def toOutputMonoid(
- implicit
- monoidKM: MonoidK[M],
- captureResult: CaptureP[V, M[R], P],
- ): Expr.ConcatOutput[V, M, R, P] =
- Expr.ConcatOutput(expressions, captureResult)
-
-}
-
-object ConcatOutputExprBuilder {
-
- implicit def defaultAsMonoid[V, M[_] : MonoidK, R, P](
- builder: ConcatOutputExprBuilder[V, M, R, P],
- )(implicit
- captureResult: CaptureP[V, M[R], P],
- ): Expr.ConcatOutput[V, M, R, P] =
- builder.toOutputMonoid
-}
diff --git a/core/src/main/scala/vapors/dsl/DefinitionExprBuilder.scala b/core/src/main/scala/vapors/dsl/DefinitionExprBuilder.scala
deleted file mode 100644
index 8ff595fe9..000000000
--- a/core/src/main/scala/vapors/dsl/DefinitionExprBuilder.scala
+++ /dev/null
@@ -1,31 +0,0 @@
-package com.rallyhealth
-
-package vapors.dsl
-
-import vapors.algebra.Expr
-import vapors.data.{FactSet, FactType}
-
-import cats.{Foldable, Id}
-
-final class DefinitionExprBuilder[T](private val factType: FactType[T]) extends AnyVal {
-
- /**
- * Creates a definition that always adds exactly one fact.
- */
- def from[P](
- defExpr: RootExpr[T, P],
- )(implicit
- captureResult: CaptureRootExpr[FactSet, P],
- ): Expr.Define[Id, T, P] =
- Expr.Define[Id, T, P](factType, defExpr, captureResult)
-
- /**
- * Creates a definition that adds a fact for every value returned by the [[Foldable]] [[Expr]].
- */
- def fromEvery[M[_] : Foldable, P](
- defExpr: RootExpr[M[T], P],
- )(implicit
- captureResult: CaptureRootExpr[FactSet, P],
- ): Expr.Define[M, T, P] =
- Expr.Define(factType, defExpr, captureResult)
-}
diff --git a/core/src/main/scala/vapors/dsl/ExprBuilder.scala b/core/src/main/scala/vapors/dsl/ExprBuilder.scala
deleted file mode 100644
index 011ed7d78..000000000
--- a/core/src/main/scala/vapors/dsl/ExprBuilder.scala
+++ /dev/null
@@ -1,746 +0,0 @@
-package com.rallyhealth
-
-package vapors.dsl
-
-import vapors.algebra.{CaptureP, Expr, ExprConverter, ExprSorter}
-import vapors.data.{Evidence, FactTable, TypedFact, Window}
-import vapors.lens.NamedLens
-import vapors.math._
-
-import cats._
-
-import scala.collection.{Factory, MapView, View}
-import scala.reflect.runtime.universe.TypeTag
-
-/**
- * Chains algebraic operations into a single [[Expr]] node.
- *
- * @param returnOutput the head of the tree of expressions as built so far
- *
- * TODO: Make this more reusable for [[MapViewExprBuilder]]
- */
-sealed class ExprBuilder[V, M[_], U, P](val returnOutput: Expr[V, M[U], P]) {
-
- type CaptureResult[R] = CaptureP[V, R, P]
-
- type CaptureCondResult = CaptureResult[Boolean]
-
- type CaptureInputResult[R] = CaptureP[U, R, P]
- type CaptureInputAsResult = CaptureInputResult[U]
- type CaptureInputCondResult = CaptureInputResult[Boolean]
-
- def returnInput(implicit captureResult: CaptureResult[V]): Expr[V, V, P] = Expr.ReturnInput(captureResult)
-
- /**
- * Embed the result of an expression with the input of the current builder.
- */
- def embedResult[A](
- expr: RootExpr[A, P],
- )(implicit
- captureEmbed: CaptureP[V, A, P],
- ): ValExprBuilder[V, A, P] =
- new ValExprBuilder[V, A, P](Expr.Embed(expr, captureEmbed))
-
- /**
- * Embed a constant value with the input of the current builder.
- */
- def embedConst[A](
- value: A,
- )(implicit
- captureConst: CaptureRootExpr[A, P],
- captureEmbed: CaptureP[V, A, P],
- ): ValExprBuilder[V, A, P] =
- new ValExprBuilder[V, A, P](Expr.Embed(Expr.ConstOutput(value, Evidence.none, captureConst), captureEmbed))
-}
-
-object ExprBuilder {
-
- type ValId[V, P] = ValExprBuilder[V, V, P]
- type ValFn[V, R, P] = ValExprBuilder[V, V, P] => ExprBuilder[V, Id, R, P]
-
- type FoldableId[F[_], V, P] = FoldableExprBuilder[F[V], F, V, P]
- type FoldableFn[F[_], V, M[_], U, P] = FoldableId[F, V, P] => ExprBuilder[F[V], M, U, P]
-}
-
-trait ExprBuilderSyntax {
-
- /**
- * Implicitly allows embedding any expression that only requires the FactTable into expression.
- *
- * @see [[Expr.Embed]]
- */
- implicit def embedExpr[V, R, P](
- expr: RootExpr[R, P],
- )(implicit
- captureResult: CaptureP[V, R, P],
- ): Expr.Embed[V, R, P] = Expr.Embed(expr, captureResult)
-
- implicit def liftValExpr[V, R, P](expr: Expr[V, R, P]): ValExprBuilder[V, R, P] =
- new ValExprBuilder(expr)
-
- implicit def returnFoldableExprOutput[V, M[_], U, P](builder: FoldableExprBuilder[V, M, U, P]): Expr[V, M[U], P] =
- builder.returnOutput
-
- implicit def returnValExprOutput[V, R, P](builder: ValExprBuilder[V, R, P]): Expr[V, R, P] =
- builder.returnOutput
-
- implicit def addTo[R : Addition](lhs: R): AdditionBuilderOps[R] = new AdditionBuilderOps(lhs)
-
- implicit def subtractFrom[R : Subtraction](lhs: R): SubtractBuilderOps[R] = new SubtractBuilderOps(lhs)
-
- implicit def divideFrom[R : Division](lhs: R): DivisionBuilderOps[R] = new DivisionBuilderOps(lhs)
-
-}
-
-final class AdditionBuilderOps[R : Addition](number: R) {
-
- def +[V, P](
- builder: ValExprBuilder[V, R, P],
- )(implicit
- captureResult: builder.CaptureResult[R],
- ): ValExprBuilder[V, R, P] = {
- builder.addTo(number)
- }
-}
-
-final class SubtractBuilderOps[R : Subtraction](number: R) {
-
- def -[V, P](
- builder: ValExprBuilder[V, R, P],
- )(implicit
- captureResult: builder.CaptureResult[R],
- ): ValExprBuilder[V, R, P] = {
- builder.subtractFrom(number)
- }
-}
-
-final class MultiplicationBuilderOps[R : Multiplication](number: R) {
-
- def *[V, P](
- builder: ValExprBuilder[V, R, P],
- )(implicit
- captureResult: builder.CaptureResult[R],
- ): ValExprBuilder[V, R, P] = {
- builder.multiplyTo(number)
- }
-}
-
-final class DivisionBuilderOps[R : Division](number: R) {
-
- def /[V, P](
- builder: ValExprBuilder[V, R, P],
- )(implicit
- captureResult: builder.CaptureResult[R],
- ): ValExprBuilder[V, R, P] = {
- builder.divideFrom(number)
- }
-}
-
-/**
- * Same as [[ExprBuilder]], but for arity-1 higher-kinded types
- *
- * @see [[ExprBuilder]]
- *
- * TODO: Rename? Is this always foldable?
- */
-final class FoldableExprBuilder[V, M[_], U, P](returnOutput: Expr[V, M[U], P])
- extends ExprBuilder[V, M, U, P](returnOutput) {
-
- /**
- * Same as [[to]](List).
- */
- def toList(
- implicit
- ev: M[U] <:< IterableOnce[U],
- captureResult: CaptureResult[List[U]],
- ): FoldableExprBuilder[V, List, U, P] =
- to(List)
-
- /**
- * Same as [[to]](Set).
- */
- def toSet(
- implicit
- ev: M[U] <:< IterableOnce[U],
- captureResult: CaptureResult[Set[U]],
- ): FoldableExprBuilder[V, Set, U, P] =
- to(Set)
-
- /**
- * Converts the iterable of 2-tuples return value into a Map.
- *
- * @example
- * {{{
- * assert(eval(const(Set("A" -> 1, "B" -> 2)).withOutputFoldable.toMap).output.value == Map("A" -> 1, "B" -> 2))
- * }}}
- */
- def toMap[K, X](
- implicit
- ev: M[U] <:< IterableOnce[(K, X)],
- captureResult: CaptureResult[MapView[K, X]],
- ): MapViewExprBuilder[V, K, X, P] =
- new MapViewExprBuilder(
- Expr.SelectFromOutput[V, M[U], MapView[K, X], P](
- returnOutput,
- NamedLens.id[M[U]].toMapView,
- captureResult,
- ),
- )
-
- /**
- * Converts the iterable return value into the specific Scala collection companion object.
- *
- * @example
- * {{{
- * assert(eval(const(List(1, 2, 2, 3)).withOutputFoldable.to(Set)).output.value == Set(1, 2, 3))
- * }}}
- */
- def to[N[_] : Foldable](
- factory: Factory[U, N[U]],
- )(implicit
- ev: M[U] <:< IterableOnce[U],
- captureResult: CaptureResult[N[U]],
- ): FoldableExprBuilder[V, N, U, P] =
- new FoldableExprBuilder(
- Expr.SelectFromOutput[V, M[U], N[U], P](
- returnOutput,
- NamedLens.id[M[U]].asIterable.to(factory),
- captureResult,
- ),
- )
-
- /**
- * Sorts the sequence of values returned based on the given total ordering for the value type.
- */
- def sorted(
- implicit
- orderU: Order[U],
- ev: M[U] <:< Seq[U],
- tt: TypeTag[U],
- factory: Factory[U, M[U]],
- captureResult: CaptureResult[M[U]],
- ): FoldableExprBuilder[V, M, U, P] =
- new FoldableExprBuilder(Expr.SortOutput(returnOutput, ExprSorter.byNaturalOrder[M, U], captureResult))
-
- /**
- * Sorts the sequence of values returned based on the given total ordering for the type of the
- * selected field of the values.
- */
- def sortBy[R : Order](
- buildLens: NamedLens.Fn[U, R],
- )(implicit
- ev: M[U] <:< Seq[U],
- tt: TypeTag[U],
- factory: Factory[U, M[U]],
- captureResult: CaptureResult[M[U]],
- ): FoldableExprBuilder[V, M, U, P] = {
- val lens = buildLens(NamedLens.id[U])
- new FoldableExprBuilder(Expr.SortOutput(returnOutput, ExprSorter.byField[M, U, R](lens), captureResult))
- }
-
- /**
- * Groups the [[Foldable]] return value by the selected field.
- *
- * The values of the map produced must have a total ordering so that they are retrieved from the map
- * in a consistent and predictable way.
- */
- def groupBy[K](
- buildKeyLens: NamedLens.Fn[U, K],
- )(implicit
- foldableM: Foldable[M],
- orderU: Order[U],
- captureSelect: CaptureResult[View[(K, Seq[U])]],
- captureResult: CaptureResult[MapView[K, Seq[U]]],
- ): MapViewExprBuilder[V, K, Seq[U], P] = {
- val keyLens = buildKeyLens(NamedLens.id[U])
- new MapViewExprBuilder(Expr.GroupOutput(returnOutput, keyLens, captureResult))
- }
-
- /**
- * Takes a given number of elements from the start of the traversable return value.
- */
- def take(
- n: Int,
- )(implicit
- traverseM: Traverse[M],
- traverseFilterM: TraverseFilter[M],
- captureResult: CaptureResult[M[U]],
- ): FoldableExprBuilder[V, M, U, P] =
- new FoldableExprBuilder(Expr.TakeFromOutput(returnOutput, n, captureResult))
-
- /**
- * Takes the first element from the start of the traversable return value or None, if the return value is empty.
- */
- def headOption(
- implicit
- traverseM: Traverse[M],
- traverseFilterM: TraverseFilter[M],
- ev: M[U] <:< Iterable[U],
- captureAllResults: CaptureResult[M[U]],
- captureHeadResult: CaptureResult[Option[U]],
- ): FoldableExprBuilder[V, Option, U, P] =
- new FoldableExprBuilder(
- Expr.SelectFromOutput(take(1), NamedLens.id[M[U]].headOption, captureHeadResult),
- )
-
- /**
- * Maps an expression over every element of the returned [[Functor]] and folds the evidence together.
- */
- def map[R](
- buildFn: ValExprBuilder[U, U, P] => ExprBuilder[U, Id, R, P],
- )(implicit
- foldableM: Foldable[M],
- functorM: Functor[M],
- postEachOutput: CaptureInputAsResult,
- postMap: CaptureResult[M[R]],
- ): FoldableExprBuilder[V, M, R, P] = {
- val mapExpr = buildFn(
- new ValExprBuilder(Expr.ReturnInput(postEachOutput)),
- )
- val next = Expr.MapOutput(returnOutput, mapExpr.returnOutput, postMap)
- new FoldableExprBuilder(next)
- }
-
- /**
- * Maps an expression that produces the same return type constructor and flattens all the returned
- * elements together based on the definition of [[FlatMap]].
- *
- * This will also fold all the evidence together.
- *
- * @note there is no good definition of `flatMap` inside of an applicative data structure. The input
- * to any outer expression builder almost always not be the same type as the type of input to
- * the inner expression to be flattened. This means that you can't reference any expression outside
- * of the scope of the expression builder function given to `.flatMap`.
- *
- * The only way to fix this would be to provide some way to carry the input from previous expressions
- * around in some kind of stack or grab bag, from which you could grab values for another expression.
- * Until then, this method is kind of useless.
- */
- def flatMap[X](
- buildFn: ValExprBuilder[U, U, P] => ExprBuilder[U, M, X, P],
- )(implicit
- foldableM: Foldable[M],
- flatMapM: FlatMap[M],
- postEachInput: CaptureInputAsResult,
- postFlatMap: CaptureResult[M[X]],
- ): FoldableExprBuilder[V, M, X, P] = {
- val flatMapExpr = buildFn(
- new ValExprBuilder(Expr.ReturnInput(postEachInput)),
- )
- val next = Expr.FlatMapOutput(returnOutput, flatMapExpr.returnOutput, postFlatMap)
- new FoldableExprBuilder(next)
- }
-
- /**
- * Fold all the result values into a single result based on the definition of [[Monoid]].
- *
- * @example
- * {{{
- * // for better or for worse, the default definition of Monoid[Int] is summation
- * assert(eval(const(List(1, 2, 3)).withOutputFoldable.fold).output.value == 6)
- * }}}
- */
- def fold(
- implicit
- foldableM: Foldable[M],
- monoidU: Monoid[U],
- captureResult: CaptureResult[U],
- ): ValExprBuilder[V, U, P] = {
- new ValExprBuilder(Expr.FoldOutput(returnOutput, captureResult))
- }
-
- /**
- * Returns true if the result value is an empty [[Foldable]].
- */
- def isEmpty(
- implicit
- foldableM: Foldable[M],
- captureResult: CaptureCondResult,
- ): ValExprBuilder[V, Boolean, P] =
- new ValExprBuilder(Expr.OutputIsEmpty(returnOutput, captureResult))
-
- /**
- * Computes the given condition expression for every element of the returned value until one returns true
- * OR the returned value is empty. Otherwise -- if all elements of the non-empty returned value return false
- * -- this expression will return false.
- */
- def exists(
- buildFn: ValExprBuilder[U, U, P] => ExprBuilder[U, Id, Boolean, P],
- )(implicit
- foldableM: Foldable[M],
- postEachOutput: CaptureP[U, U, P],
- captureResult: CaptureCondResult,
- ): ValExprBuilder[V, Boolean, P] = {
- val condExpr = buildFn(new ValExprBuilder(Expr.ReturnInput(postEachOutput)))
- val next = Expr.ExistsInOutput(returnOutput, condExpr.returnOutput, captureResult)
- new ValExprBuilder(next)
- }
-
- /**
- * Filters out all elements of the returned [[Foldable]] for which the given conditional expression returns false.
- *
- * What's left is all the elements of this expression's returned [[Foldable]] for which the given condition
- * returns true.
- */
- def filter(
- buildFn: ValExprBuilder[U, U, P] => ExprBuilder[U, Id, Boolean, P],
- )(implicit
- foldableM: Foldable[M],
- filterM: FunctorFilter[M],
- captureInput: CaptureInputResult[U],
- captureResult: CaptureResult[M[U]],
- ): FoldableExprBuilder[V, M, U, P] = {
- val condExpr = buildFn(
- new ValExprBuilder(Expr.ReturnInput(captureInput)),
- )
- new FoldableExprBuilder(Expr.FilterOutput(returnOutput, condExpr.returnOutput, captureResult))
- }
-
- /**
- * Returns true if the returned [[Foldable]] shares any elements in common with the given set of valid values.
- */
- def containsAny(
- validValues: Set[U],
- )(implicit
- foldableM: Foldable[M],
- filterM: FunctorFilter[M],
- captureCond: CaptureCondResult,
- captureFilterCond: CaptureInputCondResult,
- captureFilterInput: CaptureInputResult[U],
- captureFilterResult: CaptureResult[M[U]],
- ): ValExprBuilder[V, Boolean, P] =
- new ValExprBuilder[V, Boolean, P](
- Expr.Not(
- filter(_ in validValues).isEmpty,
- captureCond,
- ),
- )
-}
-
-/**
- * Same as [[ExprBuilder]], but for concrete types.
- *
- * @see [[ExprBuilder]]
- *
- * TODO: This should probably share some methods with [[FoldableExprBuilder]]... or at least
- * switching between builder types should be a lot easier.
- */
-final class ValExprBuilder[V, R, P](override val returnOutput: Expr[V, R, P])
- extends ExprBuilder[V, Id, R, P](returnOutput) {
-
- // chains expression builder .get calls into a single select operation
- @inline private def buildGetExpr[N[_], X](
- buildLens: NamedLens.Fn[R, N[X]],
- )(implicit
- captureResult: CaptureResult[N[X]],
- ): Expr[V, N[X], P] = {
- val lens = buildLens(NamedLens.id[R])
- // if the previous node was a SelectFromOutput, then combine the lenses and produce a single node
- returnOutput match {
- case prev: Expr.SelectFromOutput[V, s, R, P] =>
- // capture the starting type as an existential type parameter 's'
- // it is ignored in the return type after the compile proves that this code is safe
- Expr.SelectFromOutput[V, s, N[X], P](prev.inputExpr, prev.lens.andThen(lens), captureResult)
- case _ =>
- // otherwise, build the lens as a new SelectFromOutput node
- Expr.SelectFromOutput(returnOutput, lens, captureResult)
- }
- }
-
- /**
- * Selects a field from the returned value using the given lens.
- *
- * @example
- * {{{
- * // assuming you run this example in 2021...
- * assert(const(LocalDate.now()).withOutputValue.get(_.select(_.getYear)).output.value == 2021)
- * }}}
- */
- def get[X](
- buildLens: NamedLens.Fn[R, X],
- )(implicit
- captureResult: CaptureResult[X],
- ): ValExprBuilder[V, X, P] =
- new ValExprBuilder(buildGetExpr[Id, X](buildLens))
-
- /**
- * Same as [[get]], except it expects the selected value to have a higher-kinded type and returns
- * a [[FoldableExprBuilder]].
- *
- * @example
- * {{{
- * // selecting a value from a Map returns an Option, which is foldable
- * assert(const(Map("A" -> 1)).withOutputValue.getFoldable(_.at("A")).isEmpty).output.value == false)
- * }}}
- *
- * TODO: Rename? It only needs to be a higher-kinded type, but [[FoldableExprBuilder]] almost always
- * requires a [[Foldable]] definition for any chained operations. Ideally, we would be able
- * to avoid needing to distinguish the type of builder to use until after we have selected the field.
- */
- def getFoldable[N[_], X](
- buildLens: NamedLens.Fn[R, N[X]],
- )(implicit
- captureResult: CaptureResult[N[X]],
- ): FoldableExprBuilder[V, N, X, P] =
- new FoldableExprBuilder(buildGetExpr(buildLens))
-
- @deprecated(
- "Use valuesOfType(...) to avoid needing this .value method or use .get(_.select(_.value)) instead.",
- "0.17.0",
- )
- def value[X](
- implicit
- ev: R <:< TypedFact[X],
- captureResult: CaptureResult[X],
- ): ValExprBuilder[V, X, P] =
- new ValExprBuilder(buildGetExpr[Id, X](_.field("value", _.value)))
-
- def in(accepted: Set[R])(implicit captureCond: CaptureCondResult): ValExprBuilder[V, Boolean, P] =
- new ValExprBuilder(Expr.OutputWithinSet(returnOutput, accepted, captureCond))
-
- def +(
- rhs: Expr[V, R, P],
- )(implicit
- R: Addition[R],
- captureResult: CaptureResult[R],
- ): ValExprBuilder[V, R, P] =
- new ValExprBuilder(ExprDsl.add(returnOutput, rhs))
-
- def +(
- rhs: R,
- )(implicit
- R: Addition[R],
- captureResult: CaptureResult[R],
- ): ValExprBuilder[V, R, P] =
- new ValExprBuilder(ExprDsl.add(returnOutput, Expr.ConstOutput(rhs, Evidence.none, captureResult)))
-
- def addTo(
- lhs: R,
- )(implicit
- R: Addition[R],
- captureResult: CaptureResult[R],
- ): ValExprBuilder[V, R, P] =
- new ValExprBuilder(ExprDsl.add(Expr.ConstOutput(lhs, Evidence.none, captureResult), returnOutput))
-
- def *(
- rhs: Expr[V, R, P],
- )(implicit
- R: Multiplication[R],
- captureResult: CaptureResult[R],
- ): ValExprBuilder[V, R, P] =
- new ValExprBuilder(ExprDsl.multiply(returnOutput, rhs))
-
- def *(
- rhs: R,
- )(implicit
- R: Multiplication[R],
- captureResult: CaptureResult[R],
- ): ValExprBuilder[V, R, P] =
- new ValExprBuilder(ExprDsl.multiply(returnOutput, Expr.ConstOutput(rhs, Evidence.none, captureResult)))
-
- def multiplyTo(
- lhs: R,
- )(implicit
- R: Multiplication[R],
- captureResult: CaptureResult[R],
- ): ValExprBuilder[V, R, P] =
- new ValExprBuilder(ExprDsl.multiply(Expr.ConstOutput(lhs, Evidence.none, captureResult), returnOutput))
-
- def -(
- rhs: Expr[V, R, P],
- )(implicit
- R: Subtraction[R],
- captureResult: CaptureResult[R],
- ): ValExprBuilder[V, R, P] =
- new ValExprBuilder(ExprDsl.subtract(returnOutput, rhs))
-
- def -(
- rhs: R,
- )(implicit
- R: Subtraction[R],
- captureResult: CaptureResult[R],
- ): ValExprBuilder[V, R, P] =
- new ValExprBuilder(ExprDsl.subtract(returnOutput, Expr.ConstOutput(rhs, Evidence.none, captureResult)))
-
- def subtractFrom(
- lhs: R,
- )(implicit
- R: Subtraction[R],
- captureResult: CaptureResult[R],
- ): ValExprBuilder[V, R, P] =
- new ValExprBuilder(ExprDsl.subtract(Expr.ConstOutput(lhs, Evidence.none, captureResult), returnOutput))
-
- def /(
- rhs: Expr[V, R, P],
- )(implicit
- R: Division[R],
- captureResult: CaptureResult[R],
- ): ValExprBuilder[V, R, P] =
- new ValExprBuilder(ExprDsl.divide(returnOutput, rhs))
-
- def /(
- rhs: R,
- )(implicit
- R: Division[R],
- captureResult: CaptureResult[R],
- ): ValExprBuilder[V, R, P] =
- new ValExprBuilder(ExprDsl.divide(returnOutput, Expr.ConstOutput(rhs, Evidence.none, captureResult)))
-
- def divideFrom(
- lhs: R,
- )(implicit
- R: Division[R],
- captureResult: CaptureResult[R],
- ): ValExprBuilder[V, R, P] =
- new ValExprBuilder(ExprDsl.divide(Expr.ConstOutput(lhs, Evidence.none, captureResult), returnOutput))
-
- def unary_-(
- implicit
- R: Negative[R],
- captureResult: CaptureResult[R],
- ): ValExprBuilder[V, R, P] =
- new ValExprBuilder(ExprDsl.negative(returnOutput))
-
- def withinWindow(
- windowExpr: Expr[V, Window[R], P],
- )(implicit
- captureResult: CaptureCondResult,
- ): ValExprBuilder[V, Boolean, P] =
- new ValExprBuilder(ExprDsl.within(returnOutput, windowExpr))
-
- def within(
- window: Window[R],
- )(implicit
- captureWindow: CaptureP[V, Window[R], P],
- captureConst: CaptureP[FactTable, Window[R], P],
- captureResult: CaptureCondResult,
- ): ValExprBuilder[V, Boolean, P] =
- new ValExprBuilder(
- Expr.OutputWithinWindow(returnOutput, embed(const(window)(captureConst))(captureWindow), captureResult),
- )
-
- @deprecated("Use === const(...) instead. This method doesn't fit with the overall DSL.", "0.17.0")
- def isEqualTo(
- value: R,
- )(implicit
- orderR: Order[R],
- captureWindow: CaptureP[V, Window[R], P],
- captureConst: CaptureP[FactTable, Window[R], P],
- captureResult: CaptureCondResult,
- ): ValExprBuilder[V, Boolean, P] =
- within(Window.equalTo(value))
-
- def ===(
- value: R,
- )(implicit
- orderR: Order[R],
- captureWindow: CaptureP[V, Window[R], P],
- captureConst: CaptureP[FactTable, Window[R], P],
- captureResult: CaptureCondResult,
- ): ValExprBuilder[V, Boolean, P] =
- within(Window.equalTo(value))
-
- def ===(
- valueExpr: Expr[V, R, P],
- )(implicit
- orderR: Order[R],
- captureWindow: CaptureP[V, Window[R], P],
- captureResult: CaptureCondResult,
- ): ValExprBuilder[V, Boolean, P] =
- withinWindow(Expr.WrapOutput(valueExpr, ExprConverter.asWindow[R](Window.equalTo(_)), captureWindow))
-
- def !==(
- value: R,
- )(implicit
- orderR: Order[R],
- captureWindow: CaptureP[V, Window[R], P],
- captureConst: CaptureP[FactTable, Window[R], P],
- captureResult: CaptureCondResult,
- ): ValExprBuilder[V, Boolean, P] =
- Expr.Not(within(Window.equalTo(value)), captureResult)
-
- def !==(
- valueExpr: Expr[V, R, P],
- )(implicit
- orderR: Order[R],
- captureWindow: CaptureP[V, Window[R], P],
- captureResult: CaptureCondResult,
- ): ValExprBuilder[V, Boolean, P] =
- Expr.Not(this === valueExpr, captureResult)
-
- def <(
- value: R,
- )(implicit
- orderR: Order[R],
- captureWindow: CaptureP[V, Window[R], P],
- captureConst: CaptureP[FactTable, Window[R], P],
- captureResult: CaptureCondResult,
- ): ValExprBuilder[V, Boolean, P] =
- within(Window.lessThan(value))
-
- def <(
- valueExpr: Expr[V, R, P],
- )(implicit
- orderR: Order[R],
- captureWindow: CaptureP[V, Window[R], P],
- captureResult: CaptureCondResult,
- ): ValExprBuilder[V, Boolean, P] =
- withinWindow(Expr.WrapOutput(valueExpr, ExprConverter.asWindow[R](Window.lessThan(_)), captureWindow))
-
- def <=(
- value: R,
- )(implicit
- orderR: Order[R],
- captureWindow: CaptureP[V, Window[R], P],
- captureConst: CaptureP[FactTable, Window[R], P],
- captureResult: CaptureCondResult,
- ): ValExprBuilder[V, Boolean, P] =
- within(Window.lessThanOrEqual(value))
-
- def <=(
- valueExpr: Expr[V, R, P],
- )(implicit
- orderR: Order[R],
- captureWindow: CaptureP[V, Window[R], P],
- captureResult: CaptureCondResult,
- ): ValExprBuilder[V, Boolean, P] =
- withinWindow(Expr.WrapOutput(valueExpr, ExprConverter.asWindow[R](Window.lessThanOrEqual(_)), captureWindow))
-
- def >(
- value: R,
- )(implicit
- orderR: Order[R],
- captureWindow: CaptureP[V, Window[R], P],
- captureConst: CaptureP[FactTable, Window[R], P],
- captureResult: CaptureCondResult,
- ): ValExprBuilder[V, Boolean, P] =
- within(Window.greaterThan(value))
-
- def >(
- valueExpr: Expr[V, R, P],
- )(implicit
- orderR: Order[R],
- captureWindow: CaptureP[V, Window[R], P],
- captureResult: CaptureCondResult,
- ): ValExprBuilder[V, Boolean, P] =
- withinWindow(Expr.WrapOutput(valueExpr, ExprConverter.asWindow[R](Window.greaterThan(_)), captureWindow))
-
- def >=(
- value: R,
- )(implicit
- orderR: Order[R],
- captureWindow: CaptureP[V, Window[R], P],
- captureConst: CaptureP[FactTable, Window[R], P],
- captureResult: CaptureCondResult,
- ): ValExprBuilder[V, Boolean, P] =
- within(Window.greaterThanOrEqual(value))
-
- def >=(
- valueExpr: Expr[V, R, P],
- )(implicit
- orderR: Order[R],
- captureWindow: CaptureP[V, Window[R], P],
- captureResult: CaptureCondResult,
- ): ValExprBuilder[V, Boolean, P] =
- withinWindow(Expr.WrapOutput(valueExpr, ExprConverter.asWindow[R](Window.greaterThanOrEqual(_)), captureWindow))
-}
diff --git a/core/src/main/scala/vapors/dsl/ExprBuilderCatsInstances.scala b/core/src/main/scala/vapors/dsl/ExprBuilderCatsInstances.scala
deleted file mode 100644
index 18490165d..000000000
--- a/core/src/main/scala/vapors/dsl/ExprBuilderCatsInstances.scala
+++ /dev/null
@@ -1,252 +0,0 @@
-package com.rallyhealth
-
-package vapors.dsl
-
-import cats._
-import cats.data.Ior
-import cats.syntax.all._
-
-import scala.collection.{MapView, View}
-
-trait ExprBuilderCatsInstances {
-
- implicit def monadSet: Monad[Set] = alleycats.std.set.alleyCatsStdSetMonad
-
- implicit def traverseSet: Traverse[Set] = alleycats.std.set.alleyCatsSetTraverse
-
- implicit def traverseFilterSet: TraverseFilter[Set] = alleycats.std.set.alleyCatsSetTraverseFilter
-
- implicit def traverseMap[K]: Traverse[Map[K, *]] = alleycats.std.map.alleycatsStdInstancesForMap
-
- implicit def traverseFilterMap[K]: TraverseFilter[Map[K, *]] = alleycats.std.map.alleycatsStdMapTraverseFilter
-
- implicit def traverseMapView[K]: Traverse[MapView[K, *]] = new Traverse[MapView[K, *]] {
-
- override final def traverse[G[_], A, B](
- fa: MapView[K, A],
- )(
- f: A => G[B],
- )(implicit
- G: Applicative[G],
- ): G[MapView[K, B]] =
- traverseMap.traverse(fa.toMap)(f).map(_.view)
-
- override final def map[A, B](fa: MapView[K, A])(f: A => B): MapView[K, B] = fa.mapValues(f)
-
- override final def foldLeft[A, B](
- fa: MapView[K, A],
- b: B,
- )(
- f: (B, A) => B,
- ): B =
- fa.foldLeft(b) { case (x, (_, a)) => f(x, a) }
-
- override final def foldRight[A, B](
- fa: MapView[K, A],
- lb: Eval[B],
- )(
- f: (A, Eval[B]) => Eval[B],
- ): Eval[B] =
- Foldable.iterateRight(fa.values, lb)(f)
-
- override final def size[A](fa: MapView[K, A]): Long = fa.size.toLong
-
- override final def get[A](fa: MapView[K, A])(idx: Long): Option[A] = {
- if (idx < 0L || Int.MaxValue < idx) None
- else {
- val n = idx.toInt
- if (n >= fa.size) None
- else Some(fa.valuesIterator.drop(n).next())
- }
- }
-
- override final def isEmpty[A](fa: MapView[K, A]): Boolean = fa.isEmpty
-
- override final def fold[A](fa: MapView[K, A])(implicit A: Monoid[A]): A = A.combineAll(fa.values)
-
- override final def toList[A](fa: MapView[K, A]): List[A] = fa.values.toList
-
- override final def collectFirst[A, B](fa: MapView[K, A])(pf: PartialFunction[A, B]): Option[B] =
- fa.collectFirst(new PartialFunction[(K, A), B] {
- override final def isDefinedAt(x: (K, A)): Boolean = pf.isDefinedAt(x._2)
- override final def apply(v1: (K, A)): B = pf(v1._2)
- })
-
- override final def collectFirstSome[A, B](fa: MapView[K, A])(f: A => Option[B]): Option[B] =
- collectFirst(fa)(Function.unlift(f))
- }
-
- implicit def traverseFilterMapView[K]: TraverseFilter[MapView[K, *]] = new TraverseFilter[MapView[K, *]] {
- override final def traverse: Traverse[MapView[K, *]] = traverseMapView
- override final def traverseFilter[G[_], A, B](
- fa: MapView[K, A],
- )(
- f: A => G[Option[B]],
- )(implicit
- G: Applicative[G],
- ): G[MapView[K, B]] = {
- import cats.syntax.functor._
- traverseFilterMap.traverseFilter(fa.toMap)(f).map(_.view)
- }
- }
-
- implicit val vaporsInstancesForView: Traverse[View]
- with TraverseFilter[View]
- with Alternative[View]
- with Monad[View]
- with CoflatMap[View]
- with Align[View] =
- new Traverse[View] with TraverseFilter[View] with Alternative[View] with Monad[View] with CoflatMap[View]
- with Align[View] {
-
- override final def traverse: Traverse[View] = this
-
- override final def empty[A]: View[A] = View.empty
-
- override final def combineK[A](
- x: View[A],
- y: View[A],
- ): View[A] = x ++ y
-
- override final def pure[A](x: A): View[A] = View(x)
-
- override final def map[A, B](fa: View[A])(f: A => B): View[B] =
- fa.map(f)
-
- override final def flatMap[A, B](fa: View[A])(f: A => View[B]): View[B] =
- fa.flatMap(f)
-
- override final def map2[A, B, Z](
- fa: View[A],
- fb: View[B],
- )(
- f: (A, B) => Z,
- ): View[Z] =
- if (fb.isEmpty) View.empty // do O(1) work if fb is empty
- else fa.flatMap(a => fb.map(b => f(a, b))) // already O(1) if fa is empty
-
- override final def map2Eval[A, B, Z](
- fa: View[A],
- fb: Eval[View[B]],
- )(
- f: (A, B) => Z,
- ): Eval[View[Z]] =
- if (fa.isEmpty) Eval.now(View.empty) // no need to evaluate fb
- else fb.map(fb => map2(fa, fb)(f))
-
- override final def coflatMap[A, B](fa: View[A])(f: View[A] => B): View[B] =
- fa.tails.to(View).init.map(f)
-
- override final def foldLeft[A, B](
- fa: View[A],
- b: B,
- )(
- f: (B, A) => B,
- ): B =
- fa.foldLeft(b)(f)
-
- override final def foldRight[A, B](
- fa: View[A],
- lb: Eval[B],
- )(
- f: (A, Eval[B]) => Eval[B],
- ): Eval[B] =
- Now(fa).flatMap { s =>
- // Note that we don't use pattern matching, since that may needlessly force the tail.
- if (s.isEmpty) lb else f(s.head, Eval.defer(foldRight(s.tail, lb)(f)))
- }
-
- override final def foldMap[A, B](fa: View[A])(f: A => B)(implicit B: Monoid[B]): B =
- B.combineAll(fa.iterator.map(f))
-
- override final def traverse[G[_], A, B](fa: View[A])(f: A => G[B])(implicit G: Applicative[G]): G[View[B]] =
- Traverse[LazyList].traverse(fa.to[LazyList[A]](LazyList))(f).map(_.to(View))
-
- override final def mapWithIndex[A, B](fa: View[A])(f: (A, Int) => B): View[B] =
- fa.zipWithIndex.map(ai => f(ai._1, ai._2))
-
- override final def zipWithIndex[A](fa: View[A]): View[(A, Int)] =
- fa.zipWithIndex
-
- override final def tailRecM[A, B](a: A)(fn: A => View[Either[A, B]]): View[B] =
- FlatMap[LazyList]
- .tailRecM(a) {
- fn.andThen(_.to[LazyList[Either[A, B]]](LazyList))
- }
- .to(View)
-
- override final def exists[A](fa: View[A])(p: A => Boolean): Boolean =
- fa.exists(p)
-
- override final def forall[A](fa: View[A])(p: A => Boolean): Boolean =
- fa.forall(p)
-
- override final def get[A](fa: View[A])(idx: Long): Option[A] =
- Traverse[LazyList].get(fa.to[LazyList[A]](LazyList))(idx)
-
- override final def isEmpty[A](fa: View[A]): Boolean = fa.isEmpty
-
- override final def foldM[G[_], A, B](
- fa: View[A],
- z: B,
- )(
- f: (B, A) => G[B],
- )(implicit
- G: Monad[G],
- ): G[B] =
- Traverse[LazyList].foldM(fa.to[LazyList[A]](LazyList), z)(f)
-
- override final def fold[A](fa: View[A])(implicit A: Monoid[A]): A = A.combineAll(fa)
-
- override final def toList[A](fa: View[A]): List[A] = fa.toList
-
- override final def toIterable[A](fa: View[A]): Iterable[A] = fa
-
- override def reduceLeftOption[A](fa: View[A])(f: (A, A) => A): Option[A] =
- fa.reduceLeftOption(f)
-
- override final def find[A](fa: View[A])(f: A => Boolean): Option[A] = fa.find(f)
-
- override final def algebra[A]: Monoid[View[A]] = new Monoid[View[A]] {
- override final def empty: View[A] = View.empty
- override final def combine(
- x: View[A],
- y: View[A],
- ): View[A] = x ++ y
- }
-
- override final def collectFirst[A, B](fa: View[A])(pf: PartialFunction[A, B]): Option[B] = fa.collectFirst(pf)
-
- override final def collectFirstSome[A, B](fa: View[A])(f: A => Option[B]): Option[B] =
- fa.collectFirst(Function.unlift(f))
-
- override final def align[A, B](
- fa: View[A],
- fb: View[B],
- ): View[Ior[A, B]] =
- alignWith(fa, fb)(identity)
-
- override final def alignWith[A, B, C](
- fa: View[A],
- fb: View[B],
- )(
- f: Ior[A, B] => C,
- ): View[C] =
- Align[LazyList].alignWith(fa.to[LazyList[A]](LazyList), fb.to[LazyList[B]](LazyList))(f).to(View)
-
- override final def traverseFilter[G[_], A, B](
- fa: View[A],
- )(
- f: A => G[Option[B]],
- )(implicit
- G: Applicative[G],
- ): G[View[B]] =
- TraverseFilter[LazyList].traverseFilter(fa.to[LazyList[A]](LazyList))(f).map(_.to(View))
-
- override def filterA[G[_], A](fa: View[A])(f: A => G[Boolean])(implicit G: Applicative[G]): G[View[A]] =
- TraverseFilter[LazyList].filterA(fa.to[LazyList[A]](LazyList))(f).map(_.to(View))
-
- override def mapFilter[A, B](fa: View[A])(f: A => Option[B]): View[B] =
- fa.collect(Function.unlift(f))
- }
-}
diff --git a/core/src/main/scala/vapors/dsl/ExprDsl.scala b/core/src/main/scala/vapors/dsl/ExprDsl.scala
deleted file mode 100644
index 9dded77df..000000000
--- a/core/src/main/scala/vapors/dsl/ExprDsl.scala
+++ /dev/null
@@ -1,300 +0,0 @@
-package com.rallyhealth
-
-package vapors.dsl
-
-import vapors.algebra.{CaptureP, Expr, ExprResult}
-import vapors.data._
-import vapors.interpreter.{ExprInput, InterpretExprAsResultFn}
-import vapors.lens.NamedLens
-import vapors.logic.{Conjunction, Disjunction, Negation}
-import vapors.math._
-
-import cats.data.NonEmptyList
-import cats.{Foldable, Monoid}
-
-object ExprDsl extends ExprDsl
-
-// TODO: Remove methods that are not useful anymore and move less-useful methods to a separate object
-trait ExprDsl extends TimeFunctions with WrapExprSyntax with WrapEachExprSyntax {
-
- /**
- * Evaluates the given [[RootExpr]] with the given [[FactTable]] to produce the [[ExprResult]].
- *
- * To access the value of the result, you can get the `result.output.value`. [[Evidence]] for the
- * value can be accessed from `result.output.evidence`. Any parameter captured in [[CaptureP]] is
- * accessible from `result.param`.
- *
- * You can also apply a post-processing [[ExprResult.Visitor]] to analyze the results in more depth
- * in a recursive and type-safe way.
- */
- def eval[R, P](facts: FactTable)(query: RootExpr[R, P]): ExprResult[FactTable, R, P] = {
- InterpretExprAsResultFn(query)(ExprInput.fromFactTable(facts))
- }
-
- /**
- * Creates an embeddable [[RootExpr]] that always returns a given constant value.
- *
- * @see [[Expr.ConstOutput]]
- */
- def const[R, P](
- value: R,
- evidence: Evidence = Evidence.none,
- )(implicit
- capture: CaptureRootExpr[R, P],
- ): Expr.ConstOutput[FactTable, R, P] =
- Expr.ConstOutput(value, evidence, capture)
-
- /**
- * Uses the value of a given fact and also considers the fact as evidence of its own value.
- */
- def factValue[R, P](
- typedFact: TypedFact[R],
- )(implicit
- capture: CaptureRootExpr[R, P],
- ): Expr.ConstOutput[FactTable, R, P] =
- const(typedFact.value, Evidence(typedFact))
-
- /**
- * @note For better type inference, you should consider using [[ExprBuilder.returnInput]]
- *
- * This method may be deprecated in the future.
- *
- * @see [[Expr.ReturnInput]]
- */
- def input[V, P](
- implicit
- capture: CaptureP[V, V, P],
- ): Expr.ReturnInput[V, P] =
- Expr.ReturnInput(capture)
-
- /**
- * Start the creation of an [[Expr.Define]] for a [[FactType]].
- */
- def define[T](factType: FactType[T]): DefinitionExprBuilder[T] = new DefinitionExprBuilder(factType)
-
- /**
- * Apply the given definitions to add the produced [[Fact]]s to the [[FactTable]] for the life of the
- * given `subExpr`.
- *
- * @param definitions a set of [[Expr.Definition]]s that will all be concatenated to the [[FactTable]]
- * @param subExpr an expression that will see the defined [[Fact]]s in its [[FactTable]]
- */
- def usingDefinitions[V, R, P](
- definitions: Expr.Definition[P]*,
- )(
- subExpr: Expr[V, R, P],
- )(implicit
- captureResult: CaptureP[V, R, P],
- ): Expr.UsingDefinitions[V, R, P] =
- Expr.UsingDefinitions(definitions.toVector, subExpr, captureResult)
-
- /**
- * Typically, this function will be applied implicitly by the DSL. If it doesn't you may have to explicitly
- * choose the type to embed. For better type inference, you should use [[ExprBuilder.embedConst]].
- *
- * This method may be deprecated in the future.
- *
- * @see [[Expr.ConstOutput]]
- */
- def embed[V, R, P](
- expr: RootExpr[R, P],
- )(implicit
- captureResult: CaptureP[V, R, P],
- ): Expr.Embed[V, R, P] =
- Expr.Embed(expr, captureResult)
-
- /**
- * Concatenates the outputs of the expressions given.
- */
- def concat[V, M[_], R, P](expressions: Expr[V, M[R], P]*): ConcatOutputExprBuilder[V, M, R, P] =
- new ConcatOutputExprBuilder(expressions.to(LazyList))
-
- /**
- * @see [[Expr.And]] for more details of how [[Conjunction]] works during evaluation.
- */
- def and[V, R : Conjunction : ExtractBoolean, P](
- first: Expr[V, R, P],
- second: Expr[V, R, P],
- remaining: Expr[V, R, P]*,
- )(implicit
- captureResult: CaptureP[V, R, P],
- ): Expr.And[V, R, P] = {
- val subExpressions = first :: NonEmptyList.of(second, remaining: _*)
- Expr.And(subExpressions, captureResult)
- }
-
- /**
- * @see [[Expr.Or]] for more details of how [[Disjunction]] works during evaluation.
- */
- def or[V, R : Disjunction : ExtractBoolean, P](
- first: Expr[V, R, P],
- second: Expr[V, R, P],
- remaining: Expr[V, R, P]*,
- )(implicit
- captureResult: CaptureP[V, R, P],
- ): Expr.Or[V, R, P] = {
- val subExpressions = first :: NonEmptyList.of(second, remaining: _*)
- Expr.Or(subExpressions, captureResult)
- }
-
- /**
- * @see [[Expr.Not]] for more details of how [[Negation]] works during evaluation.
- */
- def not[V, R : Negation, P](
- sub: Expr[V, R, P],
- )(implicit
- captureResult: CaptureP[V, R, P],
- ): Expr.Not[V, R, P] =
- Expr.Not(sub, captureResult)
-
- /**
- * Builds an if / then / elif / else style conditional branching expression.
- */
- def when[V, R, P](condExpr: CondExpr[V, P]): WhenExprBuilder[V, P] = new WhenExprBuilder(condExpr)
-
- /**
- * Grabs all facts of a given set of types and returns them in order of fact type alphabetically,
- * then by their natural ordering (as defined on the [[FactType]]).
- */
- def factsOfType[T, P](
- factTypeSet: FactTypeSet[T],
- )(implicit
- captureInput: CaptureFromFacts[T, P],
- captureAllResults: CaptureRootExpr[Seq[TypedFact[T]], P],
- ): FoldableExprBuilder[FactTable, Seq, TypedFact[T], P] =
- new FoldableExprBuilder(
- Expr.WithFactsOfType[T, Seq[TypedFact[T]], P](
- factTypeSet,
- input(captureInput),
- captureAllResults,
- ),
- )
-
- /**
- * Same as [[factsOfType]], but maps the facts into their values.
- */
- def valuesOfType[T, P](
- factTypeSet: FactTypeSet[T],
- )(implicit
- captureInput: CaptureFromFacts[T, P],
- captureAllFacts: CaptureRootExpr[Seq[TypedFact[T]], P],
- captureEachResult: CaptureP[TypedFact[T], T, P],
- captureEachInput: CaptureP[TypedFact[T], TypedFact[T], P],
- captureAllResults: CaptureP[FactTable, Seq[T], P],
- ): FoldableExprBuilder[FactTable, Seq, T, P] =
- factsOfType(factTypeSet).map(_.value)
-
- /**
- * Takes a sequence of expressions and produces an expression of sequence of all the items.
- *
- * @see [[wrapSeq]] for varargs syntactic sugar.
- *
- * If you would like to put the results into a heterogeneous sequence, then you should use the [[wrap]] method.
- */
- def sequence[V, R, P](
- expressions: Seq[Expr[V, R, P]],
- )(implicit
- captureResult: CaptureP[V, Seq[R], P],
- ): Expr.WrapOutputSeq[V, R, P] = Expr.WrapOutputSeq(expressions, captureResult)
-
- /**
- * Syntactic sugar for [[sequence]].
- *
- * You should use this method over [[sequence]] when you are writing your expression in the embedded DSL.
- * If you are abstracting over a sequence of expressions, then you should use [[sequence]].
- */
- @inline final def wrapSeq[V, R, P](
- expressions: Expr[V, R, P]*,
- )(implicit
- captureResult: CaptureP[V, Seq[R], P],
- ): Expr.WrapOutputSeq[V, R, P] = sequence(expressions)
-
- /*
- * The following DSL functions will probably be deprecated in favor of their ExprBuilder equivalents
- */
-
- def collectSome[V, M[_] : Foldable, U, R : Monoid, P](
- inputExpr: Expr[V, M[U], P],
- collectExpr: ValExpr[U, Option[R], P],
- )(implicit
- capture: CaptureP[V, R, P],
- ): Expr.CollectFromOutput[V, M, U, R, P] =
- Expr.CollectFromOutput(inputExpr, collectExpr, capture)
-
- def selectFrom[V, S, R, P](
- inputExpr: Expr[V, S, P],
- lens: NamedLens[S, R],
- )(implicit
- captureInput: CaptureP[V, R, P],
- ): Expr.SelectFromOutput[V, S, R, P] =
- Expr.SelectFromOutput(inputExpr, lens, captureInput)
-
- def add[V, R : Addition, P](
- lhs: Expr[V, R, P],
- rhs: Expr[V, R, P],
- )(implicit
- capture: CaptureP[V, R, P],
- ): Expr.AddOutputs[V, R, P] =
- Expr.AddOutputs(NonEmptyList.of(lhs, rhs), capture)
-
- def multiply[V, R : Multiplication, P](
- lhs: Expr[V, R, P],
- rhs: Expr[V, R, P],
- )(implicit
- capture: CaptureP[V, R, P],
- ): Expr.MultiplyOutputs[V, R, P] =
- Expr.MultiplyOutputs(NonEmptyList.of(lhs, rhs), capture)
-
- def subtract[V, R : Subtraction, P](
- lhs: Expr[V, R, P],
- rhs: Expr[V, R, P],
- )(implicit
- capture: CaptureP[V, R, P],
- ): Expr.SubtractOutputs[V, R, P] =
- Expr.SubtractOutputs(NonEmptyList.of(lhs, rhs), capture)
-
- def divide[V, R : Division, P](
- lhs: Expr[V, R, P],
- rhs: Expr[V, R, P],
- )(implicit
- capture: CaptureP[V, R, P],
- ): Expr.DivideOutputs[V, R, P] =
- Expr.DivideOutputs(NonEmptyList.of(lhs, rhs), capture)
-
- def pow[V, P](
- base: Expr[V, Double, P],
- exp: Expr[V, Double, P],
- )(implicit
- capture: CaptureP[V, Double, P],
- ): Expr.ExponentiateOutputs[V, P] =
- Expr.ExponentiateOutputs(base, exp, capture)
-
- def negative[V, R : Negative, P](
- inputExpr: Expr[V, R, P],
- )(implicit
- capture: CaptureP[V, R, P],
- ): Expr.NegativeOutput[V, R, P] =
- Expr.NegativeOutput(inputExpr, capture)
-
- def exists[V, M[_] : Foldable, U, P](
- inputExpr: Expr[V, M[U], P],
- condExpr: ValCondExpr[U, P],
- )(implicit
- capture: CaptureP[V, Boolean, P],
- ): Expr.ExistsInOutput[V, M, U, P] =
- Expr.ExistsInOutput(inputExpr, condExpr, capture)
-
- def returnInput[V, P](
- implicit
- capture: CaptureP[V, V, P],
- ): Expr.ReturnInput[V, P] =
- Expr.ReturnInput(capture)
-
- def within[V, R, P](
- inputExpr: Expr[V, R, P],
- windowExpr: Expr[V, Window[R], P],
- )(implicit
- capture: CaptureP[V, Boolean, P],
- ): Expr.OutputWithinWindow[V, R, P] =
- Expr.OutputWithinWindow(inputExpr, windowExpr, capture)
-}
diff --git a/core/src/main/scala/vapors/dsl/HListOperationWrapper.scala b/core/src/main/scala/vapors/dsl/HListOperationWrapper.scala
deleted file mode 100644
index a5d1a53da..000000000
--- a/core/src/main/scala/vapors/dsl/HListOperationWrapper.scala
+++ /dev/null
@@ -1,50 +0,0 @@
-package com.rallyhealth
-
-package vapors.dsl
-
-import vapors.algebra.{CaptureP, Expr, ExprConverter, NonEmptyExprHList}
-
-import shapeless.ops.hlist.Tupler
-import shapeless.{Generic, HList}
-
-trait HListOperationWrapper[V, M[_], L <: HList, P] extends Any {
-
- type Op[R] <: Expr[V, M[R], P]
-
- protected def exprHList: NonEmptyExprHList[V, M, L, P]
-
- protected def buildOp[R](
- converter: ExprConverter[L, R],
- captureResult: CaptureP[V, M[R], P],
- ): Op[R]
-
- final def asTuple[T](
- implicit
- tupler: Tupler.Aux[L, T],
- captureResult: CaptureP[V, M[T], P],
- ): Op[T] =
- buildOp(
- ExprConverter.asTuple,
- captureResult,
- )
-
- final def asHList(
- implicit
- captureResult: CaptureP[V, M[L], P],
- ): Op[L] =
- buildOp(
- ExprConverter.asHListIdentity,
- captureResult,
- )
-
- final def as[R](
- implicit
- gen: Generic.Aux[R, L],
- captureResult: CaptureP[V, M[R], P],
- ): Op[R] =
- buildOp(
- ExprConverter.asProductType,
- captureResult,
- )
-
-}
diff --git a/core/src/main/scala/vapors/dsl/MapViewExprBuilder.scala b/core/src/main/scala/vapors/dsl/MapViewExprBuilder.scala
deleted file mode 100644
index 90b27842f..000000000
--- a/core/src/main/scala/vapors/dsl/MapViewExprBuilder.scala
+++ /dev/null
@@ -1,91 +0,0 @@
-package com.rallyhealth
-
-package vapors.dsl
-
-import vapors.algebra.{CaptureP, Expr}
-import vapors.lens.{DataPath, NamedLens}
-
-import cats.Id
-import shapeless.Nat
-
-import scala.collection.{MapView, View}
-
-final class MapViewExprBuilder[V, K, U, P](private val inputExpr: Expr[V, MapView[K, U], P]) extends AnyVal {
-
- /**
- * Apply the given expression over every value of the Map, without affecting the keys.
- *
- * TODO: The signature of this method is difficult to work with because the definition of the
- * [[FoldableExprBuilder.groupBy]] method means every value is foldable. However, this
- * method assumes gives you a [[ValExprBuilder]] which is almost never helpful.
- */
- def mapValues[R](
- buildExpr: ValExprBuilder[(K, U), U, P] => ExprBuilder[(K, U), Id, R, P],
- )(implicit
- captureView: CaptureP[V, View[(K, U)], P],
- captureEachTuple: CaptureP[(K, U), (K, U), P],
- captureEachTupleKey: CaptureP[(K, U), K, P],
- captureEachTupleValue: CaptureP[(K, U), U, P],
- captureEachResultTuple: CaptureP[(K, U), (K, R), P],
- captureViewResult: CaptureP[V, View[(K, R)], P],
- captureMapViewResult: CaptureP[V, MapView[K, R], P],
- ): MapViewExprBuilder[V, K, R, P] =
- MapViewExprBuilder
- .asFoldableBuilder(this)
- .map { kv =>
- val selectKeyFromTuple = kv.get(_.copy(path = DataPath.empty.atKey(Nat._1), get = _._1))
- val selectValueFromTuple = kv.get(_.copy(path = DataPath.empty.atKey(Nat._2), get = _._2))
- val mappedValue = buildExpr(new ValExprBuilder(selectValueFromTuple))
- wrap(
- selectKeyFromTuple.returnOutput,
- mappedValue.returnOutput,
- ).asTuple[(K, R)]
- }
- .toMap
-
- /**
- * Returns every entry of the returned Map as a lazy sequential [[View]] of 2-tuples.
- */
- def values(
- implicit
- captureView: CaptureP[V, View[(K, U)], P],
- captureEachTuple: CaptureP[(K, U), (K, U), P],
- captureEachTupleValue: CaptureP[(K, U), U, P],
- captureResult: CaptureP[V, View[U], P],
- ): FoldableExprBuilder[V, View, U, P] = {
- new FoldableExprBuilder(
- Expr.MapOutput(
- Expr.SelectFromOutput(
- inputExpr,
- NamedLens.id[MapView[K, U]].asIterable.to(View),
- captureView,
- ),
- Expr.SelectFromOutput(
- Expr.ReturnInput(captureEachTuple),
- NamedLens[(K, U), U](DataPath.empty.atKey(Nat._2), _._2),
- captureEachTupleValue,
- ),
- captureResult,
- ),
- )
- }
-}
-
-object MapViewExprBuilder {
-
- implicit def asExpr[V, K, U, P](builder: MapViewExprBuilder[V, K, U, P]): Expr[V, MapView[K, U], P] =
- builder.inputExpr
-
- implicit def asFoldableBuilder[V, K, U, P](
- builder: MapViewExprBuilder[V, K, U, P],
- )(implicit
- captureView: CaptureP[V, View[(K, U)], P],
- ): FoldableExprBuilder[V, View, (K, U), P] =
- new FoldableExprBuilder(
- Expr.SelectFromOutput(
- builder.inputExpr,
- NamedLens.id[MapView[K, U]].asIterable.to(View),
- captureView,
- ),
- )
-}
diff --git a/core/src/main/scala/vapors/dsl/TimeFunctions.scala b/core/src/main/scala/vapors/dsl/TimeFunctions.scala
deleted file mode 100644
index 251cd7233..000000000
--- a/core/src/main/scala/vapors/dsl/TimeFunctions.scala
+++ /dev/null
@@ -1,132 +0,0 @@
-package com.rallyhealth
-
-package vapors.dsl
-
-import vapors.algebra.{CaptureP, Expr}
-import vapors.data.FactTable
-import vapors.time.{CountTime, ModifyTime}
-
-import shapeless._
-
-import java.time.{Clock, Instant, LocalDate}
-
-/**
- * Provides common functions work working with time.
- *
- * This works by providing an escape hatch for evaluating a custom Scala function (rather than building
- * all the operations out of [[Expr]] nodes).
- *
- * @see [[Expr.CustomFunction]]
- */
-trait TimeFunctions {
-
- /**
- * Adds the result of the `rhs` temporal amount expression to the result of the `lhs` temporal expression.
- *
- * Requires a definition of [[ModifyTime]] for the two types. This is a safer API than working directly with
- * Java's Time library because it forbids adding [[java.time.Duration]]s to a [[LocalDate]] or adding a
- * [[java.time.Period]] to an [[Instant]]. Java Time will just throw an exception if the types are incompatible.
- *
- * @param lhsExpr an expression that computes a date and / or time
- * @param rhsExpr an expression that produces the duration of time to add (can be negative)
- *
- */
- // TODO: Can this be converted to Addition[T] if we make the second argument a different type? Maybe AddLeft[T, D]?
- final def dateAdd[V, T, D, P](
- lhsExpr: Expr[V, T, P],
- rhsExpr: Expr[V, D, P],
- )(implicit
- modTime: ModifyTime[T, D],
- argTypeInfo: Typeable[T :: D :: HNil],
- captureArgResult: CaptureP[V, T :: D :: HNil, P],
- captureResult: CaptureP[V, T, P],
- ): Expr[V, T, P] = {
- val argExpr = wrap(lhsExpr, rhsExpr).asHList.returnOutput
- val fn: T :: D :: HNil => T = {
- case lhs :: rhs :: HNil =>
- ModifyTime.addTo(lhs, rhs)
- }
- Expr.CustomFunction(argExpr, "date_add", fn, captureResult)
- }
-
- /**
- * Computes the difference between the `lhsExpr` and the `rhsExpr` as an integral value of the given unit
- * (can be negative). The result will be rounded down to the maximum number of whole units between the two
- * temporal instances that can be counted.
- *
- * This requires an instance of [[CountTime]] to make sure that the given unit type is safe to count for
- * the given temporal types. This is a safer API than working directly with Java's Time library because it
- * forbids subtracting two different temporal types from each other, without first converting them appropriately.
- * Java Time will just throw an exception if the types are incompatible.
- *
- * @param lhsExpr an expression that computes the temporal instant of when to start counting
- * @param rhsExpr an expression that computes the temporal instant of when to stop counting
- * (either counting units of time in the past or future from lhsExpr)
- * @param roundToUnitExpr the type of unit to round down to
- */
- final def dateDiff[V, T, U, P](
- lhsExpr: Expr[V, T, P],
- rhsExpr: Expr[V, T, P],
- roundToUnitExpr: Expr[V, U, P],
- )(implicit
- countTime: CountTime[T, U],
- argTypeInfo: Typeable[T :: T :: U :: HNil],
- captureArgResult: CaptureP[V, T :: T :: U :: HNil, P],
- captureResult: CaptureP[V, Long, P],
- ): Expr[V, Long, P] = {
- val argExpr = wrap(lhsExpr, rhsExpr, roundToUnitExpr).asHList.returnOutput
- val fn: T :: T :: U :: HNil => Long = {
- case lhs :: rhs :: unit :: HNil =>
- CountTime.between(lhs, rhs, unit)
- }
- Expr.CustomFunction(argExpr, "date_diff", fn, captureResult)
- }
-
- /**
- * Returns an expression that computes the current [[LocalDate]] when it is invoke, using the system
- * [[Clock]] with the default timezone information of host machine / JVM.
- */
- final def today[V, P](
- implicit
- captureClock: CaptureP[FactTable, Clock, P],
- captureEmbed: CaptureP[V, Clock, P],
- captureResult: CaptureP[V, LocalDate, P],
- ): Expr[V, LocalDate, P] =
- today(Clock.systemDefaultZone())
-
- /**
- * Returns an expression that computes the current [[LocalDate]] when it is invoked, based on the given [[Clock]].
- */
- final def today[V, P](
- clock: Clock,
- )(implicit
- captureClock: CaptureP[FactTable, Clock, P],
- captureEmbed: CaptureP[V, Clock, P],
- captureResult: CaptureP[V, LocalDate, P],
- ): Expr[V, LocalDate, P] =
- Expr.CustomFunction[V, Clock, LocalDate, P](embed(const(clock)), "today", LocalDate.now, captureResult)
-
- /**
- * Returns an expression that computes the current [[Instant]] when it is invoked, using the UTC [[Clock]].
- */
- final def now[V, P](
- implicit
- captureClock: CaptureP[FactTable, Clock, P],
- captureEmbed: CaptureP[V, Clock, P],
- captureResult: CaptureP[V, Instant, P],
- ): Expr[V, Instant, P] =
- now(Clock.systemUTC())
-
- /**
- * Returns an expression that computes the current [[Instant]] when it is invoked, based on the given [[Clock]].
- */
- final def now[V, P](
- clock: Clock,
- )(implicit
- captureClock: CaptureP[FactTable, Clock, P],
- captureEmbed: CaptureP[V, Clock, P],
- captureResult: CaptureP[V, Instant, P],
- ): Expr[V, Instant, P] =
- Expr.CustomFunction[V, Clock, Instant, P](embed(const(clock)), "now", Instant.now, captureResult)
-
-}
diff --git a/core/src/main/scala/vapors/dsl/WhenExprBuilder.scala b/core/src/main/scala/vapors/dsl/WhenExprBuilder.scala
deleted file mode 100644
index 1452870a9..000000000
--- a/core/src/main/scala/vapors/dsl/WhenExprBuilder.scala
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.rallyhealth
-
-package vapors.dsl
-
-import vapors.algebra.{CaptureP, ConditionBranch, Expr}
-
-import cats.data.NonEmptyList
-
-final class WhenExprBuilder[V, P](private val whenExpr: CondExpr[V, P]) extends AnyVal {
-
- def thenReturn[R](thenExpr: Expr[V, R, P]): WhenElseExprBuilder[V, R, P] =
- new WhenElseExprBuilder(NonEmptyList.of(ConditionBranch(whenExpr, thenExpr)))
-}
-
-final class WhenElifExprBuilder[V, R, P](private val t: (CondExpr[V, P], NonEmptyList[ConditionBranch[V, R, P]]))
- extends AnyVal {
-
- def thenReturn(thenExpr: Expr[V, R, P]): WhenElseExprBuilder[V, R, P] =
- new WhenElseExprBuilder(ConditionBranch(t._1, thenExpr) :: t._2)
-}
-
-final class WhenElseExprBuilder[V, R, P](private val branches: NonEmptyList[ConditionBranch[V, R, P]]) extends AnyVal {
-
- def elseReturn(
- elseExpr: Expr[V, R, P],
- )(implicit
- captureResult: CaptureP[V, R, P],
- ): Expr.When[V, R, P] =
- Expr.When(branches.reverse, elseExpr, captureResult)
-
- def elif(elifExpr: CondExpr[V, P]): WhenElifExprBuilder[V, R, P] = new WhenElifExprBuilder((elifExpr, branches))
-}
diff --git a/core/src/main/scala/vapors/dsl/WithFactsOfTypeBuilder.scala b/core/src/main/scala/vapors/dsl/WithFactsOfTypeBuilder.scala
deleted file mode 100644
index 93841e4b6..000000000
--- a/core/src/main/scala/vapors/dsl/WithFactsOfTypeBuilder.scala
+++ /dev/null
@@ -1,37 +0,0 @@
-package com.rallyhealth
-
-package vapors.dsl
-
-import vapors.algebra.{CaptureP, Expr}
-import vapors.data.{FactTypeSet, TypedFact}
-
-/**
- * @note this is not a value class because the input [[FactTypeSet]] is also a value class AND the [[CaptureP]]
- * implicit is needed in the original [[withFactsOfType]] method in order for type inference to work properly.
- * We could ask for the implicit again, but that is confusing for the caller who would have to look at the
- * source code to know which instance is actually used.
- */
-final class WithFactsOfTypeBuilder[T, P](
- factTypeSet: FactTypeSet[T],
-)(implicit
- captureInput: CaptureFromFacts[T, P],
-) {
-
- def where[M[_], U](
- buildSubExpr: ExprBuilder.FoldableFn[Seq, TypedFact[T], M, U, P],
- )(implicit
- captureResult: CaptureRootExpr[M[U], P],
- ): Expr.WithFactsOfType[T, M[U], P] =
- Expr.WithFactsOfType(
- factTypeSet,
- buildSubExpr(new FoldableExprBuilder(input)).returnOutput,
- captureResult,
- )
-
- def returnInput(
- implicit
- captureInput: CaptureFromFacts[T, P],
- captureResult: CaptureRootExpr[Seq[TypedFact[T]], P],
- ): Expr.WithFactsOfType[T, Seq[TypedFact[T]], P] =
- Expr.WithFactsOfType(factTypeSet, input(captureInput), captureResult)
-}
diff --git a/core/src/main/scala/vapors/dsl/WithOutputSyntax.scala b/core/src/main/scala/vapors/dsl/WithOutputSyntax.scala
deleted file mode 100644
index 667d201ef..000000000
--- a/core/src/main/scala/vapors/dsl/WithOutputSyntax.scala
+++ /dev/null
@@ -1,38 +0,0 @@
-package com.rallyhealth
-
-package vapors.dsl
-
-import vapors.algebra.Expr
-
-import cats.Foldable
-
-trait WithOutputSyntax {
-
- implicit def thenChainValue[V, R, P](expr: Expr[V, R, P]): WithOutputValueExprBuilder[V, R, P] =
- new WithOutputValueExprBuilder(expr)
-
- implicit def thenChainFoldable[V, M[_], R, P](expr: Expr[V, M[R], P]): WithOutputFoldableExprBuilder[V, M, R, P] =
- new WithOutputFoldableExprBuilder(expr)
-
-}
-
-// TODO: These classes would not be needed if everything returned builders
-final class WithOutputValueExprBuilder[V, R, P](private val expr: Expr[V, R, P]) extends AnyVal {
-
- /**
- * Converts any [[Expr]] node into a [[ValExprBuilder]].
- */
- def withOutputValue: ValExprBuilder[V, R, P] = new ValExprBuilder(expr)
-}
-
-final class WithOutputFoldableExprBuilder[V, M[_], R, P](private val expr: Expr[V, M[R], P]) extends AnyVal {
-
- /**
- * Converts any [[Expr]] for which there is a [[Foldable]] definition for the return type constructor
- * into a [[FoldableExprBuilder]].
- */
- def withOutputFoldable(
- implicit
- foldableM: Foldable[M],
- ): FoldableExprBuilder[V, M, R, P] = new FoldableExprBuilder(expr)
-}
diff --git a/core/src/main/scala/vapors/dsl/WrapEachExprSyntax.scala b/core/src/main/scala/vapors/dsl/WrapEachExprSyntax.scala
deleted file mode 100644
index 0135937cf..000000000
--- a/core/src/main/scala/vapors/dsl/WrapEachExprSyntax.scala
+++ /dev/null
@@ -1,172 +0,0 @@
-package com.rallyhealth
-
-package vapors.dsl
-
-import vapors.algebra.{CaptureP, Expr, ExprConverter, NonEmptyExprHList}
-
-import cats.{Align, FunctorFilter}
-import shapeless.{::, HList, HNil}
-
-/**
- * Provides the ability to wrap expressions with the same input and captured parameter but different outputs,
- * and then transform this [[HList]] of expressions into an [[Expr]] of a higher-kinded wrapper around an
- * [[HList]] return type.
- *
- * @see similar to [[WrapExprSyntax]] accept this operates over a type-constructor to allow performing additional
- * capabilities to the returned value.
- */
-trait WrapEachExprSyntax {
-
- def wrapEach[V, M[_], E1, E2, P](
- e1: Expr[V, M[E1], P],
- e2: Expr[V, M[E2], P],
- ): WrapEachExprHListWrapper[V, M, E1 :: E2 :: HNil, P] =
- new WrapEachExprHListWrapper(e1 :: NonEmptyExprHList.tailK(e2))
-
- def wrapEach[V, M[_], E1, E2, E3, P](
- e1: Expr[V, M[E1], P],
- e2: Expr[V, M[E2], P],
- e3: Expr[V, M[E3], P],
- ): WrapEachExprHListWrapper[V, M, E1 :: E2 :: E3 :: HNil, P] =
- new WrapEachExprHListWrapper(e1 :: e2 :: NonEmptyExprHList.tailK(e3))
-
- def wrapEach[V, M[_], E1, E2, E3, E4, P](
- e1: Expr[V, M[E1], P],
- e2: Expr[V, M[E2], P],
- e3: Expr[V, M[E3], P],
- e4: Expr[V, M[E4], P],
- ): WrapEachExprHListWrapper[V, M, E1 :: E2 :: E3 :: E4 :: HNil, P] =
- new WrapEachExprHListWrapper(e1 :: e2 :: e3 :: NonEmptyExprHList.tailK(e4))
-
- def wrapEach[V, M[_], E1, E2, E3, E4, E5, P](
- e1: Expr[V, M[E1], P],
- e2: Expr[V, M[E2], P],
- e3: Expr[V, M[E3], P],
- e4: Expr[V, M[E4], P],
- e5: Expr[V, M[E5], P],
- ): WrapEachExprHListWrapper[V, M, E1 :: E2 :: E3 :: E4 :: E5 :: HNil, P] =
- new WrapEachExprHListWrapper(e1 :: e2 :: e3 :: e4 :: NonEmptyExprHList.tailK(e5))
-
- def wrapEach[V, M[_], E1, E2, E3, E4, E5, E6, P](
- e1: Expr[V, M[E1], P],
- e2: Expr[V, M[E2], P],
- e3: Expr[V, M[E3], P],
- e4: Expr[V, M[E4], P],
- e5: Expr[V, M[E5], P],
- e6: Expr[V, M[E6], P],
- ): WrapEachExprHListWrapper[V, M, E1 :: E2 :: E3 :: E4 :: E5 :: E6 :: HNil, P] =
- new WrapEachExprHListWrapper(e1 :: e2 :: e3 :: e4 :: e5 :: NonEmptyExprHList.tailK(e6))
-
- def wrapEach[V, M[_], E1, E2, E3, E4, E5, E6, E7, P](
- e1: Expr[V, M[E1], P],
- e2: Expr[V, M[E2], P],
- e3: Expr[V, M[E3], P],
- e4: Expr[V, M[E4], P],
- e5: Expr[V, M[E5], P],
- e6: Expr[V, M[E6], P],
- e7: Expr[V, M[E7], P],
- ): WrapEachExprHListWrapper[V, M, E1 :: E2 :: E3 :: E4 :: E5 :: E6 :: E7 :: HNil, P] =
- new WrapEachExprHListWrapper(e1 :: e2 :: e3 :: e4 :: e5 :: e6 :: NonEmptyExprHList.tailK(e7))
-
- def wrapEach[V, M[_], E1, E2, E3, E4, E5, E6, E7, E8, P](
- e1: Expr[V, M[E1], P],
- e2: Expr[V, M[E2], P],
- e3: Expr[V, M[E3], P],
- e4: Expr[V, M[E4], P],
- e5: Expr[V, M[E5], P],
- e6: Expr[V, M[E6], P],
- e7: Expr[V, M[E7], P],
- e8: Expr[V, M[E8], P],
- ): WrapEachExprHListWrapper[V, M, E1 :: E2 :: E3 :: E4 :: E5 :: E6 :: E7 :: E8 :: HNil, P] =
- new WrapEachExprHListWrapper(e1 :: e2 :: e3 :: e4 :: e5 :: e6 :: e7 :: NonEmptyExprHList.tailK(e8))
-
- def wrapEach[V, M[_], E1, E2, E3, E4, E5, E6, E7, E8, E9, P](
- e1: Expr[V, M[E1], P],
- e2: Expr[V, M[E2], P],
- e3: Expr[V, M[E3], P],
- e4: Expr[V, M[E4], P],
- e5: Expr[V, M[E5], P],
- e6: Expr[V, M[E6], P],
- e7: Expr[V, M[E7], P],
- e8: Expr[V, M[E8], P],
- e9: Expr[V, M[E9], P],
- ): WrapEachExprHListWrapper[V, M, E1 :: E2 :: E3 :: E4 :: E5 :: E6 :: E7 :: E8 :: E9 :: HNil, P] =
- new WrapEachExprHListWrapper(e1 :: e2 :: e3 :: e4 :: e5 :: e6 :: e7 :: e8 :: NonEmptyExprHList.tailK(e9))
-
- def wrapEach[V, M[_], E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, P](
- e1: Expr[V, M[E1], P],
- e2: Expr[V, M[E2], P],
- e3: Expr[V, M[E3], P],
- e4: Expr[V, M[E4], P],
- e5: Expr[V, M[E5], P],
- e6: Expr[V, M[E6], P],
- e7: Expr[V, M[E7], P],
- e8: Expr[V, M[E8], P],
- e9: Expr[V, M[E9], P],
- e10: Expr[V, M[E10], P],
- ): WrapEachExprHListWrapper[V, M, E1 :: E2 :: E3 :: E4 :: E5 :: E6 :: E7 :: E8 :: E9 :: E10 :: HNil, P] =
- new WrapEachExprHListWrapper(e1 :: e2 :: e3 :: e4 :: e5 :: e6 :: e7 :: e8 :: e9 :: NonEmptyExprHList.tailK(e10))
-
- def wrapEach[V, M[_], E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, P](
- e1: Expr[V, M[E1], P],
- e2: Expr[V, M[E2], P],
- e3: Expr[V, M[E3], P],
- e4: Expr[V, M[E4], P],
- e5: Expr[V, M[E5], P],
- e6: Expr[V, M[E6], P],
- e7: Expr[V, M[E7], P],
- e8: Expr[V, M[E8], P],
- e9: Expr[V, M[E9], P],
- e10: Expr[V, M[E10], P],
- e11: Expr[V, M[E11], P],
- ): WrapEachExprHListWrapper[V, M, E1 :: E2 :: E3 :: E4 :: E5 :: E6 :: E7 :: E8 :: E9 :: E10 :: E11 :: HNil, P] =
- new WrapEachExprHListWrapper(
- e1 :: e2 :: e3 :: e4 :: e5 :: e6 :: e7 :: e8 :: e9 :: e10 :: NonEmptyExprHList.tailK(e11),
- )
-
- def wrapEach[V, M[_], E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, P](
- e1: Expr[V, M[E1], P],
- e2: Expr[V, M[E2], P],
- e3: Expr[V, M[E3], P],
- e4: Expr[V, M[E4], P],
- e5: Expr[V, M[E5], P],
- e6: Expr[V, M[E6], P],
- e7: Expr[V, M[E7], P],
- e8: Expr[V, M[E8], P],
- e9: Expr[V, M[E9], P],
- e10: Expr[V, M[E10], P],
- e11: Expr[V, M[E11], P],
- e12: Expr[V, M[E12], P],
- ): WrapEachExprHListWrapper[
- V,
- M,
- E1 :: E2 :: E3 :: E4 :: E5 :: E6 :: E7 :: E8 :: E9 :: E10 :: E11 :: E12 :: HNil,
- P,
- ] =
- new WrapEachExprHListWrapper(
- e1 :: e2 :: e3 :: e4 :: e5 :: e6 :: e7 :: e8 :: e9 :: e10 :: e11 :: NonEmptyExprHList.tailK(e12),
- )
-}
-
-final class WrapEachExprHListWrapper[V, M[_], L <: HList, P](private val exprHList: NonEmptyExprHList[V, M, L, P])
- extends AnyVal {
-
- def zippedToShortest(
- implicit
- alignM: Align[M],
- filterM: FunctorFilter[M],
- ): ZippedToShortestExprWrapper[V, M, L, P] = new ZippedToShortestExprWrapper(exprHList)
-}
-
-final class ZippedToShortestExprWrapper[V, M[_] : Align : FunctorFilter, L <: HList, P](
- override protected val exprHList: NonEmptyExprHList[V, M, L, P],
-) extends HListOperationWrapper[V, M, L, P] {
-
- override type Op[R] = Expr.ZipOutput[V, M, L, R, P]
-
- override protected def buildOp[R](
- converter: ExprConverter[L, R],
- captureResult: CaptureP[V, M[R], P],
- ): Expr.ZipOutput[V, M, L, R, P] =
- Expr.ZipOutput(exprHList, converter, captureResult)
-}
diff --git a/core/src/main/scala/vapors/dsl/WrapExprSyntax.scala b/core/src/main/scala/vapors/dsl/WrapExprSyntax.scala
deleted file mode 100644
index 784d9df62..000000000
--- a/core/src/main/scala/vapors/dsl/WrapExprSyntax.scala
+++ /dev/null
@@ -1,168 +0,0 @@
-package com.rallyhealth
-
-package vapors.dsl
-
-import vapors.algebra.{CaptureP, Expr, ExprConverter, NonEmptyExprHList}
-
-import cats.Id
-import shapeless.{::, Generic, HList, HNil}
-
-/**
- * Provides the ability to wrap expressions with the same input and captured parameter but different outputs,
- * and then transform this [[HList]] of expressions into an [[Expr]] of an [[HList]] return type.
- *
- * @see similar to [[WrapEachExprSyntax]] except it does not require a shared higher-kinded type constructor
- * for the output value.
- */
-trait WrapExprSyntax {
-
- def wrap[V, E1, P](e1: Expr[V, E1, P]): ExprHListWrapper[V, E1 :: HNil, P] =
- new ExprHListWrapper(NonEmptyExprHList.tail(e1))
-
- def wrap[V, E1, E2, P](
- e1: Expr[V, E1, P],
- e2: Expr[V, E2, P],
- ): ExprHListWrapper[V, E1 :: E2 :: HNil, P] =
- new ExprHListWrapper(e1 :: NonEmptyExprHList.tail(e2))
-
- def wrap[V, E1, E2, E3, P](
- e1: Expr[V, E1, P],
- e2: Expr[V, E2, P],
- e3: Expr[V, E3, P],
- ): ExprHListWrapper[V, E1 :: E2 :: E3 :: HNil, P] =
- new ExprHListWrapper(e1 :: e2 :: NonEmptyExprHList.tail(e3))
-
- def wrap[V, E1, E2, E3, E4, P](
- e1: Expr[V, E1, P],
- e2: Expr[V, E2, P],
- e3: Expr[V, E3, P],
- e4: Expr[V, E4, P],
- ): ExprHListWrapper[V, E1 :: E2 :: E3 :: E4 :: HNil, P] =
- new ExprHListWrapper(e1 :: e2 :: e3 :: NonEmptyExprHList.tail(e4))
-
- def wrap[V, E1, E2, E3, E4, E5, P](
- e1: Expr[V, E1, P],
- e2: Expr[V, E2, P],
- e3: Expr[V, E3, P],
- e4: Expr[V, E4, P],
- e5: Expr[V, E5, P],
- ): ExprHListWrapper[V, E1 :: E2 :: E3 :: E4 :: E5 :: HNil, P] =
- new ExprHListWrapper(e1 :: e2 :: e3 :: e4 :: NonEmptyExprHList.tail(e5))
-
- def wrap[V, E1, E2, E3, E4, E5, E6, P](
- e1: Expr[V, E1, P],
- e2: Expr[V, E2, P],
- e3: Expr[V, E3, P],
- e4: Expr[V, E4, P],
- e5: Expr[V, E5, P],
- e6: Expr[V, E6, P],
- ): ExprHListWrapper[V, E1 :: E2 :: E3 :: E4 :: E5 :: E6 :: HNil, P] =
- new ExprHListWrapper(e1 :: e2 :: e3 :: e4 :: e5 :: NonEmptyExprHList.tail(e6))
-
- def wrap[V, E1, E2, E3, E4, E5, E6, E7, P](
- e1: Expr[V, E1, P],
- e2: Expr[V, E2, P],
- e3: Expr[V, E3, P],
- e4: Expr[V, E4, P],
- e5: Expr[V, E5, P],
- e6: Expr[V, E6, P],
- e7: Expr[V, E7, P],
- ): ExprHListWrapper[V, E1 :: E2 :: E3 :: E4 :: E5 :: E6 :: E7 :: HNil, P] =
- new ExprHListWrapper(e1 :: e2 :: e3 :: e4 :: e5 :: e6 :: NonEmptyExprHList.tail(e7))
-
- def wrap[V, E1, E2, E3, E4, E5, E6, E7, E8, P](
- e1: Expr[V, E1, P],
- e2: Expr[V, E2, P],
- e3: Expr[V, E3, P],
- e4: Expr[V, E4, P],
- e5: Expr[V, E5, P],
- e6: Expr[V, E6, P],
- e7: Expr[V, E7, P],
- e8: Expr[V, E8, P],
- ): ExprHListWrapper[V, E1 :: E2 :: E3 :: E4 :: E5 :: E6 :: E7 :: E8 :: HNil, P] =
- new ExprHListWrapper(e1 :: e2 :: e3 :: e4 :: e5 :: e6 :: e7 :: NonEmptyExprHList.tail(e8))
-
- def wrap[V, E1, E2, E3, E4, E5, E6, E7, E8, E9, P](
- e1: Expr[V, E1, P],
- e2: Expr[V, E2, P],
- e3: Expr[V, E3, P],
- e4: Expr[V, E4, P],
- e5: Expr[V, E5, P],
- e6: Expr[V, E6, P],
- e7: Expr[V, E7, P],
- e8: Expr[V, E8, P],
- e9: Expr[V, E9, P],
- ): ExprHListWrapper[V, E1 :: E2 :: E3 :: E4 :: E5 :: E6 :: E7 :: E8 :: E9 :: HNil, P] =
- new ExprHListWrapper(e1 :: e2 :: e3 :: e4 :: e5 :: e6 :: e7 :: e8 :: NonEmptyExprHList.tail(e9))
-
- def wrap[V, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, P](
- e1: Expr[V, E1, P],
- e2: Expr[V, E2, P],
- e3: Expr[V, E3, P],
- e4: Expr[V, E4, P],
- e5: Expr[V, E5, P],
- e6: Expr[V, E6, P],
- e7: Expr[V, E7, P],
- e8: Expr[V, E8, P],
- e9: Expr[V, E9, P],
- e10: Expr[V, E10, P],
- ): ExprHListWrapper[V, E1 :: E2 :: E3 :: E4 :: E5 :: E6 :: E7 :: E8 :: E9 :: E10 :: HNil, P] =
- new ExprHListWrapper(e1 :: e2 :: e3 :: e4 :: e5 :: e6 :: e7 :: e8 :: e9 :: NonEmptyExprHList.tail(e10))
-
- def wrap[V, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, P](
- e1: Expr[V, E1, P],
- e2: Expr[V, E2, P],
- e3: Expr[V, E3, P],
- e4: Expr[V, E4, P],
- e5: Expr[V, E5, P],
- e6: Expr[V, E6, P],
- e7: Expr[V, E7, P],
- e8: Expr[V, E8, P],
- e9: Expr[V, E9, P],
- e10: Expr[V, E10, P],
- e11: Expr[V, E11, P],
- ): ExprHListWrapper[V, E1 :: E2 :: E3 :: E4 :: E5 :: E6 :: E7 :: E8 :: E9 :: E10 :: E11 :: HNil, P] =
- new ExprHListWrapper(e1 :: e2 :: e3 :: e4 :: e5 :: e6 :: e7 :: e8 :: e9 :: e10 :: NonEmptyExprHList.tail(e11))
-
- def wrap[V, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, P](
- e1: Expr[V, E1, P],
- e2: Expr[V, E2, P],
- e3: Expr[V, E3, P],
- e4: Expr[V, E4, P],
- e5: Expr[V, E5, P],
- e6: Expr[V, E6, P],
- e7: Expr[V, E7, P],
- e8: Expr[V, E8, P],
- e9: Expr[V, E9, P],
- e10: Expr[V, E10, P],
- e11: Expr[V, E11, P],
- e12: Expr[V, E12, P],
- ): ExprHListWrapper[V, E1 :: E2 :: E3 :: E4 :: E5 :: E6 :: E7 :: E8 :: E9 :: E10 :: E11 :: E12 :: HNil, P] =
- new ExprHListWrapper(
- e1 :: e2 :: e3 :: e4 :: e5 :: e6 :: e7 :: e8 :: e9 :: e10 :: e11 :: NonEmptyExprHList.tail(e12),
- )
-
-}
-
-final class ExprHListWrapper[V, L <: HList, P](override protected val exprHList: NonEmptyExprHList[V, Id, L, P])
- extends AnyVal
- with HListOperationWrapper[V, Id, L, P] {
-
- override type Op[R] = Expr.WrapOutputHList[V, L, R, P]
-
- override protected def buildOp[R](
- converter: ExprConverter[L, R],
- captureResult: CaptureP[V, Id[R], P],
- ): Expr.WrapOutputHList[V, L, R, P] =
- Expr.WrapOutputHList(exprHList, converter, captureResult)
-}
-
-final class GenericIdentity[R] extends Generic[R] {
- override type Repr = R
- override def to(repr: R): Repr = repr
- override def from(repr: Repr): R = repr
-}
-
-object GenericIdentity {
- def apply[R]: GenericIdentity[R] = new GenericIdentity[R]
-}
diff --git a/core/src/main/scala/vapors/dsl/package.scala b/core/src/main/scala/vapors/dsl/package.scala
deleted file mode 100644
index 603854984..000000000
--- a/core/src/main/scala/vapors/dsl/package.scala
+++ /dev/null
@@ -1,25 +0,0 @@
-package com.rallyhealth
-
-package vapors
-
-import vapors.algebra.{CaptureP, Expr}
-import vapors.data.{FactTable, TypedFact}
-
-package object dsl extends ExprDsl with ExprBuilderSyntax with WithOutputSyntax with ExprBuilderCatsInstances {
-
- final type CondExpr[V, P] = Expr[V, Boolean, P]
-
- final type ValExpr[V, R, P] = Expr[V, R, P]
- final type ValCondExpr[V, P] = ValExpr[V, Boolean, P]
-
- /**
- * An [[Expr]] that has no input dependency and only operates on the [[FactTable]].
- *
- * A root expression can be embedded inside of any other expression using an [[Expr.Embed]] node
- * (these will typically be applied automatically, but you can always forcibly embed the expressions).
- */
- final type RootExpr[R, P] = Expr[FactTable, R, P]
-
- final type CaptureRootExpr[R, P] = CaptureP[FactTable, R, P]
- final type CaptureFromFacts[T, P] = CaptureP[Seq[TypedFact[T]], Seq[TypedFact[T]], P]
-}
diff --git a/core/src/main/scala/vapors/interpreter/ExprInput.scala b/core/src/main/scala/vapors/interpreter/ExprInput.scala
deleted file mode 100644
index d5b31e022..000000000
--- a/core/src/main/scala/vapors/interpreter/ExprInput.scala
+++ /dev/null
@@ -1,38 +0,0 @@
-package com.rallyhealth
-
-package vapors.interpreter
-
-import vapors.data.{Evidence, FactTable}
-
-final case class ExprInput[V](
- value: V,
- evidence: Evidence,
- factTable: FactTable,
-) {
-
- @inline def withValue[U](
- value: U,
- evidence: Evidence = this.evidence,
- ): ExprInput[U] = copy(value = value, evidence = evidence)
-}
-
-object ExprInput {
-
- type Init = ExprInput[FactTable]
-
- @inline def fromFactTable(factTable: FactTable): Init =
- ExprInput(factTable, Evidence.none, factTable)
-
- @inline def fromValue[V](
- value: V,
- evidence: Evidence,
- factTable: FactTable,
- ): ExprInput[V] =
- ExprInput(value, evidence, factTable)
-
- @inline def fromValue[V](
- value: V,
- evidence: Evidence = Evidence.none,
- ): ExprInput[V] =
- fromValue(value, evidence, FactTable(evidence.factSet))
-}
diff --git a/core/src/main/scala/vapors/interpreter/ExprOutput.scala b/core/src/main/scala/vapors/interpreter/ExprOutput.scala
deleted file mode 100644
index d3eb9490f..000000000
--- a/core/src/main/scala/vapors/interpreter/ExprOutput.scala
+++ /dev/null
@@ -1,152 +0,0 @@
-package com.rallyhealth
-
-package vapors.interpreter
-
-import vapors.data.{Evidence, ExtractBoolean, ExtractValue}
-import vapors.logic.{Conjunction, Disjunction, Negation}
-
-import cats.Monoid
-
-/**
- * The result of a computation without any debugging information (i.e. captured parameter or result nodes)
- *
- * @param value the result of the computation
- * @param evidence the facts used in the computation
- */
-final case class ExprOutput[R](
- value: R,
- evidence: Evidence,
-)
-
-object ExprOutput {
-
- /**
- * Logical Conjunction (aka AND)
- *
- * - If either side is false, the result is false
- * - Evidence of falseness is accumulated
- * - Evidence of truthiness requires evidence of truth on both sides, otherwise no evidence of truth
- *
- * Examples:
- *
- * | X is True | Evidence of X | Y is True | Evidence of Y | Result is True | Evidence of Result |
- * | --------- | ------------- | --------- | ------------- | -------------- | ------------------ |
- * | T | {} | T | {} | T | {} |
- * | T | {} | F | {} | F | {} |
- * | T | {} | T | {A} | T | {} |
- * | T | {} | F | {A} | F | {A} |
- * | T | {B} | T | {A} | T | {A, B} |
- * | T | {B} | F | {} | F | {} |
- * | T | {B} | T | {} | T | {} |
- * | T | {B} | F | {A} | F | {A} |
- * | F | {} | T | {A} | F | {} |
- * | F | {B} | F | {A} | F | {A, B} |
- * | F | {B} | T | {A} | F | {B} |
- * | F | {B} | F | {} | F | {B} |
- * | F | {} | F | {A} | F | {} |
- */
- implicit def conjunction[R : Conjunction : ExtractBoolean]: Conjunction[ExprOutput[R]] =
- (lhs: ExprOutput[R], rhs: ExprOutput[R]) => {
- import cats.syntax.apply._
- @inline def isTrue(output: ExprOutput[R]): Boolean = ExtractValue[Boolean](output.value)
- val value = Conjunction[R].conjunction(lhs.value, rhs.value)
- val evidence = {
- if (ExtractValue[Boolean](value)) {
- // only combine evidence of truthiness if both sides are true
- val evTrueL = Option.when(isTrue(lhs))(lhs.evidence)
- val evTrueR = Option.when(isTrue(rhs))(rhs.evidence)
- (evTrueL, evTrueR).mapN(_ ++ _).getOrElse(Evidence.none)
- } else {
- val evFalseL = Option.unless(isTrue(lhs))(lhs.evidence)
- val evFalseR = Option.unless(isTrue(rhs))(rhs.evidence)
- // combine any evidence of falseness
- (evFalseL ++ evFalseR).foldLeft(Evidence.none) { case (l, r) => l ++ r }
- }
- }
- ExprOutput(value, evidence)
- }
-
- /**
- * Logical Disjunction (aka inclusive OR)
- *
- * - If either side is true, the result is true
- * - Evidence of truthiness is accumulated
- * - Evidence of falseness requires evidence of false on both sides, otherwise there is no evidence of false
- *
- * Examples:
- *
- * | X is True | Evidence of X | Y is True | Evidence of Y | Result is True | Evidence of Result |
- * | --------- | ------------- | --------- | ------------- | -------------- | ------------------ |
- * | T | {} | T | {} | T | {} |
- * | T | {} | F | {} | T | {} |
- * | T | {} | T | {A} | T | {A} |
- * | T | {} | F | {A} | T | {} |
- * | T | {B} | T | {A} | T | {A, B} |
- * | T | {B} | F | {} | T | {B} |
- * | T | {B} | T | {} | T | {B} |
- * | T | {B} | F | {A} | T | {B} |
- * | F | {} | T | {A} | T | {A} |
- * | F | {B} | F | {A} | F | {A, B} |
- * | F | {B} | T | {A} | T | {A} |
- * | F | {B} | F | {} | F | {} |
- * | F | {} | F | {A} | F | {} |
- */
- implicit def disjunction[R : Disjunction : ExtractBoolean]: Disjunction[ExprOutput[R]] =
- (lhs: ExprOutput[R], rhs: ExprOutput[R]) => {
- import cats.syntax.apply._
- @inline def isTrue(output: ExprOutput[R]): Boolean = ExtractValue[Boolean](output.value)
- val value = Disjunction[R].disjunction(lhs.value, rhs.value)
- val evidence = {
- if (ExtractValue[Boolean](value)) {
- // combine all evidence of truthiness from sides that are truthy
- val evTrueL = Option.when(isTrue(lhs))(lhs.evidence)
- val evTrueR = Option.when(isTrue(rhs))(rhs.evidence)
- (evTrueL ++ evTrueR).foldLeft(Evidence.none) { case (l, r) => l ++ r }
- } else {
- // only combine evidence of falseness if both sides are false
- val evFalseL = Option.unless(lhs.evidence.isEmpty)(lhs.evidence)
- val evFalseR = Option.unless(rhs.evidence.isEmpty)(rhs.evidence)
- (evFalseL, evFalseR).mapN(_ ++ _).getOrElse(Evidence.none)
- }
- }
- ExprOutput(value, evidence)
- }
-
- /**
- * Negates the result value without affecting the [[Evidence]].
- */
- implicit def negation[R : Negation]: Negation[ExprOutput[R]] = { output =>
- val negatedValue = Negation[R].negation(output.value)
- output.copy(value = negatedValue)
- }
-
- /**
- * Combine two monoidal values and union their evidence.
- *
- * @note This is not _always_ safe. There may be some combinations of values in which you must combine
- * [[Evidence]] for the resulting value differently based on the inputs. However, this is not the
- * general purpose or intent of saying something is a [[Monoid]], so this definition should be
- * generally safe. For example, there is no standard definition of [[Monoid]] for Boolean, because
- * there is no safe assumption for and "empty" boolean value. However, evidence of true || true is
- * not necessarily the same as evidence of true && true. Any definitions for which this distinction
- * matters will typically use its own typeclasses, such as [[Conjunction]] or [[Disjunction]].
- */
- implicit def monoid[A : Monoid]: Monoid[ExprOutput[A]] = {
- new Monoid[ExprOutput[A]] {
-
- override final def empty: ExprOutput[A] = {
- ExprOutput(Monoid[A].empty, Evidence.none)
- }
-
- override final def combine(
- x: ExprOutput[A],
- y: ExprOutput[A],
- ): ExprOutput[A] = {
- ExprOutput(
- Monoid[A].combine(x.value, y.value),
- x.evidence ++ y.evidence,
- )
- }
- }
- }
-}
diff --git a/core/src/main/scala/vapors/interpreter/InterpretExprAsResultFn.scala b/core/src/main/scala/vapors/interpreter/InterpretExprAsResultFn.scala
deleted file mode 100644
index 06f996b34..000000000
--- a/core/src/main/scala/vapors/interpreter/InterpretExprAsResultFn.scala
+++ /dev/null
@@ -1,614 +0,0 @@
-package com.rallyhealth
-
-package vapors.interpreter
-
-import vapors.algebra.{ConditionBranch, Expr, ExprResult, NonEmptyExprHList}
-import vapors.data._
-import vapors.interpreter.InterpretExprAsSimpleOutputFn.SimpleOutputFnFunctorBuilder
-import vapors.logic._
-import vapors.math._
-
-import cats._
-import cats.data.Chain
-import shapeless.HList
-
-import scala.collection.MapView
-import scala.collection.immutable.BitSet
-
-/**
- * This is the main interpreter for the [[Expr]] algebra. It recursively processes every node in the tree
- * and combines the [[ExprResult]] in a symmetric fashion.
- *
- * The end result of interpreting an [[Expr]] is a function from [[ExprInput]] => [[ExprResult]] (which
- * itself contains an [[ExprOutput]] and a captured [[P]] parameter inside of the [[ExprResult.Context]]).
- *
- * This interpreter calls itself recursively for every sub-expression node by calling the [[Expr.visit]]
- * and passing the appropriate definition of [[Expr.Visitor]] (i.e. either `this` or some appropriately
- * parameterized version of [[InterpretExprAsResultFn]]).
- *
- * In some cases, we cannot recursively handle [[ExprResult]]s, so we use the [[InterpretExprAsSimpleOutputFn]]
- * to get a simplified output function that can be combined in a [[Semigroupal]] fashion.
- */
-final class InterpretExprAsResultFn[V, P] extends Expr.Visitor[V, P, Lambda[r => ExprInput[V] => ExprResult[V, r, P]]] {
-
- import cats.syntax.all._
- import vapors.syntax.math._
-
- override def visitAddOutputs[R : Addition](expr: Expr.AddOutputs[V, R, P]): ExprInput[V] => ExprResult[V, R, P] = {
- input =>
- val inputResults = expr.inputExprList.map { inputExpr =>
- inputExpr.visit(this)(input)
- }
- val inputResultList = inputResults.toList
- val outputValue = inputResultList.map(_.output.value).reduceLeft(_ + _)
- val allEvidence = inputResultList.foldMap(_.output.evidence)
- val allParams = inputResultList.map(_.param)
- resultOfManySubExpr(expr, input, outputValue, allEvidence, allParams) {
- ExprResult.AddOutputs(_, _, inputResultList)
- }
- }
-
- override def visitAnd[R : Conjunction : ExtractBoolean](
- expr: Expr.And[V, R, P],
- ): ExprInput[V] => ExprResult[V, R, P] = { input =>
- val inputResults = expr.inputExprList.map { inputExpr =>
- inputExpr.visit(this)(input)
- }
- val combinedOutput = inputResults.map(_.output).reduceLeft(Conjunction[ExprOutput[R]].conjunction)
- val inputResultList = inputResults.toList
- val allParams = inputResultList.map(_.param)
- resultOfManySubExpr(expr, input, combinedOutput.value, combinedOutput.evidence, allParams) {
- ExprResult.And(_, _, inputResultList)
- }
- }
-
- override def visitCollectSomeOutput[M[_] : Foldable, U, R : Monoid](
- expr: Expr.CollectFromOutput[V, M, U, R, P],
- ): ExprInput[V] => ExprResult[V, R, P] = { input =>
- val inputResult = expr.inputExpr.visit(this)(input)
- val collectFn = expr.collectExpr.visit(InterpretExprAsResultFn())
- val (combinedResult, combinedEvidence, allParams) = inputResult.output.value.collectFoldSome { elem =>
- // If given a fact, use it as evidence, otherwise keep input evidence for this value of the collection
- val inputEvidence = Evidence.fromAny(elem).getOrElse(inputResult.output.evidence)
- val collectInput = input.withValue(elem, inputEvidence)
- val collectResult = collectFn(collectInput)
- // TODO: Keep all params / replay steps instead of just the ones that return true?
- collectResult.output.value.map { result =>
- (
- result,
- collectResult.output.evidence,
- collectResult.param :: Nil,
- )
- }
- }
- resultOfManySubExpr(expr, input, combinedResult, combinedEvidence, allParams) {
- ExprResult.CollectFromOutput(_, _, inputResult)
- }
- }
-
- override def visitConcatOutput[M[_] : MonoidK, R](
- expr: Expr.ConcatOutput[V, M, R, P],
- ): ExprInput[V] => ExprResult[V, M[R], P] = { input =>
- implicit val monoidMR: Monoid[M[R]] = MonoidK[M].algebra[R]
- val inputResults = expr.inputExprList.map(_.visit(this)(input))
- val allParams = inputResults.map(_.param).toList
- val allEvidence = inputResults.foldMap(_.output.evidence)
- val outputValues = inputResults.foldMap(_.output.value)
- resultOfManySubExpr(expr, input, outputValues, allEvidence, allParams) {
- ExprResult.ConcatOutput(_, _, inputResults)
- }
- }
-
- override def visitConstOutput[R](expr: Expr.ConstOutput[V, R, P]): ExprInput[V] => ExprResult[V, R, P] = { input =>
- resultOfPureExpr(expr, input, expr.value, input.evidence) {
- ExprResult.ConstOutput(_, _)
- }
- }
-
- override def visitCustomFunction[A, R](
- expr: Expr.CustomFunction[V, A, R, P],
- ): ExprInput[V] => ExprResult[V, R, P] = { input =>
- val argResult = InterpretExprAsResultFn(expr.inputExpr)(input)
- val value = expr.evaluate(argResult.output.value)
- resultOfPureExpr(expr, input, value, argResult.output.evidence) {
- ExprResult.CustomFunction(_, _, argResult)
- }
- }
-
- override def visitDefine[M[_] : Foldable, T](
- expr: Expr.Define[M, T, P],
- ): ExprInput[V] => ExprResult[V, FactSet, P] = { input =>
- val definitionFn = expr.definitionExpr.visit(InterpretExprAsResultFn())
- val definitionContext = input.withValue(input.factTable)
- val definitionResult = definitionFn(definitionContext)
- val definedFactSet = definitionResult.output.value.foldMap { definitionValue =>
- FactSet(DerivedFact(expr.factType, definitionValue, definitionResult.output.evidence))
- }
- val output = ExprOutput(definedFactSet, definitionResult.output.evidence)
- val postParam = expr.capture.foldToParam(expr, definitionContext, output, definitionResult.param :: Nil)
- ExprResult.Define(expr, ExprResult.Context(input, output, postParam), definitionResult)
- }
-
- override def visitEmbed[R](expr: Expr.Embed[V, R, P]): ExprInput[V] => ExprResult[V, R, P] = { input =>
- val embeddedFn = expr.embeddedExpr.visit(InterpretExprAsResultFn())
- val embeddedInput = input.withValue(input.factTable)
- val embeddedResult = embeddedFn(embeddedInput)
- // The evidence of the surrounding context is not relevant to the evidence of the embedded expression
- // so we ignore it and leave it up to the parent expression to combine evidence as it sees fit.
- resultOfSingleSubExpr(expr, input, embeddedResult) {
- ExprResult.Embed(_, _, embeddedResult)
- }
- }
-
- override def visitExistsInOutput[M[_] : Foldable, U](
- expr: Expr.ExistsInOutput[V, M, U, P],
- ): ExprInput[V] => ExprResult[V, Boolean, P] = { input =>
- val inputResult = expr.inputExpr.visit(this)(input)
- val conditionFn = expr.conditionExpr.visit(InterpretExprAsResultFn())
- val (allMatchedIndexes, allEvidence, allCondResults) = inputResult.output.value.toList.zipWithIndex.collectFold {
- case (elem, idx) =>
- // If given a fact, use it as evidence, otherwise keep input evidence for this value of the collection
- val inputEvidence = Evidence.fromAny(elem).getOrElse(inputResult.output.evidence)
- val conditionInput = input.withValue(elem, inputEvidence)
- val conditionResult = conditionFn(conditionInput)
- val isMatch = conditionResult.output.value
- val (matchedIdx, accEvidence, accResults) = {
- if (isMatch) (Chain(idx), conditionResult.output.evidence, Chain(conditionResult))
- else (Chain.nil, Evidence.none, Chain.nil)
- }
- (matchedIdx, accEvidence, accResults)
- }
- val matchedIndexSet = allMatchedIndexes.iterator.to(BitSet)
- val condResultList = allCondResults.toList
- val allParams = condResultList.map(_.param)
- // TODO: Better way to capture the param from the inputResult separate from the condResultList params?
- resultOfManySubExpr(expr, input, matchedIndexSet.nonEmpty, allEvidence, inputResult.param :: allParams) {
- ExprResult.ExistsInOutput(_, _, inputResult, condResultList, matchedIndexSet)
- }
- }
-
- override def visitExponentiateOutputs(
- expr: Expr.ExponentiateOutputs[V, P],
- ): ExprInput[V] => ExprResult[V, Double, P] = { input =>
- val baseResult = expr.baseExpr.visit(this)(input)
- val exponentResult = expr.exponentExpr.visit(this)(input)
- val base = baseResult.output.value
- val exponent = exponentResult.output.value
- val output = Math.pow(base, exponent)
- val allEvidence = baseResult.output.evidence ++ exponentResult.output.evidence
- val allParams = List(baseResult.param, exponentResult.param)
- resultOfManySubExpr(expr, input, output, allEvidence, allParams) {
- ExprResult.ExponentiateOutputs(_, _, baseResult, exponentResult)
- }
- }
-
- override def visitFilterOutput[M[_] : Foldable : FunctorFilter, U](
- expr: Expr.FilterOutput[V, M, U, P],
- ): ExprInput[V] => ExprResult[V, M[U], P] = { input =>
- implicit val functorM: Functor[M] = FunctorFilter[M].functor
- val inputResult = expr.inputExpr.visit(this)(input)
- val condFn = expr.condExpr.visit(InterpretExprAsResultFn())
- val condResults = inputResult.output.value.map { elem =>
- val inputEvidence = Evidence.fromAny(elem).getOrElse(inputResult.output.evidence)
- val condInput = input.withValue(elem, inputEvidence)
- condFn(condInput)
- }
- val matchingValues = condResults.collect {
- case condResult if condResult.output.value => condResult.input.value
- }
- val (matchingEvidence, matchingParams) = condResults.collectFoldSome { result =>
- Option.when(result.output.value) {
- (result.output.evidence, result.param :: Nil)
- }
- }
- val condResultList = condResults.toList
- // TODO: Better way to capture the param from the inputResult separate from the condResultList params?
- resultOfManySubExpr(expr, input, matchingValues, matchingEvidence, inputResult.param :: matchingParams) {
- ExprResult.FilterOutput(_, _, inputResult, condResultList)
- }
- }
-
- override def visitFlatMapOutput[M[_] : Foldable : FlatMap, U, X](
- expr: Expr.FlatMapOutput[V, M, U, X, P],
- ): ExprInput[V] => ExprResult[V, M[X], P] = { input =>
- val inputResult = expr.inputExpr.visit(this)(input)
- val flatMapFn = expr.flatMapExpr.visit(InterpretExprAsResultFn())
- val allResults = inputResult.output.value.map { elem =>
- // If given a fact, use it as evidence, otherwise keep input evidence for this value of the collection
- val inputEvidence = Evidence.fromAny(elem).getOrElse(inputResult.output.evidence)
- val flatMapInput = input.withValue(elem, inputEvidence)
- flatMapFn(flatMapInput)
- }
- val allValues = allResults.flatMap(_.output.value)
- // TODO: Shouldn't I only look at the evidence of results that aren't empty?
- val (allEvidence, allParams) = allResults.foldMap { elemResult =>
- (elemResult.output.evidence, elemResult.param :: Nil)
- }
- val subOps = allResults.toList
- resultOfManySubExpr(expr, input, allValues, allEvidence, allParams) {
- ExprResult.FlatMapOutput(_, _, inputResult, subOps)
- }
- }
-
- override def visitGroupOutput[M[_] : Foldable, U : Order, K](
- expr: Expr.GroupOutput[V, M, U, K, P],
- ): ExprInput[V] => ExprResult[V, MapView[K, Seq[U]], P] = { input =>
- val inputResult = expr.inputExpr.visit(this)(input)
- val values = inputResult.output.value
- val grouped = values.toIterable.groupBy(expr.groupByLens.get).view.mapValues(_.to(LazyList))
- resultOfManySubExpr(expr, input, grouped, inputResult.output.evidence, inputResult.param :: Nil) {
- ExprResult.GroupOutput(_, _, inputResult)
- }
- }
-
- override def visitMapOutput[M[_] : Foldable : Functor, U, R](
- expr: Expr.MapOutput[V, M, U, R, P],
- ): ExprInput[V] => ExprResult[V, M[R], P] = { input =>
- val inputResult = expr.inputExpr.visit(this)(input)
- val mapFn = expr.mapExpr.visit(InterpretExprAsResultFn())
- val allResults = inputResult.output.value.map { elem =>
- // If given a fact, use it as evidence, otherwise keep input evidence for this value of the collection
- val inputEvidence = Evidence.fromAny(elem).getOrElse(inputResult.output.evidence)
- val mapInput = input.withValue(elem, inputEvidence)
- mapFn(mapInput)
- }
- val allValues = allResults.map(_.output.value)
- val (allEvidence, allParams) = allResults.foldMap { elemResult =>
- (elemResult.output.evidence, elemResult.param :: Nil)
- }
- val subOps = allResults.toList
- resultOfManySubExpr(expr, input, allValues, allEvidence, allParams) {
- ExprResult.MapOutput(_, _, inputResult, subOps)
- }
- }
-
- override def visitMultiplyOutputs[R : Multiplication](
- expr: Expr.MultiplyOutputs[V, R, P],
- ): ExprInput[V] => ExprResult[V, R, P] = { input =>
- val inputResults = expr.inputExprList.map { inputExpr =>
- inputExpr.visit(this)(input)
- }
- val inputResultList = inputResults.toList
- val outputValue = inputResultList.map(_.output.value).reduceLeft(_ * _)
- val allEvidence = inputResultList.foldMap(_.output.evidence)
- val allParams = inputResultList.map(_.param)
- resultOfManySubExpr(expr, input, outputValue, allEvidence, allParams) {
- ExprResult.MultiplyOutputs(_, _, inputResultList)
- }
- }
-
- override def visitNegativeOutput[R : Negative](
- expr: Expr.NegativeOutput[V, R, P],
- ): ExprInput[V] => ExprResult[V, R, P] = { input =>
- val inputResult = expr.inputExpr.visit(this)(input)
- val outputValue = Negative[R].negative(inputResult.output.value)
- resultOfManySubExpr(expr, input, outputValue, inputResult.output.evidence, inputResult.param :: Nil) {
- ExprResult.NegativeOutput(_, _, inputResult)
- }
- }
-
- override def visitNot[R : Negation](expr: Expr.Not[V, R, P]): ExprInput[V] => ExprResult[V, R, P] = { input =>
- val inputResult = expr.inputExpr.visit(this)(input)
- val outputValue = Negation[R].negation(inputResult.output.value)
- resultOfManySubExpr(expr, input, outputValue, inputResult.output.evidence, inputResult.param :: Nil) {
- ExprResult.Not(_, _, inputResult)
- }
- }
-
- override def visitOr[R : Disjunction : ExtractBoolean](
- expr: Expr.Or[V, R, P],
- ): ExprInput[V] => ExprResult[V, R, P] = { input =>
- val inputResults = expr.inputExprList.map { inputExpr =>
- inputExpr.visit(this)(input)
- }
- val combinedOutput = inputResults.map(_.output).reduceLeft(Disjunction[ExprOutput[R]].disjunction)
- val inputResultList = inputResults.toList
- val allParams = inputResultList.map(_.param)
- resultOfManySubExpr(expr, input, combinedOutput.value, combinedOutput.evidence, allParams) {
- ExprResult.Or(_, _, inputResultList)
- }
- }
-
- override def visitOutputIsEmpty[M[_] : Foldable, R](
- expr: Expr.OutputIsEmpty[V, M, R, P],
- ): ExprInput[V] => ExprResult[V, Boolean, P] = { input =>
- val inputResult = expr.inputExpr.visit(this)(input)
- val isEmpty = inputResult.output.value.isEmpty
- resultOfPureExpr(expr, input, isEmpty, inputResult.output.evidence) {
- ExprResult.OutputIsEmpty(_, _, inputResult)
- }
- }
-
- override def visitOutputWithinSet[R](
- expr: Expr.OutputWithinSet[V, R, P],
- ): ExprInput[V] => ExprResult[V, Boolean, P] = { input =>
- val inputResult = expr.inputExpr.visit(this)(input)
- val isWithinSet = expr.accepted.contains(inputResult.output.value)
- resultOfPureExpr(expr, input, isWithinSet, inputResult.output.evidence) {
- ExprResult.OutputWithinSet(_, _, inputResult)
- }
- }
-
- override def visitOutputWithinWindow[R](
- expr: Expr.OutputWithinWindow[V, R, P],
- ): ExprInput[V] => ExprResult[V, Boolean, P] = { input =>
- val inputResult = expr.inputExpr.visit(this)(input)
- val windowResult = expr.windowExpr.visit(this)(input)
- val isWithinWindow = windowResult.output.value.contains(inputResult.output.value)
- resultOfPureExpr(expr, input, isWithinWindow, inputResult.output.evidence ++ windowResult.output.evidence) {
- ExprResult.OutputWithinWindow(_, _, inputResult)
- }
- }
-
- override def visitFoldOutput[M[_] : Foldable, R : Monoid](
- expr: Expr.FoldOutput[V, M, R, P],
- ): ExprInput[V] => ExprResult[V, R, P] = { input =>
- val inputResult = expr.inputExpr.visit(this)(input)
- val resultValue = inputResult.output.value.fold
- resultOfPureExpr(expr, input, resultValue, inputResult.output.evidence) {
- ExprResult.FoldOutput(_, _, inputResult)
- }
- }
-
- override def visitReturnInput(expr: Expr.ReturnInput[V, P]): ExprInput[V] => ExprResult[V, V, P] = { input =>
- resultOfPureExpr(expr, input, input.value, input.evidence ++ Evidence.fromAnyOrNone(input.value)) {
- ExprResult.ReturnInput(_, _)
- }
- }
-
- override def visitSelectFromOutput[S, R](
- expr: Expr.SelectFromOutput[V, S, R, P],
- ): ExprInput[V] => ExprResult[V, R, P] = { input =>
- val inputResult = expr.inputExpr.visit(this)(input)
- val selected = expr.lens.get(inputResult.output.value)
- resultOfManySubExpr(expr, input, selected, inputResult.output.evidence, inputResult.param :: Nil) {
- ExprResult.SelectFromOutput(_, _, inputResult)
- }
- }
-
- override def visitSortOutput[M[_], R](expr: Expr.SortOutput[V, M, R, P]): ExprInput[V] => ExprResult[V, M[R], P] = {
- input =>
- val inputResult = expr.inputExpr.visit(this)(input)
- val unsorted = inputResult.output.value
- val sorted = expr.sorter(unsorted)
- resultOfManySubExpr(expr, input, sorted, inputResult.output.evidence, inputResult.param :: Nil) {
- ExprResult.SortOutput(_, _, inputResult)
- }
- }
-
- override def visitSubtractOutputs[R : Subtraction](
- expr: Expr.SubtractOutputs[V, R, P],
- ): ExprInput[V] => ExprResult[V, R, P] = { input =>
- val allResults = expr.inputExprList.map(_.visit(this)(input))
- val allResultsList = allResults.toList
- val addResult = allResultsList.map(_.output.value).reduceLeft(_ - _)
- val allEvidence = allResultsList.foldMap(_.output.evidence)
- val allParams = allResultsList.map(_.param)
- resultOfManySubExpr(expr, input, addResult, allEvidence, allParams) {
- ExprResult.SubtractOutputs(_, _, allResultsList)
- }
- }
-
- override def visitDivideOutputs[R : Division](
- expr: Expr.DivideOutputs[V, R, P],
- ): ExprInput[V] => ExprResult[V, R, P] = { input =>
- val allResults = expr.inputExprList.map(_.visit(this)(input))
- val allResultsList = allResults.toList
- val addResult = allResultsList.map(_.output.value).reduceLeft(_ / _)
- val allEvidence = allResultsList.foldMap(_.output.evidence)
- val allParams = allResultsList.map(_.param)
- resultOfManySubExpr(expr, input, addResult, allEvidence, allParams) {
- ExprResult.DivideOutputs(_, _, allResultsList)
- }
- }
-
- override def visitTakeFromOutput[M[_] : Traverse : TraverseFilter, R](
- expr: Expr.TakeFromOutput[V, M, R, P],
- ): ExprInput[V] => ExprResult[V, M[R], P] = { input =>
- val inputResult = expr.inputExpr.visit(this)(input)
- val values = inputResult.output.value
- val takeWindow: Window[Int] = expr.take match {
- case pos if pos > 0 => Window.between(0, pos)
- case 0 => Window.empty
- case neg if neg < 0 =>
- val totalSize = values.size.toInt
- Window.between(totalSize + neg, totalSize)
- }
- // TODO: Handle evidence when the input is a set / sequence of facts
- val selectedValues = values.zipWithIndex.collect {
- case (elem, idx) if takeWindow.contains(idx) => elem
- }
- resultOfManySubExpr(expr, input, selectedValues, inputResult.output.evidence, inputResult.param :: Nil) {
- ExprResult.TakeFromOutput(_, _, inputResult)
- }
- }
-
- override def visitWrapOutputSeq[R](expr: Expr.WrapOutputSeq[V, R, P]): ExprInput[V] => ExprResult[V, Seq[R], P] = {
- input =>
- val inputResultList = expr.inputExprList.to(LazyList).map(_.visit(this)(input))
- val allEvidence = inputResultList.foldMap(_.output.evidence)
- val allParams = inputResultList.foldMap(_.param :: Nil)
- val outputValues = inputResultList.map(_.output.value)
- resultOfManySubExpr(expr, input, outputValues, allEvidence, allParams) {
- ExprResult.WrapOutputSeq(_, _, inputResultList)
- }
- }
-
- override def visitWrapOutput[L, R](expr: Expr.WrapOutput[V, L, R, P]): ExprInput[V] => ExprResult[V, R, P] = {
- input =>
- val inputResult = expr.inputExpr.visit(this)(input)
- val convertedValue = expr.converter(inputResult.output.value)
- resultOfManySubExpr(expr, input, convertedValue, inputResult.output.evidence, inputResult.param :: Nil) {
- ExprResult.WrapOutput(_, _, inputResult)
- }
- }
-
- override def visitWrapOutputHList[T <: HList, R](
- expr: Expr.WrapOutputHList[V, T, R, P],
- ): ExprInput[V] => ExprResult[V, R, P] = { input =>
- val (tupleOutput, allParams) = visitHListOfScalarExprAndCombineOutput(expr.inputExprHList, input)
- val value = expr.converter(tupleOutput.value)
- resultOfManySubExpr(expr, input, value, tupleOutput.evidence, allParams) {
- ExprResult.WrapOutputHList(_, _)
- }
- }
-
- override def visitUsingDefinitions[R](expr: Expr.UsingDefinitions[V, R, P]): ExprInput[V] => ExprResult[V, R, P] = {
- input =>
- val definitionVisitor = new InterpretExprAsResultFn[FactTable, P]
- val definitionInput = input.withValue(input.factTable)
- val (declaredFacts, evidence, declaredParams) = expr.definitions.foldMap { defExpr =>
- val definitionFn = defExpr.visit(definitionVisitor)
- val definitionResult = definitionFn(definitionInput)
- (definitionResult.output.value, definitionResult.output.evidence, definitionResult.param :: Nil)
- }
- val subInput = input.copy(factTable = input.factTable.addAll(declaredFacts))
- val subFn = expr.subExpr.visit(this)
- val subResult = subFn(subInput)
- // TODO: Come up with a better way to combine the CaptureP params from expressions that have multiple
- // sub expressions with different meanings.
- val allParams = subResult.param :: declaredParams
- val postParam = expr.capture.foldToParam(expr, input, subResult.output, allParams)
- ExprResult.UsingDefinitions(expr, ExprResult.Context(input, subResult.output, postParam), subResult)
- }
-
- override def visitWhen[R](expr: Expr.When[V, R, P]): ExprInput[V] => ExprResult[V, R, P] = { input =>
- val (maybeConditionResult, condParams) = {
- expr.conditionBranches.foldLeft((None, Nil): (Option[(ConditionBranch[V, R, P], Evidence)], List[Eval[P]])) {
- case (acc @ (Some(_), _), _) => acc
- case ((None, params), cond) =>
- val whenResult = cond.whenExpr.visit(this)(input)
- val conditionMet = whenResult.output.value
- (Option.when(conditionMet)((cond, whenResult.output.evidence)), whenResult.param :: params)
- }
- }
- val (thenExpr, condEvidence) = maybeConditionResult
- .map {
- case (branch, evidence) => (branch.thenExpr, evidence)
- }
- .getOrElse {
- (expr.defaultExpr, Evidence.none)
- }
- val thenResult = thenExpr.visit(this)(input)
- // union the evidence for the condition with the evidence for the output
- val allEvidence = condEvidence.union(thenResult.output.evidence)
- // TODO: Better way to organize the params than to just put the thenExpr param at the head?
- val allParams = thenResult.param :: condParams
- resultOfManySubExpr(expr, input, thenResult.output.value, allEvidence, allParams) {
- ExprResult.When(_, _, maybeConditionResult.map(_._1), thenResult)
- }
- }
-
- override def visitWithFactsOfType[T, R](
- expr: Expr.WithFactsOfType[T, R, P],
- ): ExprInput[V] => ExprResult[V, R, P] = { input =>
- val inputFactTable = input.withValue(input.factTable)
- val withMatchingFactsFn = expr.subExpr.visit(InterpretExprAsResultFn())
- val matchingFacts = input.factTable.getSortedSeq(expr.factTypeSet)
- // facts will always be added as their own evidence when used, so we do not need to add them to the evidence here
- val subInput = input.withValue[Seq[TypedFact[T]]](matchingFacts)
- val subResult = withMatchingFactsFn(subInput)
- val postParam = expr.capture.foldToParam(expr, inputFactTable, subResult.output, subResult.param :: Nil)
- ExprResult.WithFactsOfType(
- expr,
- ExprResult.Context(input, subResult.output, postParam),
- subResult,
- )
- }
-
- override def visitZipOutput[M[_] : Align : FunctorFilter, L <: HList, R](
- expr: Expr.ZipOutput[V, M, L, R, P],
- ): ExprInput[V] => ExprResult[V, M[R], P] = { input =>
- val (tupleOutput, allParams) =
- visitHListOfHigherKindedExprAndZipCombinedToShortestOutput(expr.inputExprHList, input)
- val outputValues = FunctorFilter[M].functor.map(tupleOutput.value)(expr.converter)
- resultOfManySubExpr(expr, input, outputValues, tupleOutput.evidence, allParams) {
- ExprResult.ZipOutput(_, _)
- }
- }
-
- @inline private def resultOfPureExpr[R](
- expr: Expr[V, R, P],
- input: ExprInput[V],
- result: R,
- evidence: Evidence,
- )(
- buildPostOp: (expr.type, ExprResult.Context[V, R, P]) => ExprResult[V, R, P],
- ): ExprResult[V, R, P] = {
- resultOfManySubExpr(expr, input, result, evidence, Nil)(buildPostOp)
- }
-
- @inline private def resultOfManySubExpr[R](
- expr: Expr[V, R, P],
- input: ExprInput[V],
- result: R,
- evidence: Evidence,
- capturedParams: List[Eval[P]],
- )(
- buildResult: (expr.type, ExprResult.Context[V, R, P]) => ExprResult[V, R, P],
- ): ExprResult[V, R, P] = {
- val output = ExprOutput(result, evidence)
- val param = expr.capture.foldToParam(expr, input, output, capturedParams)
- buildResult(expr, ExprResult.Context(input, output, param))
- }
-
- @inline private def resultOfSingleSubExpr[R](
- expr: Expr[V, R, P],
- input: ExprInput[V],
- subResult: ExprResult[_, R, P],
- )(
- buildPostOp: (expr.type, ExprResult.Context[V, R, P]) => ExprResult[V, R, P],
- ): ExprResult[V, R, P] = {
- resultOfManySubExpr(expr, input, subResult.output.value, subResult.output.evidence, subResult.param :: Nil) {
- buildPostOp
- }
- }
-
- /**
- * This type and functor are used for HList operations that require the [[InterpretExprAsSimpleOutputFn]] interpreter
- */
- private object SimpleOutputFnFunctorBuilder extends SimpleOutputFnFunctorBuilder[V, P]
- import SimpleOutputFnFunctorBuilder._
-
- /**
- * Uses the [[SimpleOutputFunctor]] to visit and map over each expression of the given `exprHList` and return
- * a simplified output of [[InterpretExprAsSimpleOutputFn.GenSimpleOutput]] combined as a Monoid.
- *
- * The evidence sets are unioned together, the params are combined in a list, and the values are mapped into
- * an [[HList]] of the given type.
- *
- * @see [[NonEmptyExprHList.visitProduct]] for more details and examples
- */
- private def visitHListOfScalarExprAndCombineOutput[L <: HList](
- exprHList: NonEmptyExprHList[V, Id, L, P],
- input: ExprInput[V],
- ): SimpleOutput[L] = {
- implicit val id: Functor[Id] with Semigroupal[Id] = cats.catsInstancesForId
- exprHList.visitProduct(new InterpretExprAsSimpleOutputFn).apply(input)
- }
-
- /**
- * Similar to [[visitHListOfScalarExprAndCombineOutput]] except that it handles an HList of expressions that return
- * higher-kinded functor wrapped values by aligning and zipping the values as HList values of each element
- * inside the wrapper.
- *
- * In other words, it only returns a wrapped HList for each element of the shortest-length output value.
- *
- * @see [[NonEmptyExprHList.visitZippedToShortest]] for more details and examples.
- */
- private def visitHListOfHigherKindedExprAndZipCombinedToShortestOutput[M[_] : Align : FunctorFilter, L <: HList](
- exprHList: NonEmptyExprHList[V, M, L, P],
- input: ExprInput[V],
- ): SimpleOutput[M[L]] = {
- exprHList.visitZippedToShortest(new InterpretExprAsSimpleOutputFn).apply(input)
- }
-}
-
-object InterpretExprAsResultFn {
-
- final def apply[V, P](): InterpretExprAsResultFn[V, P] = new InterpretExprAsResultFn
-
- final def apply[V, R, P](expr: Expr[V, R, P])(input: ExprInput[V]): ExprResult[V, R, P] = {
- expr.visit(InterpretExprAsResultFn())(input)
- }
-}
diff --git a/core/src/main/scala/vapors/interpreter/InterpretExprAsSimpleOutputFn.scala b/core/src/main/scala/vapors/interpreter/InterpretExprAsSimpleOutputFn.scala
deleted file mode 100644
index 6b70f2133..000000000
--- a/core/src/main/scala/vapors/interpreter/InterpretExprAsSimpleOutputFn.scala
+++ /dev/null
@@ -1,57 +0,0 @@
-package com.rallyhealth
-
-package vapors.interpreter
-
-import vapors.algebra.Expr
-import vapors.interpreter.InterpretExprAsSimpleOutputFn.GenSimpleOutput
-
-import cats.{Eval, Functor, Semigroupal}
-
-/**
- * Interprets an [[Expr]] as a function from [[ExprInput]] to a tuple of [[ExprOutput]] and a list of captured params.
- *
- * This is necessary to define a [[Functor]] and [[Semigroupal]] for an expression, so that we can recursively map
- * over the whole [[com.rallyhealth.vapors.algebra.NonEmptyExprHList]] to get an [[shapeless.HList]] result.
- *
- * Since the [[InterpretExprAsResultFn]] return type is dependent on the input [[Expr]], it is impossible to define
- * these instances. By simplifying to the more generic return type of [[GenSimpleOutput]] we are able to leverage
- * the standard function, tuple, and list instances from cats over the well defined type constructor of [[ExprOutput]].
- *
- * @see [[GenSimpleOutput]] for the interpreted function return type.
- * @see [[InterpretExprAsResultFn]] for the implementation details.
- */
-class InterpretExprAsSimpleOutputFn[V, P] extends VisitGenericExprWithProxyFn[V, P, GenSimpleOutput[*, P]] {
-
- override protected def visitGeneric[U, R](
- expr: Expr[U, R, P],
- input: ExprInput[U],
- ): GenSimpleOutput[R, P] = {
- val result = InterpretExprAsResultFn(expr)(input)
- // strip the output and captured param from the full ExprResult
- (result.output, result.param :: Nil)
- }
-}
-
-object InterpretExprAsSimpleOutputFn {
- type GenSimpleOutput[R, P] = (ExprOutput[R], List[Eval[P]])
-
- class SimpleOutputFnFunctorBuilder[V, P] {
- type SimpleOutput[R] = GenSimpleOutput[R, P]
- type SimpleOutputFn[R] = ExprInput[V] => SimpleOutput[R]
-
- implicit object SimpleOutputFunctor extends Functor[SimpleOutputFn] with Semigroupal[SimpleOutputFn] {
- override def map[A, B](fa: SimpleOutputFn[A])(f: A => B): SimpleOutputFn[B] = fa.andThen {
- case (o, params) => (o.copy(value = f(o.value)), params)
- }
-
- override def product[A, B](
- fa: SimpleOutputFn[A],
- fb: SimpleOutputFn[B],
- ): SimpleOutputFn[(A, B)] = { input =>
- val (a, aParams) = fa(input)
- val (b, bParams) = fb(input)
- (ExprOutput((a.value, b.value), a.evidence & b.evidence), aParams ::: bParams)
- }
- }
- }
-}
diff --git a/core/src/main/scala/vapors/interpreter/VisitGenericExprWithProxyFn.scala b/core/src/main/scala/vapors/interpreter/VisitGenericExprWithProxyFn.scala
deleted file mode 100644
index c73955549..000000000
--- a/core/src/main/scala/vapors/interpreter/VisitGenericExprWithProxyFn.scala
+++ /dev/null
@@ -1,147 +0,0 @@
-package com.rallyhealth
-
-package vapors.interpreter
-
-import vapors.algebra.Expr
-import vapors.algebra.Expr.Visitor
-import vapors.data.{ExtractBoolean, FactSet}
-import vapors.logic.{Conjunction, Disjunction, Negation}
-import vapors.math._
-
-import cats._
-import cats.kernel.Monoid
-import shapeless.HList
-
-import scala.collection.MapView
-
-/**
- * A function interpreter from [[ExprInput]] to any output type constructor that passes all expressions nodes into
- * a single common [[visitGeneric]] function.
- *
- * This class makes it easier to define common behavior when interpreting expressions as functions when you do not
- * need to take into account any specific method signatures or expression node types. It is useful for defining
- * behavior that only relies on the common methods and values of [[Expr]] and [[ExprInput]].
- */
-abstract class VisitGenericExprWithProxyFn[V, P, G[_]] extends Visitor[V, P, Lambda[r => ExprInput[V] => G[r]]] {
-
- protected def visitGeneric[U, R](
- expr: Expr[U, R, P],
- input: ExprInput[U],
- ): G[R]
-
- override def visitAddOutputs[R : Addition](expr: Expr.AddOutputs[V, R, P]): ExprInput[V] => G[R] =
- visitGeneric(expr, _)
-
- override def visitAnd[R : Conjunction : ExtractBoolean](expr: Expr.And[V, R, P]): ExprInput[V] => G[R] =
- visitGeneric(expr, _)
-
- override def visitCollectSomeOutput[M[_] : Foldable, U, R : Monoid](
- expr: Expr.CollectFromOutput[V, M, U, R, P],
- ): ExprInput[V] => G[R] = visitGeneric(expr, _)
-
- override def visitConcatOutput[M[_] : MonoidK, R](expr: Expr.ConcatOutput[V, M, R, P]): ExprInput[V] => G[M[R]] =
- visitGeneric(expr, _)
-
- override def visitConstOutput[R](expr: Expr.ConstOutput[V, R, P]): ExprInput[V] => G[R] =
- visitGeneric(expr, _)
-
- override def visitCustomFunction[A, R](expr: Expr.CustomFunction[V, A, R, P]): ExprInput[V] => G[R] =
- visitGeneric(expr, _)
-
- override def visitDefine[M[_] : Foldable, T](expr: Expr.Define[M, T, P]): ExprInput[V] => G[FactSet] = { input =>
- visitGeneric(expr, input.withValue(input.factTable))
- }
-
- override def visitDivideOutputs[R : Division](expr: Expr.DivideOutputs[V, R, P]): ExprInput[V] => G[R] =
- visitGeneric(expr, _)
-
- override def visitEmbed[R](expr: Expr.Embed[V, R, P]): ExprInput[V] => G[R] =
- visitGeneric(expr, _)
-
- override def visitExistsInOutput[M[_] : Foldable, U](
- expr: Expr.ExistsInOutput[V, M, U, P],
- ): ExprInput[V] => G[Boolean] = visitGeneric(expr, _)
-
- override def visitExponentiateOutputs(expr: Expr.ExponentiateOutputs[V, P]): ExprInput[V] => G[Double] =
- visitGeneric(expr, _)
-
- override def visitFilterOutput[M[_] : Foldable : FunctorFilter, R](
- expr: Expr.FilterOutput[V, M, R, P],
- ): ExprInput[V] => G[M[R]] = visitGeneric(expr, _)
-
- override def visitFlatMapOutput[M[_] : Foldable : FlatMap, U, X](
- expr: Expr.FlatMapOutput[V, M, U, X, P],
- ): ExprInput[V] => G[M[X]] = visitGeneric(expr, _)
-
- override def visitGroupOutput[M[_] : Foldable, U : Order, K](
- expr: Expr.GroupOutput[V, M, U, K, P],
- ): ExprInput[V] => G[MapView[K, Seq[U]]] = visitGeneric(expr, _)
-
- override def visitMapOutput[M[_] : Foldable : Functor, U, R](
- expr: Expr.MapOutput[V, M, U, R, P],
- ): ExprInput[V] => G[M[R]] = visitGeneric(expr, _)
-
- override def visitMultiplyOutputs[R : Multiplication](expr: Expr.MultiplyOutputs[V, R, P]): ExprInput[V] => G[R] =
- visitGeneric(expr, _)
-
- override def visitNegativeOutput[R : Negative](expr: Expr.NegativeOutput[V, R, P]): ExprInput[V] => G[R] =
- visitGeneric(expr, _)
-
- override def visitNot[R : Negation](expr: Expr.Not[V, R, P]): ExprInput[V] => G[R] =
- visitGeneric(expr, _)
-
- override def visitOr[R : Disjunction : ExtractBoolean](expr: Expr.Or[V, R, P]): ExprInput[V] => G[R] =
- visitGeneric(expr, _)
-
- override def visitOutputIsEmpty[M[_] : Foldable, R](
- expr: Expr.OutputIsEmpty[V, M, R, P],
- ): ExprInput[V] => G[Boolean] = visitGeneric(expr, _)
-
- override def visitOutputWithinSet[R](expr: Expr.OutputWithinSet[V, R, P]): ExprInput[V] => G[Boolean] =
- visitGeneric(expr, _)
-
- override def visitOutputWithinWindow[R](expr: Expr.OutputWithinWindow[V, R, P]): ExprInput[V] => G[Boolean] =
- visitGeneric(expr, _)
-
- override def visitFoldOutput[M[_] : Foldable, R : Monoid](expr: Expr.FoldOutput[V, M, R, P]): ExprInput[V] => G[R] =
- visitGeneric(expr, _)
-
- override def visitReturnInput(expr: Expr.ReturnInput[V, P]): ExprInput[V] => G[V] =
- visitGeneric(expr, _)
-
- override def visitSelectFromOutput[S, R](expr: Expr.SelectFromOutput[V, S, R, P]): ExprInput[V] => G[R] =
- visitGeneric(expr, _)
-
- override def visitSortOutput[M[_], R](expr: Expr.SortOutput[V, M, R, P]): ExprInput[V] => G[M[R]] =
- visitGeneric(expr, _)
-
- override def visitSubtractOutputs[R : Subtraction](expr: Expr.SubtractOutputs[V, R, P]): ExprInput[V] => G[R] =
- visitGeneric(expr, _)
-
- override def visitTakeFromOutput[M[_] : Traverse : TraverseFilter, R](
- expr: Expr.TakeFromOutput[V, M, R, P],
- ): ExprInput[V] => G[M[R]] = visitGeneric(expr, _)
-
- override def visitWrapOutputSeq[R](expr: Expr.WrapOutputSeq[V, R, P]): ExprInput[V] => G[Seq[R]] =
- visitGeneric(expr, _)
-
- override def visitUsingDefinitions[R](expr: Expr.UsingDefinitions[V, R, P]): ExprInput[V] => G[R] =
- visitGeneric(expr, _)
-
- override def visitWhen[R](expr: Expr.When[V, R, P]): ExprInput[V] => G[R] =
- visitGeneric(expr, _)
-
- override def visitWithFactsOfType[T, R](expr: Expr.WithFactsOfType[T, R, P]): ExprInput[V] => G[R] = { input =>
- visitGeneric(expr, input.withValue(input.factTable))
- }
-
- override def visitWrapOutput[L, R](expr: Expr.WrapOutput[V, L, R, P]): ExprInput[V] => G[R] =
- visitGeneric(expr, _)
-
- override def visitWrapOutputHList[T <: HList, R](expr: Expr.WrapOutputHList[V, T, R, P]): ExprInput[V] => G[R] =
- visitGeneric(expr, _)
-
- override def visitZipOutput[M[_] : Align : FunctorFilter, L <: HList, R](
- expr: Expr.ZipOutput[V, M, L, R, P],
- ): ExprInput[V] => G[M[R]] = visitGeneric(expr, _)
-}
diff --git a/core/src/main/scala/vapors/lens/NamedLens.scala b/core/src/main/scala/vapors/lens/NamedLens.scala
deleted file mode 100644
index 316f45342..000000000
--- a/core/src/main/scala/vapors/lens/NamedLens.scala
+++ /dev/null
@@ -1,266 +0,0 @@
-package com.rallyhealth.vapors.lens
-
-import cats.arrow.Compose
-import cats.data.NonEmptySet
-import cats.kernel.Semigroup
-import com.rallyhealth.vapors.lens.NamedLens.AsIterableBuilder
-import com.rallyhealth.vapors.v1.lens.IndexedSyntax
-import shapeless.ops.hlist
-import shapeless.{Generic, HList}
-
-import scala.collection.{Factory, MapView, View}
-
-/**
- * @see [[com.rallyhealth.vapors.v1.lens.VariantLens]]
- */
-object NamedLens extends NamedLensLowPriorityImplicits {
-
- /**
- * The type of lens that returns the value it is given.
- */
- type Id[A] = NamedLens[A, A]
-
- /**
- * A singleton implementation of the [[identity]] lens.
- */
- val Id: NamedLens[Any, Any] = NamedLens(DataPath.empty, identity[Any])
-
- /**
- * The only definition of the [[Id]] lens.
- */
- def id[A]: NamedLens[A, A] = Id.asInstanceOf[Id[A]]
-
- /**
- * A function for building a lens from the [[Id]] lens.
- */
- type Fn[A, B] = NamedLens.Id[A] => NamedLens[A, B]
-
- implicit object ComposeInstance extends Compose[NamedLens] {
- override def compose[A, B, C](
- f: NamedLens[B, C],
- g: NamedLens[A, B],
- ): NamedLens[A, C] =
- g.andThen(f)
- }
-
- /**
- * A fancy trick using macros that allows you to access the surrounding context of a method
- * invocation. By wrapping the call with this class, we can access the given [[lens]] to
- * apply the appropriate transformation.
- *
- * @param lens the lens to add the `.select` method to.
- */
- implicit final class Selector[A, B](val lens: NamedLens[A, B]) extends AnyVal {
-
- /**
- * Create a [[NamedLens]] that selects a field based on a given function and applies the appropriate
- * [[com.rallyhealth.vapors.v1.lens.DataPath.atField]] operator.
- *
- * @note this uses a macro and only works for `val`s or `def`s with no arguments.
- *
- * @param getter a function that selects a value of type [[C]] from the return type [[B]] of the current lens
- */
- def select[C](getter: B => C): NamedLens[A, C] = macro NamedLensMacros.selectImpl[A, B, C]
- }
-
- /**
- * If the lens returns a [[IterableOnce]] of 2-tuples, then allow calling operations defined by [[AsMapBuilder]]
- */
- implicit def asMap[A, B, C[x] <: IterableOnce[x], K, E](
- lens: NamedLens[A, B],
- )(implicit
- ev: B <:< C[(K, E)],
- ): AsMapBuilder[A, C, K, E] =
- new AsMapBuilder[A, C, K, E](lens.as[C[(K, E)]])
-
- final class AsMapBuilder[A, C[x] <: IterableOnce[x], K, V](private val lens: NamedLens[A, C[(K, V)]]) extends AnyVal {
-
- /**
- * Returns the right-side of all the 2-tuples as an [[Iterable]] of values.
- */
- def values: NamedLens[A, Iterable[V]] = lens.copy(
- get = lens.get.andThen(_.iterator.to(View).map(_._2)),
- )
-
- /**
- * @see [[AsIterableBuilder.to]] but the values are 2-tuples
- */
- def to[B](factory: Factory[(K, V), B]): NamedLens[A, B] =
- lens.copy(get = lens.get.andThen(factory.fromSpecific(_)))
-
- /**
- * Group the 2-tuples by the left side and create a [[Map]].
- *
- * If there are duplicate keys, then the last entry in the sequence wins the spot and the others are dropped.
- */
- def toMap: NamedLens[A, Map[K, V]] = lens.copy(
- get = lens.get.andThen(Map.from(_)),
- )
-
- /**
- * Same as [[toMap]], but creates a lazy [[MapView]] instead.
- */
- def toMapView: NamedLens[A, MapView[K, V]] = lens.copy(
- get = lens.get.andThen(Map.from(_).view),
- )
- }
-
- // TODO: Make this more generally useful and convert back to a NamedLens implicitly
- final class AsIterableBuilder[A, C[x] <: IterableOnce[x], E](private val lens: NamedLens[A, C[E]]) extends AnyVal {
-
- /**
- * Use the given Scala collection companion object to convert this [[IterableOnce]] into the desired output.
- *
- * TODO: Should there be any path information for conversion?
- * List => Map seems important information as values with duplicate keys could be dropped
- */
- def to[B](factory: Factory[E, B]): NamedLens[A, B] =
- lens.copy(get = lens.get.andThen(factory.fromSpecific(_)))
-
- /**
- * Get the first element of this [[IterableOnce]], if it isn't empty.
- */
- def headOption: NamedLens[A, Option[E]] =
- lens.copy(
- path = lens.path.atHead,
- get = lens.get.andThen(b => View.from[E](b).headOption),
- )
- }
-
- implicit final class AsHListBuilder[A, L <: HList](private val lens: NamedLens[A, L]) extends AnyVal {
-
- /**
- * Convert the resulting [[HList]] into a tuple.
- */
- def tupled[T](implicit tupler: hlist.Tupler.Aux[L, T]): NamedLens[A, T] =
- lens.copy(
- path = lens.path,
- get = lens.get.andThen(tupler.apply),
- )
- }
-}
-
-sealed trait NamedLensLowPriorityImplicits {
-
- /**
- * Wrap the result of this lens with an [[AsIterableBuilder]] for helper operations on [[IterableOnce]] types.
- */
- implicit def asIterable[A, B, C[x] <: IterableOnce[x], E](
- lens: NamedLens[A, B],
- )(implicit
- ev: B <:< C[E],
- ): AsIterableBuilder[A, C, E] =
- new AsIterableBuilder(lens.as[C[E]])
-}
-
-/**
- * @see [[com.rallyhealth.vapors.v1.lens.VariantLens]] for documentation, except this lens is invariant.
- */
-final case class NamedLens[A, B](
- path: DataPath,
- get: A => B,
-) { outer =>
-
- /**
- * Composes another lens to run on the output of this lens.
- *
- * @note Because extension methods don't retain type information well,
- * this is still useful despite the [[Compose]] instance.
- */
- def andThen[C](lens: NamedLens[B, C]): NamedLens[A, C] = {
- copy(
- path = this.path ++ lens.path,
- get = get.andThen(lens.get),
- )
- }
-
- // Helpful for building a tuple with the lens itself. Identical to identity, but you don't have to specify the type.
- def self: NamedLens[A, B] = this
-
- /**
- * Access a field from the object returned by this lens.
- *
- * Typically, you would not call this directly, but instead by calling the [[NamedLens.Selector.select]]
- * extension method on this lens. The `.select` method uses macros to make sure that the `name` param is
- * set properly.
- *
- * @param name the name of the field
- * @param getter a function to extract the value of this field from the object
- * TODO: Use HList to make this more safe, instead of relying on the macro to use this properly.
- */
- def field[C](
- name: String,
- getter: B => C,
- ): NamedLens[A, C] = {
- copy(
- path = path.atField(name),
- get = this.get.andThen(getter),
- )
- }
-
- /**
- * Used for accessing the value for a given key in this object.
- *
- * This requires that there is an [[Indexed]] definition for how to access a value from the
- * indexable object returned by the current lens.
- *
- * @param key either a value of the appropriate key type OR a [[shapeless.Nat]] for accessing a
- * specifically typed value from a tuple or [[HList]]
- */
- def at[K : ValidDataPathKey, V](
- key: K,
- )(implicit
- CI: Indexed[B, K, V],
- ): NamedLens[A, V] = {
- copy(
- path = path.atKey(key),
- get = get.andThen(b => CI.get(b)(key)),
- )
- }
-
- /**
- * Filters the given set of keys from this indexable object.
- *
- * @note Unfortunately this does not work for [[HList]] the same way that [[at]] does.
- *
- * TODO: It may be possible to make this work for tuples / HList with varargs instead of [[NonEmptySet]].
- */
- def filterKeys[K : ValidDataPathKey, V : Semigroup](
- keys: NonEmptySet[K],
- )(implicit
- CI: Indexed[B, K, V],
- ): NamedLens[A, V] = {
- import IndexedSyntax._
- copy(
- path = path.filterKeys(keys),
- get = get.andThen(_.filterKeys(keys)),
- )
- }
-
- /**
- * Upcasts the lens.
- *
- * @note this would not be necessary if [[NamedLens]] used appropriate variance, however, variance for lenses
- * introduces a lot of issues.
- */
- def as[V](implicit ev: B <:< V): NamedLens[A, V] =
- this.copy(get = this.get.andThen(ev))
-
- /**
- * Converts the result into an [[HList]] if possible.
- *
- * Uses recursive implicit resolution at compile-time to derive the appropriate heterogenious return type.
- *
- * @see [[Generic]]
- */
- def asHList[L <: HList](implicit gen: Generic.Aux[B, L]): NamedLens[A, L] = copy(get = this.get.andThen(gen.to))
-
- // TODO: Are these runtime down casts needed? Why not just use .asInstanceOf (with a safe wrapper)
-
- def asIterable[V](implicit ev: B <:< IterableOnce[V]): NamedLens.AsIterableBuilder[A, IterableOnce, V] =
- new NamedLens.AsIterableBuilder(this.copy(get = this.get.andThen(ev)))
-
- def asMap[K, V](implicit ev: B <:< IterableOnce[(K, V)]): NamedLens.AsMapBuilder[A, IterableOnce, K, V] =
- new NamedLens.AsMapBuilder(this.copy(get = this.get.andThen(ev)))
-
-}
diff --git a/core/src/main/scala/vapors/lens/NamedLensMacros.scala b/core/src/main/scala/vapors/lens/NamedLensMacros.scala
deleted file mode 100644
index 257b3f726..000000000
--- a/core/src/main/scala/vapors/lens/NamedLensMacros.scala
+++ /dev/null
@@ -1,53 +0,0 @@
-package com.rallyhealth
-
-package vapors.lens
-
-import vapors.v1.lens.JavaBeanCompat
-
-import scala.annotation.tailrec
-import scala.reflect.macros.blackbox
-
-object NamedLensMacros {
-
- def selectImpl[A : c.WeakTypeTag, B : c.WeakTypeTag, C : c.WeakTypeTag](
- c: blackbox.Context,
- )(
- getter: c.Expr[B => C],
- ): c.Expr[NamedLens[A, C]] = {
- import c.universe._
- val selectChain = getter.tree match {
- case Function(_, rhs) => rhs
- }
- val fieldNames = selectTermNameList(c)(selectChain).map(JavaBeanCompat.unbeanify)
- val fieldNameLiterals = c.Expr[List[String]](q"$fieldNames")
- val dataPathToAppend = reify {
- DataPath(fieldNameLiterals.splice.map(DataPath.Field))
- }
- val lensToAppend = reify {
- NamedLens[B, C](dataPathToAppend.splice, getter.splice)
- }
- reify {
- c.prefix.splice.asInstanceOf[NamedLens.Selector[A, B]].lens.andThen(lensToAppend.splice)
- }
- }
-
- def selectTermNameList(c: blackbox.Context)(tree: c.mirror.universe.Tree): List[String] = {
- import c.universe._
- @tailrec def loop(
- remaining: Tree,
- fields: List[String],
- ): List[String] = remaining match {
- // once we have figured out the target of all of the select operations,
- // ignore the name (probably anonymous anyway) and return the field names
- case Ident(_) => fields
- // strip parameterless method application for Java compat
- case Apply(sub: Select, Nil) => loop(sub, fields)
- // recursive case: selects the term from the result of the given expression
- case Select(init, TermName(last)) => loop(init, last :: fields)
- // if the expression does more than just select or apply zero parameter methods, then stop
- case _ => c.abort(remaining.pos, "Can only extract term names from a chain of vals or parameterless methods")
- }
- loop(tree, Nil)
- }
-
-}
diff --git a/core/src/main/scala/vapors/lens/package.scala b/core/src/main/scala/vapors/lens/package.scala
deleted file mode 100644
index 3780237eb..000000000
--- a/core/src/main/scala/vapors/lens/package.scala
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.rallyhealth
-
-package vapors
-
-package object lens {
-
- type DataPath = v1.lens.DataPath
- final val DataPath = v1.lens.DataPath
-
- type Indexed[C, K, V] = v1.lens.Indexed[C, K, V]
- final val Indexed = v1.lens.Indexed
-
- type ValidDataPathKey[K] = v1.lens.ValidDataPathKey[K]
- final val ValidDataPathKey = v1.lens.ValidDataPathKey
-}
diff --git a/core/src/main/scala/vapors/logic/Conjunction.scala b/core/src/main/scala/vapors/logic/Conjunction.scala
deleted file mode 100644
index 6aeb1a8f7..000000000
--- a/core/src/main/scala/vapors/logic/Conjunction.scala
+++ /dev/null
@@ -1,47 +0,0 @@
-package com.rallyhealth
-
-package vapors.logic
-
-import vapors.interpreter.InterpretExprAsResultFn
-
-import cats.{Invariant, Semigroupal}
-
-/**
- * Defines logical conjunction (aka AND) for a specific type.
- *
- * @see for more details on how this works, check out
- * [[InterpretExprAsResultFn.Output.conjunction]]
- */
-trait Conjunction[A] {
-
- def conjunction(
- lhs: A,
- rhs: A,
- ): A
-}
-
-object Conjunction {
-
- @inline final def apply[A](implicit A: Conjunction[A]): Conjunction[A] = A
-
- implicit final object BooleanConjunction extends Conjunction[Boolean] {
- override def conjunction(
- lhs: Boolean,
- rhs: Boolean,
- ): Boolean = lhs && rhs
- }
-
- implicit final object FunctorInstances extends Invariant[Conjunction] with Semigroupal[Conjunction] {
-
- override def product[A, B](
- fa: Conjunction[A],
- fb: Conjunction[B],
- ): Conjunction[(A, B)] = { (lhs: (A, B), rhs: (A, B)) =>
- (fa.conjunction(lhs._1, rhs._1), fb.conjunction(lhs._2, rhs._2))
- }
-
- override def imap[A, B](fa: Conjunction[A])(f: A => B)(g: B => A): Conjunction[B] = { (lhs: B, rhs: B) =>
- f(fa.conjunction(g(lhs), g(rhs)))
- }
- }
-}
diff --git a/core/src/main/scala/vapors/logic/Disjunction.scala b/core/src/main/scala/vapors/logic/Disjunction.scala
deleted file mode 100644
index 46ae12353..000000000
--- a/core/src/main/scala/vapors/logic/Disjunction.scala
+++ /dev/null
@@ -1,47 +0,0 @@
-package com.rallyhealth
-
-package vapors.logic
-
-import vapors.interpreter.InterpretExprAsResultFn
-
-import cats.{Invariant, Semigroupal}
-
-/**
- * Defines logical disjunction (aka OR) for a specific type.
- *
- * @see for more details on how this works, check out
- * [[InterpretExprAsResultFn.Output.disjunction]]
- */
-trait Disjunction[A] {
-
- def disjunction(
- lhs: A,
- rhs: A,
- ): A
-}
-
-object Disjunction {
-
- @inline final def apply[A](implicit A: Disjunction[A]): Disjunction[A] = A
-
- implicit final object BooleanDisjunction extends Disjunction[Boolean] {
- override def disjunction(
- lhs: Boolean,
- rhs: Boolean,
- ): Boolean = lhs || rhs
- }
-
- implicit final object FunctorInstances extends Invariant[Disjunction] with Semigroupal[Disjunction] {
-
- override def product[A, B](
- fa: Disjunction[A],
- fb: Disjunction[B],
- ): Disjunction[(A, B)] = { (lhs: (A, B), rhs: (A, B)) =>
- (fa.disjunction(lhs._1, lhs._1), fb.disjunction(lhs._2, rhs._2))
- }
-
- override def imap[A, B](fa: Disjunction[A])(f: A => B)(g: B => A): Disjunction[B] = { (lhs: B, rhs: B) =>
- f(fa.disjunction(g(lhs), g(rhs)))
- }
- }
-}
diff --git a/core/src/main/scala/vapors/logic/Negation.scala b/core/src/main/scala/vapors/logic/Negation.scala
deleted file mode 100644
index f5c47d075..000000000
--- a/core/src/main/scala/vapors/logic/Negation.scala
+++ /dev/null
@@ -1,38 +0,0 @@
-package com.rallyhealth
-
-package vapors.logic
-
-import cats.{Invariant, Semigroupal}
-
-/**
- * Defines logical negaction (aka NOT) for a specific type.
- *
- * @see for more details on how this works, check out
- * [[InterpretExprAsResultFn.Output.negation]]
- */
-trait Negation[A] {
- def negation(value: A): A
-}
-
-object Negation {
-
- @inline final def apply[A](implicit A: Negation[A]): Negation[A] = A
-
- implicit final object BooleanNegation extends Negation[Boolean] {
- override def negation(value: Boolean): Boolean = !value
- }
-
- implicit final object InvariantInstances extends Invariant[Negation] with Semigroupal[Negation] {
-
- override def product[A, B](
- fa: Negation[A],
- fb: Negation[B],
- ): Negation[(A, B)] = { value =>
- (fa.negation(value._1), fb.negation(value._2))
- }
-
- override def imap[A, B](fa: Negation[A])(f: A => B)(g: B => A): Negation[B] = { value =>
- f(fa.negation(g(value)))
- }
- }
-}
diff --git a/core/src/main/scala/vapors/math/Addition.scala b/core/src/main/scala/vapors/math/Addition.scala
deleted file mode 100644
index be71a6ece..000000000
--- a/core/src/main/scala/vapors/math/Addition.scala
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.rallyhealth
-
-package vapors.math
-
-/**
- * Defines addition of two values for a specific type.
- */
-trait Addition[A] {
-
- def add(
- lhs: A,
- rhs: A,
- ): A
-}
-
-object Addition extends NumericalImplicits {
-
- def apply[A](implicit A: Addition[A]): Addition[A] = A
-}
diff --git a/core/src/main/scala/vapors/math/Division.scala b/core/src/main/scala/vapors/math/Division.scala
deleted file mode 100644
index 7fb99c599..000000000
--- a/core/src/main/scala/vapors/math/Division.scala
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.rallyhealth
-
-package vapors.math
-
-/**
- * Defines division for a specific type.
- *
- * @note order of arguments matter, as division is not commutative.
- */
-trait Division[A] {
-
- def quot(
- dividend: A,
- divisor: A,
- ): A // quotient = dividend/divisor
-}
-
-object Division extends NumericalImplicits {
- def apply[A](implicit A: Division[A]): Division[A] = A
-}
diff --git a/core/src/main/scala/vapors/math/Multiplication.scala b/core/src/main/scala/vapors/math/Multiplication.scala
deleted file mode 100644
index d8639067c..000000000
--- a/core/src/main/scala/vapors/math/Multiplication.scala
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.rallyhealth
-
-package vapors.math
-
-/**
- * Defines multiplication for a specific type.
- */
-trait Multiplication[A] {
-
- def multiply(
- lhs: A,
- rhs: A,
- ): A
-}
-
-object Multiplication extends NumericalImplicits {
- def apply[A](implicit A: Multiplication[A]): Multiplication[A] = A
-}
diff --git a/core/src/main/scala/vapors/math/Negative.scala b/core/src/main/scala/vapors/math/Negative.scala
deleted file mode 100644
index 45c023069..000000000
--- a/core/src/main/scala/vapors/math/Negative.scala
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.rallyhealth
-
-package vapors.math
-
-/**
- * Defines inverting a single value to it's negative.
- *
- * @note not to be confused with [[com.rallyhealth.vapors.core.logic.Negation]], which is the formal logic
- * definition of negation of the conclusion.
- */
-trait Negative[A] {
-
- def negative(value: A): A
-}
-
-object Negative extends NumericalImplicits {
-
- def apply[A](implicit A: Negative[A]): Negative[A] = A
-}
diff --git a/core/src/main/scala/vapors/math/NumericalImplicits.scala b/core/src/main/scala/vapors/math/NumericalImplicits.scala
deleted file mode 100644
index 36ce9479e..000000000
--- a/core/src/main/scala/vapors/math/NumericalImplicits.scala
+++ /dev/null
@@ -1,61 +0,0 @@
-package com.rallyhealth
-
-package vapors.math
-
-/**
- * Defines default implementations for [[Numeric]]-based arithmetic operators.
- */
-private[math] trait NumericalImplicits {
-
- implicit def integral[A : Integral]: FromIntegral[A] = new FromIntegral[A]
- implicit def fractional[A : Fractional]: FromFractional[A] = new FromFractional[A]
-}
-
-/**
- * Defines all arithmetic type-classes from Scala's [[Numeric]] definition.
- */
-abstract class FromNumeric[A : Numeric]
- extends Addition[A]
- with Subtraction[A]
- with Negative[A]
- with Multiplication[A] {
- import Numeric.Implicits._
-
- override def add(
- lhs: A,
- rhs: A,
- ): A = lhs + rhs
-
- override def subtract(
- lhs: A,
- rhs: A,
- ): A = lhs - rhs
-
- override def negative(value: A): A = -value
-
- override def multiply(
- lhs: A,
- rhs: A,
- ): A = lhs * rhs
-}
-
-/**
- * Defines all arithmetic type-classes from Scala's [[Numeric]] definition.
- */
-final class FromIntegral[A : Integral] extends FromNumeric[A] with Division[A] {
- import Integral.Implicits._
-
- override def quot(
- dividend: A,
- divisor: A,
- ): A = dividend / divisor
-}
-
-final class FromFractional[A : Fractional] extends FromNumeric[A] with Division[A] {
- import Fractional.Implicits._
-
- override def quot(
- dividend: A,
- divisor: A,
- ): A = dividend / divisor
-}
diff --git a/core/src/main/scala/vapors/math/Subtraction.scala b/core/src/main/scala/vapors/math/Subtraction.scala
deleted file mode 100644
index e5f2a23c3..000000000
--- a/core/src/main/scala/vapors/math/Subtraction.scala
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.rallyhealth
-
-package vapors.math
-
-/**
- * Defines subtraction of two values for a specific type.
- *
- * @note order of arguments matter, as subtraction is not commutative.
- */
-trait Subtraction[A] {
-
- def subtract(
- lhs: A,
- rhs: A,
- ): A
-}
-
-object Subtraction extends NumericalImplicits {
-
- def apply[A](implicit A: Subtraction[A]): Subtraction[A] = A
-}
diff --git a/core/src/main/scala/vapors/package.scala b/core/src/main/scala/vapors/package.scala
deleted file mode 100644
index 7a8dc7f88..000000000
--- a/core/src/main/scala/vapors/package.scala
+++ /dev/null
@@ -1,346 +0,0 @@
-package com.rallyhealth
-
-import vapors.algebra.{CaptureP, Expr}
-import vapors.data.{FactTable, TypedFact}
-import vapors.dsl.{ExprBuilderCatsInstances, ExprBuilderSyntax, ExprDsl, WithOutputSyntax}
-
-import shapeless.HList
-
-package object vapors {
-
- // $COVERAGE-OFF$
- object core {
-
- @deprecated("Use com.rallyhealth.vapors.algebra instead.", "0.16.0")
- object algebra {
-
- @deprecated("Use com.rallyhealth.vapors.algebra.CaptureP instead.", "0.16.0")
- final type CaptureP[V, R, P] = vapors.algebra.CaptureP[V, R, P]
-
- @deprecated("Use com.rallyhealth.vapors.algebra.CaptureP instead.", "0.16.0")
- final val CaptureP = vapors.algebra.CaptureP
-
- @deprecated("Use com.rallyhealth.vapors.algebra.Expr instead.", "0.16.0")
- final type Expr[V, R, P] = vapors.algebra.Expr[V, R, P]
-
- @deprecated("Use com.rallyhealth.vapors.algebra.Expr instead.", "0.16.0")
- final val Expr = vapors.algebra.Expr
-
- @deprecated("Use com.rallyhealth.vapors.algebra.ConditionBranch instead.", "0.16.0")
- final type ConditionBranch[V, R, P] = vapors.algebra.ConditionBranch[V, R, P]
-
- @deprecated("Use com.rallyhealth.vapors.algebra.ConditionBranch instead.", "0.16.0")
- final val ConditionBranch = vapors.algebra.ConditionBranch
-
- @deprecated("Use com.rallyhealth.vapors.algebra.ExprConverter instead.", "0.16.0")
- final type ExprConverter[L, R] = vapors.algebra.ExprConverter[L, R]
-
- @deprecated("Use com.rallyhealth.vapors.algebra.ExprConverter instead.", "0.16.0")
- final val ExprConverter = vapors.algebra.ExprConverter
-
- @deprecated("Use com.rallyhealth.vapors.algebra.ExprResult instead.", "0.16.0")
- final type ExprResult[V, R, P] = vapors.algebra.ExprResult[V, R, P]
-
- @deprecated("Use com.rallyhealth.vapors.algebra.ExprResult instead.", "0.16.0")
- final val ExprResult = vapors.algebra.ExprResult
-
- @deprecated("Use com.rallyhealth.vapors.algebra.ExprSorter instead.", "0.16.0")
- final type ExprSorter[M[_], R] = vapors.algebra.ExprSorter[M, R]
-
- @deprecated("Use com.rallyhealth.vapors.algebra.ExprSorter instead.", "0.16.0")
- final val ExprSorter = vapors.algebra.ExprSorter
-
- @deprecated("Use com.rallyhealth.vapors.algebra.NonEmptyExprHList instead.", "0.16.0")
- final type NonEmptyExprHList[V, M[_], L <: HList, P] = vapors.algebra.NonEmptyExprHList[V, M, L, P]
-
- @deprecated("Use com.rallyhealth.vapors.algebra.NonEmptyExprHList instead.", "0.16.0")
- final val NonEmptyExprHList = vapors.algebra.NonEmptyExprHList
- }
-
- @deprecated("Use com.rallyhealth.vapors.data instead.", "0.16.0")
- object data {
-
- @deprecated("Use com.rallyhealth.vapors.data.Bounded instead.", "0.16.0")
- final type Bounded[A] = vapors.data.Bounded[A]
-
- @deprecated("Use com.rallyhealth.vapors.data.Bounded instead.", "0.16.0")
- final val Bounded = vapors.data.Bounded
-
- @deprecated("Use com.rallyhealth.vapors.data.Evidence instead.", "0.16.0")
- final type Evidence = vapors.data.Evidence
-
- @deprecated("Use com.rallyhealth.vapors.data.Evidence instead.", "0.16.0")
- final val Evidence = vapors.data.Evidence
-
- @deprecated("Use com.rallyhealth.vapors.data.ExtractBoolean instead.", "0.16.0")
- final type ExtractBoolean[-T] = vapors.data.ExtractValue[T, Boolean]
-
- @deprecated("Use com.rallyhealth.vapors.data.ExtractBoolean instead.", "0.16.0")
- final val ExtractBoolean = vapors.data.ExtractBoolean
-
- @deprecated("Use com.rallyhealth.vapors.data.ExtractInstant instead.", "0.16.0")
- final type ExtractInstant[-T] = vapors.data.ExtractInstant[T]
-
- @deprecated("Use com.rallyhealth.vapors.data.ExtractInstant instead.", "0.16.0")
- final val ExtractInstant = vapors.data.ExtractInstant
-
- @deprecated("Use com.rallyhealth.vapors.data.ExtractValue instead.", "0.16.0")
- final type ExtractValue[-T, +V] = vapors.data.ExtractValue[T, V]
-
- @deprecated("Use com.rallyhealth.vapors.data.ExtractValue instead.", "0.16.0")
- final val ExtractValue = vapors.data.ExtractValue
-
- @deprecated("Use com.rallyhealth.vapors.data.Fact instead.", "0.16.0")
- final type Fact = vapors.data.Fact
-
- @deprecated("Use com.rallyhealth.vapors.data.Fact instead.", "0.16.0")
- final val Fact = vapors.data.Fact
-
- @deprecated("Use com.rallyhealth.vapors.data.FactSet instead.", "0.16.0")
- final type FactSet = vapors.data.FactSet
-
- @deprecated("Use com.rallyhealth.vapors.data.FactSet instead.", "0.16.0")
- final val FactSet = vapors.data.FactSet
-
- @deprecated("Use com.rallyhealth.vapors.data.FactTable instead.", "0.16.0")
- final type FactTable = vapors.data.FactTable
-
- @deprecated("Use com.rallyhealth.vapors.data.FactTable instead.", "0.16.0")
- final val FactTable = vapors.data.FactTable
-
- @deprecated("Use com.rallyhealth.vapors.data.FactType instead.", "0.16.0")
- final type FactType[T] = vapors.data.FactType[T]
-
- @deprecated("Use com.rallyhealth.vapors.data.FactType instead.", "0.16.0")
- final val FactType = vapors.data.FactType
-
- @deprecated("Use com.rallyhealth.vapors.data.FactType instead.", "0.16.0")
- final type FactTypeSet[A] = vapors.data.FactTypeSet[A]
-
- @deprecated("Use com.rallyhealth.vapors.data.FactTypeSet instead.", "0.16.0")
- final val FactTypeSet = vapors.data.FactTypeSet
-
- @deprecated("Use com.rallyhealth.vapors.data.TimeOrder instead.", "0.16.0")
- final type TimeOrder = vapors.data.TimeOrder
-
- @deprecated("Use com.rallyhealth.vapors.data.TimeOrder instead.", "0.16.0")
- final val TimeOrder = vapors.data.TimeOrder
-
- @deprecated("Use com.rallyhealth.vapors.data.TypedFact instead.", "0.16.0")
- final type TypedFact[A] = vapors.data.TypedFact[A]
-
- @deprecated("Use com.rallyhealth.vapors.data.TypedFact instead.", "0.16.0")
- final val TypedFact = vapors.data.TypedFact
-
- @deprecated("Use com.rallyhealth.vapors.data.TypedFact instead.", "0.16.0")
- final type TypedFactSet[A] = vapors.data.TypedFactSet[A]
-
- @deprecated("Use com.rallyhealth.vapors.data.TypedFact instead.", "0.16.0")
- final val TypedFactSet = vapors.data.TypedFactSet
-
- @deprecated("Use com.rallyhealth.vapors.data.Window instead.", "0.16.0")
- final type Window[A] = vapors.data.Window[A]
-
- @deprecated("Use com.rallyhealth.vapors.data.Window instead.", "0.16.0")
- final val Window = vapors.data.Window
- }
-
- @deprecated("Use com.rallyhealth.vapors.dsl instead.", "0.16.0")
- object dsl extends ExprDsl with ExprBuilderSyntax with WithOutputSyntax with ExprBuilderCatsInstances {
-
- @deprecated("Use com.rallyhealth.vapors.dsl.CondExr instead.", "0.16.0")
- final type CondExpr[V, P] = Expr[V, Boolean, P]
-
- @deprecated("Use com.rallyhealth.vapors.dsl.ValExpr instead.", "0.16.0")
- final type ValExpr[V, R, P] = Expr[V, R, P]
-
- @deprecated("Use com.rallyhealth.vapors.dsl.ValCondExpr instead.", "0.16.0")
- final type ValCondExpr[V, P] = ValExpr[V, Boolean, P]
-
- @deprecated("Use com.rallyhealth.vapors.dsl.RootExpr instead.", "0.16.0")
- final type RootExpr[R, P] = Expr[FactTable, R, P]
-
- @deprecated("Use com.rallyhealth.vapors.dsl.CaptureRootExpr instead.", "0.16.0")
- final type CaptureRootExpr[R, P] = CaptureP[FactTable, R, P]
-
- @deprecated("Use com.rallyhealth.vapors.dsl.CaptureFromFacts instead.", "0.16.0")
- final type CaptureFromFacts[T, P] = CaptureP[Seq[TypedFact[T]], Seq[TypedFact[T]], P]
-
- @deprecated("Use com.rallyhealth.vapors.dsl.ConcatOutputExprBuilder instead.", "0.16.0")
- final type ConcatOutputExprBuilder[V, M[_], R, P] = vapors.dsl.ConcatOutputExprBuilder[V, M, R, P]
-
- @deprecated("Use com.rallyhealth.vapors.dsl.ConcatOutputExprBuilder instead.", "0.16.0")
- final val ConcatOutputExprBuilder = vapors.dsl.ConcatOutputExprBuilder
-
- @deprecated("Use com.rallyhealth.vapors.dsl.ExprBuilder instead.", "0.16.0")
- final type ExprBuilder[V, M[_], U, P] = vapors.dsl.ExprBuilder[V, M, U, P]
-
- @deprecated("Use com.rallyhealth.vapors.dsl.ExprBuilder instead.", "0.16.0")
- final val ExprBuilder = vapors.dsl.ExprBuilder
-
- @deprecated("Use com.rallyhealth.vapors.dsl.FoldableExprBuilder instead.", "0.16.0")
- final type FoldableExprBuilder[V, M[_], U, P] = vapors.dsl.FoldableExprBuilder[V, M, U, P]
-
- @deprecated("Use com.rallyhealth.vapors.dsl.ValExprBuilder instead.", "0.16.0")
- final type ValExprBuilder[V, R, P] = vapors.dsl.ValExprBuilder[V, R, P]
-
- @deprecated("Use com.rallyhealth.vapors.dsl.ExprDsl instead.", "0.16.0")
- final type ExprDsl = vapors.dsl.ExprDsl
-
- @deprecated("Use com.rallyhealth.vapors.dsl.ExprDsl instead.", "0.16.0")
- final val ExprDsl = vapors.dsl.ExprDsl
- }
-
- @deprecated("Use com.rallyhealth.vapors.interpreter instead.", "0.16.0")
- object interpreter {
-
- @deprecated("Use com.rallyhealth.vapors.interpreter.ExprInput instead.", "0.16.0")
- final type ExprInput[V] = vapors.interpreter.ExprInput[V]
-
- @deprecated("Use com.rallyhealth.vapors.interpreter.ExprInput instead.", "0.16.0")
- final val ExprInput = vapors.interpreter.ExprInput
-
- @deprecated("Use com.rallyhealth.vapors.interpreter.ExprOutput instead.", "0.16.0")
- final type ExprOutput[R] = vapors.interpreter.ExprOutput[R]
-
- @deprecated("Use com.rallyhealth.vapors.interpreter.ExprOutput instead.", "0.16.0")
- final val ExprOutput = vapors.interpreter.ExprOutput
-
- @deprecated("Use com.rallyhealth.vapors.interpreter.InterpretExprAsResultFn instead.", "0.16.0")
- final type InterpretExprAsResultFn[V, P] = vapors.interpreter.InterpretExprAsResultFn[V, P]
-
- @deprecated("Use com.rallyhealth.vapors.interpreter.InterpretExprAsResultFn instead.", "0.16.0")
- final val InterpretExprAsResultFn = vapors.interpreter.InterpretExprAsResultFn
-
- @deprecated("Use com.rallyhealth.vapors.interpreter.InterpretExprAsSimpleOutputFn instead.", "0.16.0")
- final type InterpretExprAsSimpleOutputFn[V, P] = vapors.interpreter.InterpretExprAsSimpleOutputFn[V, P]
-
- @deprecated("Use com.rallyhealth.vapors.interpreter.InterpretExprAsSimpleOutputFn instead.", "0.16.0")
- final val InterpretExprAsSimpleOutputFn = vapors.interpreter.InterpretExprAsSimpleOutputFn
-
- @deprecated("Use com.rallyhealth.vapors.interpreter.InterpretExprAsSimpleOutputFn instead.", "0.16.0")
- final type VisitGenericExprWithProxyFn[V, P, G[_]] = vapors.interpreter.VisitGenericExprWithProxyFn[V, P, G]
- }
-
- @deprecated("Use com.rallyhealth.vapors.lens instead.", "0.16.0")
- object lens {
-
- @deprecated("Use com.rallyhealth.vapors.lens.DataPath instead.", "0.16.0")
- final type DataPath = vapors.lens.DataPath
-
- @deprecated("Use com.rallyhealth.vapors.lens.DataPath instead.", "0.16.0")
- final val DataPath = vapors.lens.DataPath
-
- @deprecated("Use com.rallyhealth.vapors.lens.Indexed instead.", "0.16.0")
- final type Indexed[C, K, V] = vapors.lens.Indexed[C, K, V]
-
- @deprecated("Use com.rallyhealth.vapors.lens.Indexed instead.", "0.16.0")
- final val Indexed = vapors.lens.Indexed
-
- @deprecated("Use com.rallyhealth.vapors.lens.NamedLens instead.", "0.16.0")
- final type NamedLens[A, B] = vapors.lens.NamedLens[A, B]
-
- @deprecated("Use com.rallyhealth.vapors.lens.NamedLens instead.", "0.16.0")
- final val NamedLens = vapors.lens.NamedLens
-
- @deprecated("Use com.rallyhealth.vapors.lens.ValidDataPathKey instead.", "0.16.0")
- final type ValidDataPathKey[K] = vapors.lens.ValidDataPathKey[K]
-
- @deprecated("Use com.rallyhealth.vapors.lens.ValidDataPathKey instead.", "0.16.0")
- final val ValidDataPathKey = vapors.lens.ValidDataPathKey
- }
-
- @deprecated("Use com.rallyhealth.vapors.logic instead.", "0.16.0")
- object logic {
-
- @deprecated("Use com.rallyhealth.vapors.logic.Conjunction instead.", "0.16.0")
- final type Conjunction[A] = vapors.logic.Conjunction[A]
-
- @deprecated("Use com.rallyhealth.vapors.logic.Conjunction instead.", "0.16.0")
- final val Conjunction = vapors.logic.Conjunction
-
- @deprecated("Use com.rallyhealth.vapors.logic.Disjunction instead.", "0.16.0")
- final type Disjunction[A] = vapors.logic.Disjunction[A]
-
- @deprecated("Use com.rallyhealth.vapors.logic.Disjunction instead.", "0.16.0")
- final val Disjunction = vapors.logic.Disjunction
-
- @deprecated("Use com.rallyhealth.vapors.logic.Negation instead.", "0.16.0")
- final type Negation[A] = vapors.logic.Negation[A]
-
- @deprecated("Use com.rallyhealth.vapors.logic.Negation instead.", "0.16.0")
- final val Negation = vapors.logic.Negation
- }
-
- @deprecated("Use com.rallyhealth.vapors.math instead.", "0.16.0")
- object math {
-
- @deprecated("Use com.rallyhealth.vapors.math.Addition instead.", "0.16.0")
- final type Addition[A] = vapors.math.Addition[A]
-
- @deprecated("Use com.rallyhealth.vapors.math.Addition instead.", "0.16.0")
- final val Addition = vapors.math.Addition
-
- @deprecated("Use com.rallyhealth.vapors.math.Division instead.", "0.16.0")
- final type Division[A] = vapors.math.Division[A]
-
- @deprecated("Use com.rallyhealth.vapors.math.Division instead.", "0.16.0")
- final val Division = vapors.math.Division
-
- @deprecated("Use com.rallyhealth.vapors.math.Multiplication instead.", "0.16.0")
- final type Multiplication[A] = vapors.math.Multiplication[A]
-
- @deprecated("Use com.rallyhealth.vapors.math.Multiplication instead.", "0.16.0")
- final val Multiplication = vapors.math.Multiplication
-
- @deprecated("Use com.rallyhealth.vapors.math.Negative instead.", "0.16.0")
- final type Negative[A] = vapors.math.Negative[A]
-
- @deprecated("Use com.rallyhealth.vapors.math.Negative instead.", "0.16.0")
- final val Negative = vapors.math.Negative
-
- @deprecated("Use com.rallyhealth.vapors.math.Subtraction instead.", "0.16.0")
- final type Subtraction[A] = vapors.math.Subtraction[A]
-
- @deprecated("Use com.rallyhealth.vapors.math.Subtraction instead.", "0.16.0")
- final val Subtraction = vapors.math.Subtraction
- }
-
- @deprecated("Use com.rallyhealth.vapors.syntax instead.", "0.16.0")
- object syntax {
-
- @deprecated("Use com.rallyhealth.vapors.syntax.all instead.", "0.16.0")
- final val all = vapors.syntax.all
-
- @deprecated("Use com.rallyhealth.vapors.syntax.indexed instead.", "0.16.0")
- final val indexed = vapors.syntax.indexed
-
- @deprecated("Use com.rallyhealth.vapors.syntax.math instead.", "0.16.0")
- final val math = vapors.syntax.math
- }
-
- @deprecated("Use com.rallyhealth.vapors.time instead.", "0.16.0")
- object time {
-
- @deprecated("Use com.rallyhealth.vapors.time.CountTime instead.", "0.16.0")
- final type CountTime[-T, -U] = vapors.time.CountTime[T, U]
-
- @deprecated("Use com.rallyhealth.vapors.time.CountTime instead.", "0.16.0")
- final val CountTime = vapors.time.CountTime
-
- @deprecated("Use com.rallyhealth.vapors.time.ModifyTime instead.", "0.16.0")
- final type ModifyTime[T, -D] = vapors.time.ModifyTime[T, D]
-
- @deprecated("Use com.rallyhealth.vapors.time.ModifyTime instead.", "0.16.0")
- final val ModifyTime = vapors.time.ModifyTime
- }
-
- @deprecated("Use com.rallyhealth.vapors.util instead.", "0.16.0")
- object util {
-
- @deprecated("Use com.rallyhealth.vapors.util.ReflectUtils instead.", "0.16.0")
- final val ReflectUtils = vapors.util.ReflectUtils
- }
- }
- // $COVERAGE-ON$
-}
diff --git a/core/src/main/scala/vapors/syntax/MathSyntax.scala b/core/src/main/scala/vapors/syntax/MathSyntax.scala
deleted file mode 100644
index e6a696672..000000000
--- a/core/src/main/scala/vapors/syntax/MathSyntax.scala
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.rallyhealth
-
-package vapors.syntax
-
-import vapors.math._
-
-trait MathSyntax {
-
- implicit def math[A](value: A): MathOps[A] = new MathOps(value)
-}
-
-final class MathOps[A](private val lhs: A) extends AnyVal {
-
- def +(rhs: A)(implicit A: Addition[A]): A = A.add(lhs, rhs)
-
- def -(rhs: A)(implicit A: Subtraction[A]): A = A.subtract(lhs, rhs)
-
- def unary_-(implicit A: Negative[A]): A = A.negative(lhs)
-
- def *(rhs: A)(implicit A: Multiplication[A]): A = A.multiply(lhs, rhs)
-
- def /(rhs: A)(implicit A: Division[A]): A = A.quot(lhs, rhs)
-}
diff --git a/core/src/main/scala/vapors/syntax/package.scala b/core/src/main/scala/vapors/syntax/package.scala
deleted file mode 100644
index 509ea1305..000000000
--- a/core/src/main/scala/vapors/syntax/package.scala
+++ /dev/null
@@ -1,14 +0,0 @@
-package com.rallyhealth
-
-package vapors
-
-package object syntax {
-
- type IndexedSyntax = vapors.v1.lens.IndexedSyntax
-
- object all extends IndexedSyntax with MathSyntax
-
- object indexed extends IndexedSyntax
-
- object math extends MathSyntax
-}
diff --git a/core/src/main/scala/vapors/time/CountTime.scala b/core/src/main/scala/vapors/time/CountTime.scala
deleted file mode 100644
index 9d2e11dd8..000000000
--- a/core/src/main/scala/vapors/time/CountTime.scala
+++ /dev/null
@@ -1,46 +0,0 @@
-package com.rallyhealth
-
-package vapors.time
-
-import java.time.temporal.{ChronoUnit, Temporal, TemporalUnit}
-
-trait CountTime[-T, -U] {
-
- /**
- * Count the whole number of complete time units between the start and end.
- *
- * @param start the start of the time range (inclusive)
- * @param end the end of the time range (inclusive)
- * @param truncateToUnit the unit to round down to
- * @return the whole number of units between the start up to, but not including, the end
- */
- def between(
- start: T,
- end: T,
- truncateToUnit: U,
- ): Long
-}
-
-object CountTime {
-
- def between[T, U](
- start: T,
- end: T,
- roundDownToUnit: U,
- )(implicit
- diffTime: CountTime[T, U],
- ): Long = diffTime.between(start, end, roundDownToUnit)
-
- private final class OfTemporal[-T <: Temporal] extends CountTime[T, TemporalUnit] {
- override def between(
- start: T,
- end: T,
- unit: TemporalUnit,
- ): Long = start.until(end, unit)
- }
-
- @inline private def temporal[T <: Temporal]: CountTime[T, ChronoUnit] = new OfTemporal[T]
-
- // TODO: Restrict invalid units by type
- implicit val ofTemporal: CountTime[Temporal, ChronoUnit] = temporal
-}
diff --git a/core/src/main/scala/vapors/time/ModifyTime.scala b/core/src/main/scala/vapors/time/ModifyTime.scala
deleted file mode 100644
index 4139b33ef..000000000
--- a/core/src/main/scala/vapors/time/ModifyTime.scala
+++ /dev/null
@@ -1,67 +0,0 @@
-package com.rallyhealth
-
-package vapors.time
-
-import java.time.temporal.{Temporal, TemporalAmount}
-import java.time._
-
-/**
- * Defines the capability of adding or subtracting an amount of time to a temporal moment.
- */
-trait ModifyTime[T, -D] {
-
- /**
- * Add a positive or negative temporal amount to a temporal moment.
- */
- def addTo(
- temporal: T,
- amount: D,
- ): T
-}
-
-object ModifyTime {
-
- def addTo[T, D](
- temporal: T,
- amount: D,
- )(implicit
- modifier: ModifyTime[T, D],
- ): T = modifier.addTo(temporal, amount)
-
- private final class OfTemporal[T <: Temporal, -D <: TemporalAmount] extends ModifyTime[T, D] {
- override def addTo(
- temporal: T,
- amount: D,
- ): T = amount.addTo(temporal).asInstanceOf[T]
- }
-
- @inline private def temporal[T <: Temporal, D <: TemporalAmount]: ModifyTime[T, D] = new OfTemporal[T, D]
-
- /**
- * Allows adding a [[Duration]] to a [[Instant]].
- *
- * An [[Instant]] does not support adding or subtracting year, month, or day [[Period]]s.
- */
- implicit val ofInstant: ModifyTime[Instant, Duration] = temporal
-
- /**
- * Allows adding a [[Period]] to a [[LocalDate]].
- *
- * A [[LocalDate]] does not support adding or subtracting nanosecond, minute, hour, etc [[Duration]]s.
- */
- implicit val ofLocalDate: ModifyTime[LocalDate, Period] = temporal
-
- /**
- * Allows adding any [[TemporalAmount]] to a [[LocalDateTime]].
- *
- * A [[LocalDateTime]] supports adding or subtracting time [[Duration]]s as well as date [[Period]]s.
- */
- implicit val ofLocalDateTime: ModifyTime[LocalDateTime, TemporalAmount] = temporal
-
- /**
- * Allows adding any [[TemporalAmount]] to a [[ZonedDateTime]].
- *
- * A [[ZonedDateTime]] supports adding or subtracting time [[Duration]]s as well as date [[Period]]s.
- */
- implicit val ofZonedDateTime: ModifyTime[ZonedDateTime, TemporalAmount] = temporal
-}
diff --git a/core/src/main/scala/vapors/util/ReflectUtils.scala b/core/src/main/scala/vapors/util/ReflectUtils.scala
deleted file mode 100644
index 84b5cd3e7..000000000
--- a/core/src/main/scala/vapors/util/ReflectUtils.scala
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.rallyhealth
-
-package vapors.util
-
-import scala.reflect.runtime.universe.{typeOf, TypeTag}
-
-object ReflectUtils {
-
- /**
- * Returns the full class name or type name but with the package path removed.
- *
- * Specifically, it removes all portions of the path that start with a lowercase letter.
- * This is to work better with enumeration types and inner classes. It is a simple heuristic
- * (albeit, an arbitrary one), so if you want the type name to include the surrounding object
- * name, that object needs to start with a capital letter.
- */
- def typeNameOf[T : TypeTag]: String = typeOf[T].toString.split('.').dropWhile(_.charAt(0).isLower).mkString(".")
-}
diff --git a/core/src/test/scala/vapors/algebra/CapturePSpec.scala b/core/src/test/scala/vapors/algebra/CapturePSpec.scala
deleted file mode 100644
index 1a7a1b2fc..000000000
--- a/core/src/test/scala/vapors/algebra/CapturePSpec.scala
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.rallyhealth
-
-package vapors.algebra
-
-import vapors.data.Evidence
-import vapors.dsl._
-import vapors.example.{FactTypes, JoeSchmoe, TimeRange}
-
-import org.scalactic.TypeCheckedTripleEquals
-import org.scalatest.wordspec.AnyWordSpec
-
-class CapturePSpec extends AnyWordSpec with TypeCheckedTripleEquals {
-
- "CaptureP" should {
-
- "capture a timestamp range post processing param" should {
-
- import vapors.example.CaptureTimeRange._
-
- "find a single fact from a query" in {
- val q = factsOfType(FactTypes.WeightMeasurement).exists {
- _.get(_.select(_.value.value)) > 18.0
- }
- val result = eval(JoeSchmoe.factTable)(q)
- assert(result.param.value === TimeRange(JoeSchmoe.weight.value.timestamp))
- assert(result.output.value)
- assert(result.output.evidence.nonEmpty)
- assertResult(Evidence(JoeSchmoe.weight))(result.output.evidence)
- }
- }
- }
-}
diff --git a/core/src/test/scala/vapors/data/FactTableSpec.scala b/core/src/test/scala/vapors/data/FactTableSpec.scala
deleted file mode 100644
index 853efb0d7..000000000
--- a/core/src/test/scala/vapors/data/FactTableSpec.scala
+++ /dev/null
@@ -1,39 +0,0 @@
-package com.rallyhealth
-
-package vapors.data
-
-import vapors.example.{FactTypes, GenericMeasurement}
-
-import org.scalatest.wordspec.AnyWordSpec
-
-import java.time.Instant
-
-class FactTableSpec extends AnyWordSpec {
-
- "FactTable" when {
-
- "given facts that have the same value sort order" should {
- val now = Instant.now()
- val measurementsAtSameTime = Seq(
- GenericMeasurement("systolic", 120, "mmHg", now),
- GenericMeasurement("diastolic", 80, "mmHg", now),
- ).map(FactTypes.GenericMeasurement(_))
- val unsortedMeasurements = measurementsAtSameTime.toSet
- // GenericMeasurements are only sorted by timestamp, so these should all produce a comparison of 0
- val sortedMeasurements =
- measurementsAtSameTime.sorted(TypedFact.orderTypedFactByValue[GenericMeasurement].toOrdering)
-
- "not use that Order instance to remove duplicates" in {
- assertResult(unsortedMeasurements) {
- FactTable(measurementsAtSameTime).getSet(FactTypes.GenericMeasurement)
- }
- }
-
- "return the results as a Seq in the expected sort order" in {
- assertResult(sortedMeasurements) {
- FactTable(measurementsAtSameTime).getSortedSeq(FactTypes.GenericMeasurement)
- }
- }
- }
- }
-}
diff --git a/core/src/test/scala/vapors/data/WindowSpec.scala b/core/src/test/scala/vapors/data/WindowSpec.scala
deleted file mode 100644
index 29ccdbaca..000000000
--- a/core/src/test/scala/vapors/data/WindowSpec.scala
+++ /dev/null
@@ -1,242 +0,0 @@
-package com.rallyhealth
-
-package vapors.data
-
-import cats.Order
-import org.scalacheck.Arbitrary
-import org.scalacheck.ops._
-import org.scalactic.Equivalence
-import org.scalatest.wordspec.AnyWordSpec
-import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks._
-
-import java.time.{LocalDate, LocalDateTime, LocalTime, ZonedDateTime}
-import scala.collection.immutable.NumericRange
-import scala.reflect.runtime.universe.{typeOf, TypeTag}
-
-class WindowSpec extends AnyWordSpec {
-
- class BoundedWindowTests[A : Arbitrary : Order](buildWindow: (A, A) => Window[A]) {
- import cats.syntax.order._
-
- private def assertWithBoundedWindow(
- testLowerBound: (Window[A], A) => Unit = (_, _) => (),
- testUpperBound: (Window[A], A) => Unit = (_, _) => (),
- ): Unit = {
- forAll { (a1: A, a2: A) =>
- whenever(a1 != a2) {
- val lowerBound = a1 min a2
- val upperBound = a1 max a2
- val window = buildWindow(lowerBound, upperBound)
- testLowerBound(window, lowerBound)
- testUpperBound(window, upperBound)
- }
- }
- }
-
- def itIsABoundedWindow(
- includeMin: Boolean,
- includeMax: Boolean,
- ): Unit = {
- "return true for contains when the value is inside the bounds" in {
- forAll { (a1: A, a2: A, v: A) =>
- whenever(a1 != a2 && v != a1 && v != a2) {
- val lowerBound = a1 min a2
- val upperBound = a1 max a2
- val window = buildWindow(lowerBound, upperBound)
- if (v < upperBound && v > lowerBound) {
- assert(window.contains(v))
- } else {
- assert(!window.contains(v))
- }
- }
- }
- }
-
- if (includeMin) {
- itIsAStartInclusiveWindow()
- } else {
- itIsAStartExclusiveWindow()
- }
- if (includeMax) {
- itIsAnEndInclusiveWindow()
- } else {
- itIsAnEndExclusiveWindow()
- }
- }
-
- def itIsAStartExclusiveWindow(): Unit = {
- "be exclusive in the lower bound" in {
- assertWithBoundedWindow(
- testLowerBound = (window, lowerBound) => assert(!window.contains(lowerBound)),
- )
- }
- }
-
- def itIsAStartInclusiveWindow(): Unit = {
- "be inclusive in the lower bound" in {
- assertWithBoundedWindow(
- testLowerBound = (window, lowerBound) => assert(window.contains(lowerBound)),
- )
- }
- }
-
- def itIsAnEndExclusiveWindow(): Unit = {
- "be exclusive in the upper bound" in {
- assertWithBoundedWindow(
- testUpperBound = (window, upperBound) => assert(!window.contains(upperBound)),
- )
- }
- }
-
- def itIsAnEndInclusiveWindow(): Unit = {
- "be inclusive in the upper bound" in {
- assertWithBoundedWindow(
- testUpperBound = (window, upperBound) => assert(window.contains(upperBound)),
- )
- }
- }
- }
-
- "Window" when {
-
- "fromRange() is given a standard Int Range" when {
-
- "exclusive (X until Y)" should {
- val tests = new BoundedWindowTests[Int]((min, max) => Window.fromRange(min until max))
- behave like tests.itIsABoundedWindow(
- includeMin = true,
- includeMax = false,
- )
- }
-
- "inclusive (X to Y)" should {
- val tests = new BoundedWindowTests[Int]((min, max) => Window.fromRange(min to max))
- tests.itIsABoundedWindow(
- includeMin = true,
- includeMax = true,
- )
- }
- }
-
- def aNumericRangeIgnoringStepSize[A : Integral : Arbitrary : Equivalence](): Unit = {
- val I = Integral[A]
- implicit val A: Order[A] = Order.fromOrdering
- val step2 = I.plus(I.one, I.one)
-
- "exclusive" should {
- val exclusiveRange = new BoundedWindowTests[A](
- (min, max) => Window.fromRange(NumericRange(min, max, step2)),
- )
- exclusiveRange.itIsABoundedWindow(includeMin = true, includeMax = false)
- }
-
- "inclusive" should {
- val inclusiveRange = new BoundedWindowTests[A](
- (min, max) => Window.fromRange(NumericRange.inclusive(min, max, step2)),
- )
- inclusiveRange.itIsABoundedWindow(includeMin = true, includeMax = true)
- }
- }
-
- "fromRange() is given an Int NumericRange" when {
- behave like aNumericRangeIgnoringStepSize[Int]()
- }
-
- "fromRange() is given a Long NumericRange" when {
- behave like aNumericRangeIgnoringStepSize[Long]()
- }
-
- def allWindowTests[A : Arbitrary : Ordering : TypeTag](): Unit = {
- implicit val order: Order[A] = Order.fromOrdering
- val typeName = typeOf[A].toString
-
- s"given values of type $typeName" when {
-
- "between()" should {
- val tests = new BoundedWindowTests[A](
- (min, max) => Window.between(min, max),
- )
- behave like tests.itIsABoundedWindow(
- includeMin = true,
- includeMax = false,
- )
- }
-
- "betweenInclusive()" should {
- val tests = new BoundedWindowTests[A](
- (min, max) => Window.betweenInclusive(min, max),
- )
- behave like tests.itIsABoundedWindow(
- includeMin = true,
- includeMax = true,
- )
- }
-
- "between() is called given includeMin and includeMax set to false" should {
- val tests = new BoundedWindowTests[A](
- (min, max) => Window.between(min, includeMin = false, max, includeMax = false),
- )
- behave like tests.itIsABoundedWindow(
- includeMin = false,
- includeMax = false,
- )
- }
-
- "between() is called given includeMin set to false and includeMax set to true" should {
- val tests = new BoundedWindowTests[A](
- (min, max) => Window.between(min, includeMin = false, max, includeMax = true),
- )
- behave like tests.itIsABoundedWindow(
- includeMin = false,
- includeMax = true,
- )
- }
-
- def assertContainsValue(
- createWindow: A => Window[A],
- chooseBoundary: (A, A) => A,
- inclusive: Boolean,
- ): Unit = {
- forAll { (a1: A, a2: A) =>
- whenever(inclusive || a1 != a2) {
- val boundary = chooseBoundary(a1, a2)
- val window = createWindow(boundary)
- val value = if (a1 === boundary) a2 else a1
- assert(window.contains(value))
- if (inclusive) {
- assert(window.contains(boundary))
- }
- }
- }
- }
-
- import cats.syntax.order._
-
- "greaterThan() contains a value greaterThan a given window boundary" in {
- assertContainsValue(Window.greaterThan(_), _ min _, inclusive = false)
- }
-
- "greaterThanOrEqual() contains a value greaterThanOrEqualTo a given window boundary" in {
- assertContainsValue(Window.greaterThanOrEqual(_), _ min _, inclusive = true)
- }
-
- "lessThan() contains a value lessThan a given window boundary" in {
- assertContainsValue(Window.lessThan(_), _ max _, inclusive = false)
- }
-
- "lessThanOrEqual() contains a value lessThanOrEqualTo a given window boundary" in {
- assertContainsValue(Window.lessThanOrEqual(_), _ max _, inclusive = true)
- }
- }
- }
-
- locally {
- allWindowTests[Int]()
- allWindowTests[Long]()
- allWindowTests[LocalDate]()
- allWindowTests[LocalTime]()
- allWindowTests[LocalDateTime]()
- allWindowTests[ZonedDateTime]()
- }
- }
-}
diff --git a/core/src/test/scala/vapors/dsl/ExprBuilderSpec.scala b/core/src/test/scala/vapors/dsl/ExprBuilderSpec.scala
deleted file mode 100644
index 40c90ff5e..000000000
--- a/core/src/test/scala/vapors/dsl/ExprBuilderSpec.scala
+++ /dev/null
@@ -1,58 +0,0 @@
-package com.rallyhealth
-
-package vapors.dsl
-
-import vapors.algebra.Expr
-import vapors.example.{FactTypes, GenericMeasurement, Probs}
-import vapors.lens.DataPath
-
-import org.scalatest.Inside.inside
-import org.scalatest.matchers.should.Matchers._
-import org.scalatest.wordspec.AnyWordSpec
-
-import java.time.Instant
-
-class ExprBuilderSpec extends AnyWordSpec {
-
- "ValExprBuilder" should {
-
- "combine lenses from chained .get() methods" in {
- val q = factsOfType(FactTypes.GenericMeasurement).exists {
- _.get(_.select(_.value)).get(_.select(_.value)) > 0.0
- }.returnOutput
- inside(q) {
- case Expr.ExistsInOutput(_, condExpr, _) =>
- inside(condExpr) {
- case Expr.OutputWithinWindow(Expr.SelectFromOutput(_, valueLens, _), _, _) =>
- assertResult(DataPath.empty.atField("value").atField("value")) {
- valueLens.path
- }
- val fact = FactTypes.GenericMeasurement(GenericMeasurement("core/exampleample", 1.0, "m", Instant.now()))
- assertResult(fact.value.value) {
- valueLens.get(fact)
- }
- }
- }
- }
-
- "combine lenses from .get() and .getFoldable() methods" in {
- val q = factsOfType(FactTypes.ProbabilityToUse).exists {
- _.get(_.select(_.value)).getFoldable(_.select(_.scores)).isEmpty
- }.returnOutput
- inside(q) {
- case Expr.ExistsInOutput(_, condExpr, _) =>
- inside(condExpr) {
- case Expr.OutputIsEmpty(Expr.SelectFromOutput(_, valueLens, _), _) =>
- assertResult(DataPath.empty.atField("value").atField("scores")) {
- valueLens.path
- }
- val fact = FactTypes.ProbabilityToUse(Probs(Map()))
- assertResult(fact.value.scores) {
- valueLens.get(fact)
- }
- }
- }
- }
- }
-
-}
diff --git a/core/src/test/scala/vapors/example/CaptureTimeRange.scala b/core/src/test/scala/vapors/example/CaptureTimeRange.scala
deleted file mode 100644
index fdf5f25f3..000000000
--- a/core/src/test/scala/vapors/example/CaptureTimeRange.scala
+++ /dev/null
@@ -1,81 +0,0 @@
-package com.rallyhealth
-
-package vapors.example
-
-import vapors.algebra.{CaptureP, Expr}
-import vapors.data.{ExtractInstant, TypedFact}
-import vapors.interpreter.{ExprInput, ExprOutput}
-
-import cats.{Eval, Monoid}
-
-import java.time.Instant
-
-object CaptureTimeRange extends CaptureP.AsMonoidCompanion[TimeRange] {
-
- implicit def captureTimeRangeFromFacts[T : ExtractInstant, R]: CaptureP.AsMonoidFromFactsOfType[T, R, TimeRange] = {
- new CaptureP.AsMonoidFromFactsOfType[T, R, TimeRange] {
-
- override protected def foldWithParentParam(
- expr: Expr[Seq[TypedFact[T]], R, TimeRange],
- input: ExprInput[Seq[TypedFact[T]]],
- output: ExprOutput[R],
- processedChildren: TimeRange,
- ): Eval[TimeRange] = {
- val timestamps = input.value.map(fact => ExtractInstant[T].extractValue(fact.value))
- Eval.now(TimeRange.fromIterable(timestamps))
- }
- }
- }
-}
-
-/**
- * A range of time that tracks the start and end of the range, without any concern for the values inbetween.
- *
- * @param min the earliest timestamp in the evaluated expression
- * @param max the oldest timestamp in the evaluated expression
- */
-final case class TimeRange private (
- min: Option[Instant],
- max: Option[Instant],
-) {
-
- /**
- * Build a new [[TimeRange]] from the earliest start and latest end time of both the given range and this.
- */
- def expand(that: TimeRange): TimeRange =
- if (this eq TimeRange.empty) that
- else if (that eq TimeRange.empty) this
- else TimeRange.fromIterable(Array(this.min, that.min, this.max, that.max).flatten[Instant])
-}
-
-object TimeRange {
-
- final val empty = TimeRange(None, None)
-
- @inline final def apply(): TimeRange = empty
-
- def apply(one: Instant): TimeRange = TimeRange(Some(one), Some(one))
-
- def apply(
- min: Instant,
- max: Instant,
- ): TimeRange = TimeRange(Some(min), Some(max))
-
- def fromIterable(many: Iterable[Instant]): TimeRange = {
- if (many.isEmpty) empty
- else {
- val sorted = Array.from(many).sortInPlace()
- TimeRange(sorted.headOption, sorted.lastOption)
- }
- }
-
- implicit val monoid: Monoid[TimeRange] = {
- new Monoid[TimeRange] {
- override def empty: TimeRange = TimeRange.empty
- override def combine(
- x: TimeRange,
- y: TimeRange,
- ): TimeRange = x.expand(y)
- }
- }
-}
diff --git a/core/src/test/scala/vapors/example/FactTypes.scala b/core/src/test/scala/vapors/example/FactTypes.scala
deleted file mode 100644
index dd1c3cdfd..000000000
--- a/core/src/test/scala/vapors/example/FactTypes.scala
+++ /dev/null
@@ -1,34 +0,0 @@
-package com.rallyhealth
-
-package vapors.example
-
-import vapors.data.{FactType, FactTypeSet}
-
-import java.time.LocalDate
-
-object FactTypes {
-
- // Order all time-based facts by latest first
- import vapors.data.TimeOrder.LatestFirst._
-
- val Name = FactType[String]("name")
- val Age = FactType[Int]("age")
- val Role = FactType[Role]("role")
- val BirthYear = FactType[Int]("year_of_birth")
- val DateOfBirth = FactType[LocalDate]("date_of_birth")
- val AddressUpdate = FactType[AddressUpdate]("address_update")
- val GenericMeasurement = FactType[GenericMeasurement]("generic_measurement")
- val WeightMeasurement = FactType[WeightMeasurementLbs]("weight_measurement")
- val WeightSelfReported = FactType[WeightMeasurementLbs]("weight_self_reported")
- val BloodPressureMeasurement = FactType[BloodPressure]("blood_pressure")
- val Tag = FactType[String]("tag")
- val TagsUpdate = FactType[TagsUpdate]("tags_update")
- val ProbabilityToUse = FactType[Probs]("probability_to_use")
- val TempFahrenheit = FactType[Double]("temp_fahrenheit")
- val TempCelcius = FactType[Double]("temp_celcius")
-}
-
-object FactTypeSets {
- import FactTypes._
- val Weight = FactTypeSet.of(WeightMeasurement, WeightSelfReported)
-}
diff --git a/core/src/test/scala/vapors/example/GeneratedUser.scala b/core/src/test/scala/vapors/example/GeneratedUser.scala
deleted file mode 100644
index b3d5d3fb2..000000000
--- a/core/src/test/scala/vapors/example/GeneratedUser.scala
+++ /dev/null
@@ -1,25 +0,0 @@
-package com.rallyhealth
-
-package vapors.example
-
-import vapors.data.FactTable
-
-import org.scalacheck.Gen
-import org.scalacheck.rng.Seed
-
-abstract class GeneratedUser {
-
- val name: String = getClass.getSimpleName.filterNot(Set('$'))
-
- val seed: Seed = Seed(name.##)
-
- lazy val factTable: FactTable =
- FactTable(Generators.genFact.pureApply(GeneratedUser.scalaCheckParams, seed))
-}
-
-object GeneratedUser {
-
- val scalaCheckParams: Gen.Parameters = Gen.Parameters.default
- .withInitialSeed(7)
- .withSize(7)
-}
diff --git a/core/src/test/scala/vapors/example/Generators.scala b/core/src/test/scala/vapors/example/Generators.scala
deleted file mode 100644
index 4b650fd80..000000000
--- a/core/src/test/scala/vapors/example/Generators.scala
+++ /dev/null
@@ -1,40 +0,0 @@
-package com.rallyhealth
-
-package vapors.example
-
-import vapors.data.Fact
-
-import org.scalacheck.Gen
-import org.scalacheck.ops._
-
-import java.time.Instant
-
-object Generators {
-
- lazy val genSmallId: Gen[String] = for {
- chars <- Gen.stringOfN(1, Gen.alphaUpperChar)
- nums <- Gen.stringOfN(2, Gen.numChar)
- } yield chars + nums
-
- lazy val genMusicalNote: Gen[Char] = Gen.choose('A', 'G')
-
- lazy val genMusicalNoteOrEmpty: Gen[String] = Gen.option(Gen.stringOfN(1, genMusicalNote)).map(_.getOrElse(""))
-
- lazy val genTimestampWithin90Days: Gen[Instant] = Gen.javaInstant.beforeNowWithin(java.time.Duration.ofDays(90))
-
- def genTagsSource: Gen[String] = genMusicalNoteOrEmpty
-
- lazy val genTags: Gen[Set[String]] = Gen.setOf(genSmallId)
-
- lazy val genTagsUpdate: Gen[TagsUpdate] = for {
- source <- genTagsSource
- tags <- genTags
- timestamp <- genTimestampWithin90Days
- } yield TagsUpdate(
- source,
- tags,
- timestamp,
- )
-
- lazy val genFact: Gen[Fact] = genTagsUpdate.map(FactTypes.TagsUpdate)
-}
diff --git a/core/src/test/scala/vapors/example/JoeSchmoe.scala b/core/src/test/scala/vapors/example/JoeSchmoe.scala
deleted file mode 100644
index 0ccacfd40..000000000
--- a/core/src/test/scala/vapors/example/JoeSchmoe.scala
+++ /dev/null
@@ -1,51 +0,0 @@
-package com.rallyhealth
-
-package vapors.example
-
-import vapors.data.{FactSet, FactTable}
-
-import java.time.{Instant, LocalDate, ZoneOffset}
-
-object JoeSchmoe {
- val name = FactTypes.Name("Joe Schmoe")
- val age = FactTypes.Age(32)
- val userRole = FactTypes.Role(Role.User)
- val adminRole = FactTypes.Role(Role.Admin)
- val dateOfBirth = FactTypes.DateOfBirth(LocalDate.of(1988, 8, 8))
-
- val lastAddressUpdate = FactTypes.AddressUpdate(
- AddressUpdate(
- Address("123 elm", "", "Springfield", "CO", "81073"),
- Instant.from(LocalDate.of(2018, 3, 12).atStartOfDay(ZoneOffset.UTC)),
- ),
- )
-
- val weight = FactTypes.WeightMeasurement(
- WeightMeasurementLbs(250.0, LocalDate.of(2020, 5, 1).atStartOfDay().toInstant(ZoneOffset.UTC)),
- )
-
- val weightSelfReported = FactTypes.WeightSelfReported(
- WeightMeasurementLbs(240.0, LocalDate.of(2019, 1, 30).atStartOfDay().toInstant(ZoneOffset.UTC)),
- )
-
- val bloodPressure = FactTypes.BloodPressureMeasurement(
- BloodPressure(120, 80, LocalDate.of(2020, 5, 1).atStartOfDay().toInstant(ZoneOffset.UTC)),
- )
-
- val probs = FactTypes.ProbabilityToUse(Probs(Map("weightloss" -> .8)))
- val asthmaTag = FactTypes.Tag("asthma")
-
- val facts = FactSet(
- name,
- age,
- adminRole,
- userRole,
- weight,
- weightSelfReported,
- bloodPressure,
- probs,
- asthmaTag,
- )
-
- val factTable = FactTable(facts.toList)
-}
diff --git a/core/src/test/scala/vapors/example/SimpleTagUpdates.scala b/core/src/test/scala/vapors/example/SimpleTagUpdates.scala
deleted file mode 100644
index 853f900c0..000000000
--- a/core/src/test/scala/vapors/example/SimpleTagUpdates.scala
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.rallyhealth
-
-package vapors.example
-
-import java.time.Instant
-
-object SimpleTagUpdates {
-
- private val now = Instant.now()
- final val tagsNow = TagsUpdate("xSource", Set("X1", "X2"), now)
- final val tags5MinAgo = TagsUpdate("ySource", Set("Y1"), now.minusSeconds(5 * 60))
- final val tags15MinAgo = TagsUpdate("zSource", Set("Z1"), now.minusSeconds(15 * 60))
-}
diff --git a/core/src/test/scala/vapors/example/Snippets.scala b/core/src/test/scala/vapors/example/Snippets.scala
deleted file mode 100644
index 5d14e102a..000000000
--- a/core/src/test/scala/vapors/example/Snippets.scala
+++ /dev/null
@@ -1,58 +0,0 @@
-package com.rallyhealth
-
-package vapors.example
-
-import vapors.algebra.Expr
-import vapors.data.{FactTable, FactType}
-import vapors.dsl._
-
-import cats.Id
-
-import java.time._
-import java.time.temporal.ChronoUnit
-
-class Snippets(val clock: Clock) {
-
- def this(fixedInstant: Instant) = this(Clock.fixed(fixedInstant, ZoneOffset.UTC))
-
- def this(fixedLocalDate: LocalDate) =
- this(Clock.fixed(fixedLocalDate.atStartOfDay(ZoneId.systemDefault()).toInstant, ZoneId.systemDefault()))
-
- val ageFromDateOfBirth: Expr[FactTable, Seq[Int], Unit] = {
- valuesOfType(FactTypes.DateOfBirth).map { dob =>
- val ageInYears = dateDiff(
- dob,
- dob.embedResult(today(clock)),
- dob.embedConst(ChronoUnit.YEARS),
- )
- ageInYears.withOutputValue.get(_.select(_.toInt))
- }
- }
-
- val ageFromDateOfBirthDef: Expr.Definition[Unit] = {
- define(FactTypes.Age).fromEvery {
- ageFromDateOfBirth
- }
- }
-
- val isOver18: RootExpr[Boolean, Unit] = {
- usingDefinitions(ageFromDateOfBirthDef) {
- factsOfType(FactTypes.Age).exists {
- _.value >= 18
- }
- }
- }
-
- lazy val isUser: RootExpr[Boolean, Unit] = {
- factsOfType(FactTypes.Role).exists {
- _.value >= Role.User
- }
- }
-
- val isEligible: RootExpr[Boolean, Unit] = and(isOver18, isUser)
-
- val isEligibleDef: Expr.Define[Id, Boolean, Unit] =
- define(FactType[Boolean]("is_eligible")).from(isEligible)
-}
-
-object Snippets extends Snippets(Clock.systemDefaultZone())
diff --git a/core/src/test/scala/vapors/example/Tags.scala b/core/src/test/scala/vapors/example/Tags.scala
deleted file mode 100644
index 07914bce2..000000000
--- a/core/src/test/scala/vapors/example/Tags.scala
+++ /dev/null
@@ -1,11 +0,0 @@
-package com.rallyhealth
-
-package vapors.example
-
-object Tags {
- val asthma = FactTypes.Tag("asthma")
- val obeseBmi = FactTypes.Tag("obese_bmi")
- val normalBmi = FactTypes.Tag("normal_bmi")
- val smoker = FactTypes.Tag("smoker")
- val nonSmoker = FactTypes.Tag("non_smoker")
-}
diff --git a/core/src/test/scala/vapors/example/models.scala b/core/src/test/scala/vapors/example/models.scala
deleted file mode 100644
index b08940656..000000000
--- a/core/src/test/scala/vapors/example/models.scala
+++ /dev/null
@@ -1,101 +0,0 @@
-package com.rallyhealth
-
-package vapors.example
-
-import vapors.data.TimeOrder.LatestFirst._
-import vapors.data._
-
-import cats.Order
-
-import java.time.Instant
-
-final case class Probs(scores: Map[String, Double])
-
-object Probs {
- implicit val order: Order[Probs] = Order.whenEqual(
- Order.reverse(Order.by(_.scores.size)),
- Order.by(_.scores.toSeq),
- )
-}
-
-sealed trait Role
-
-object Role {
- case object Admin extends Role
- case object User extends Role
-
- implicit val order: Order[Role] = Order.reverse {
- Order.by[Role, Int] {
- case Admin => 1
- case User => 2
- }
- }
-}
-
-sealed trait ColorCoding
-
-object ColorCoding {
- final case object Red extends ColorCoding
- final case object Green extends ColorCoding
- final case object Blue extends ColorCoding
-}
-
-trait HasTimestamp {
- def timestamp: Instant
-}
-
-object HasTimestamp {
- implicit val extractTimestamp: ExtractInstant[HasTimestamp] = _.timestamp
- implicit def orderByTimestampLatestFirst[T <: HasTimestamp]: Order[T] = Order.by(_.timestamp)
-}
-
-sealed trait Measurement extends HasTimestamp {
- def name: String
-}
-
-sealed trait NumericMeasurement extends Measurement {
- def value: Double
- def unit: String
-}
-
-final case class BloodPressure(
- diastolic: Double,
- systolic: Double,
- timestamp: Instant,
-) extends Measurement {
- override def name: String = "blood_pressure"
-}
-
-final case class WeightMeasurementLbs(
- value: Double,
- timestamp: Instant,
-) extends NumericMeasurement {
- override def name: String = "weight"
- override def unit: String = "lbs"
-}
-
-final case class GenericMeasurement(
- name: String,
- value: Double,
- unit: String,
- timestamp: Instant,
-) extends Measurement
-
-final case class TagsUpdate(
- source: String,
- tags: Set[String],
- timestamp: Instant,
-) extends HasTimestamp
-
-final case class Address(
- street1: String,
- street2: String,
- city: String,
- state: String,
- zip: String,
-)
-
-final case class AddressUpdate(
- address: Address,
- timestamp: Instant,
-) extends HasTimestamp
diff --git a/core/src/test/scala/vapors/example/users.scala b/core/src/test/scala/vapors/example/users.scala
deleted file mode 100644
index 3c4fae4ba..000000000
--- a/core/src/test/scala/vapors/example/users.scala
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.rallyhealth
-
-package vapors.example
-
-// Some sample users to compare for testing that generate the same facts every time
-// this should hopefully make it easier to spot when something is awry with the sample user.
-// Unlike JoeSchmoe, you cannot make any assumptions about the presence of facts so you should
-// verify that your test user has the necessary pre-conditions. If not, you should pick a
-// different generated user.
-
-case object User1 extends GeneratedUser
-case object User2 extends GeneratedUser
-case object User3 extends GeneratedUser
diff --git a/core/src/test/scala/vapors/interpreter/AddOutputsSpec.scala b/core/src/test/scala/vapors/interpreter/AddOutputsSpec.scala
deleted file mode 100644
index 07d471472..000000000
--- a/core/src/test/scala/vapors/interpreter/AddOutputsSpec.scala
+++ /dev/null
@@ -1,61 +0,0 @@
-package com.rallyhealth
-
-package vapors.interpreter
-
-import vapors.dsl._
-
-import org.scalatest.freespec.AnyFreeSpec
-
-class AddOutputsSpec extends AnyFreeSpec {
-
- "Expr.AddOutputs" - {
-
- "Int" - {
-
- "expression added to an expression" in {
- VaporsEvalTestHelpers.producesTheSameResultOrException[Int, Int, Int, ArithmeticException](
- _ + _,
- const(_) + const(_),
- )
- }
-
- "value added to an expression" in {
- VaporsEvalTestHelpers.producesTheSameResultOrException[Int, Int, Int, ArithmeticException](
- _ + _,
- const(_) + _,
- )
- }
-
- "expression added to a value" in {
- VaporsEvalTestHelpers.producesTheSameResultOrException[Int, Int, Int, ArithmeticException](
- _ + _,
- const(_).addTo(_),
- )
- }
- }
-
- "Double" - {
-
- "expression added to an expression" in {
- VaporsEvalTestHelpers.producesTheSameResultOrException[Double, Double, Double, ArithmeticException](
- _ + _,
- const(_) + const(_),
- )
- }
-
- "value added to an expression" in {
- VaporsEvalTestHelpers.producesTheSameResultOrException[Double, Double, Double, ArithmeticException](
- _ + _,
- const(_) + _,
- )
- }
-
- "expression added to a value" in {
- VaporsEvalTestHelpers.producesTheSameResultOrException[Double, Double, Double, ArithmeticException](
- _ + _,
- const(_).addTo(_),
- )
- }
- }
- }
-}
diff --git a/core/src/test/scala/vapors/interpreter/ConcatOutputSpec.scala b/core/src/test/scala/vapors/interpreter/ConcatOutputSpec.scala
deleted file mode 100644
index 241ad389c..000000000
--- a/core/src/test/scala/vapors/interpreter/ConcatOutputSpec.scala
+++ /dev/null
@@ -1,90 +0,0 @@
-package com.rallyhealth
-
-package vapors.interpreter
-
-import vapors.data.{Evidence, FactTable}
-import vapors.dsl._
-import vapors.example.{FactTypes, JoeSchmoe}
-
-import org.scalatest.Inside.inside
-import org.scalatest.freespec.AnyFreeSpec
-
-class ConcatOutputSpec extends AnyFreeSpec {
-
- "concat should" - {
-
- "combine all elements into the given traversable type" in {
- val factTypes = List(FactTypes.TagsUpdate, FactTypes.WeightMeasurement, FactTypes.WeightSelfReported)
- val expectedFacts = factTypes.flatMap(JoeSchmoe.factTable.getSortedSeq(_))
- val instantQueries = factTypes.map { factType =>
- valuesOfType(factType).map(_.get(_.select(_.timestamp))).returnOutput
- }
- val query = concat(instantQueries: _*).toOutputMonoid
- val result = eval(JoeSchmoe.factTable)(query)
- assertResult(expectedFacts.map(_.value.timestamp))(result.output.value)
- assertResult(Evidence(expectedFacts)) {
- result.output.evidence
- }
- }
-
- "combine an empty list of expressions into an empty list" in {
- val query = concat[FactTable, List, Nothing, Unit]().toOutputMonoid
- val result = eval(JoeSchmoe.factTable)(query)
- assertResult(Nil)(result.output.value)
- assertResult(Evidence.none) {
- result.output.evidence
- }
- }
-
- "concat mixed elements types into a common supertype" in {
- val factTypes = List(FactTypes.TagsUpdate, FactTypes.WeightMeasurement, FactTypes.WeightSelfReported)
- val expectedFacts = factTypes.flatMap(JoeSchmoe.factTable.getSortedSeq(_))
- val instantQueries = factTypes.map(factsOfType(_).returnOutput)
- val query = concat(instantQueries: _*).toOutputMonoid.withOutputFoldable.map(_.value.get(_.select(_.timestamp)))
- val result = eval(JoeSchmoe.factTable)(query)
- assertResult(expectedFacts.map(_.value.timestamp))(result.output.value)
- assertResult(Evidence(expectedFacts)) {
- result.output.evidence
- }
- }
-
- "combine all elements into a LazyList" in {
- val factTypes = List(FactTypes.TagsUpdate, FactTypes.WeightMeasurement, FactTypes.WeightSelfReported)
- val expectedFacts = factTypes.flatMap(JoeSchmoe.factTable.getSortedSeq(_))
- val instantQueries = factTypes.map { factType =>
- valuesOfType(factType).map(_.get(_.select(_.timestamp))).returnOutput
- }
- val query = concat(instantQueries: _*).toLazyList
- val result = eval(JoeSchmoe.factTable)(query)
- assertResult(expectedFacts.map(_.value.timestamp))(result.output.value)
- assertResult(Evidence(expectedFacts)) {
- result.output.evidence
- }
- }
-
- "combined all elements into a LazyList without forcing the values" in {
- val factTypes = List(FactTypes.TagsUpdate, FactTypes.WeightMeasurement, FactTypes.WeightSelfReported)
- val instantQueries = factTypes.map { factType =>
- valuesOfType(factType).map(_.get(_.select(_.timestamp))).returnOutput
- }
- val query = concat(instantQueries: _*).toLazyList
- val result = eval(JoeSchmoe.factTable)(query)
- inside(result.output.value) {
- case values: LazyList[_] =>
- // confirm that the collection does not start with a definite size because it was unforced
- assert(!values.hasDefiniteSize)
- // confirm that forcing the collection causes it to have a definite size
- assert(values.force.hasDefiniteSize)
- }
- }
-
- "combine an empty list of expressions into an empty lazy list" in {
- val query = concat[FactTable, List, Nothing, Unit]().toLazyList
- val result = eval(JoeSchmoe.factTable)(query)
- assertResult(LazyList.empty)(result.output.value)
- assertResult(Evidence.none) {
- result.output.evidence
- }
- }
- }
-}
diff --git a/core/src/test/scala/vapors/interpreter/DivideOutputsSpec.scala b/core/src/test/scala/vapors/interpreter/DivideOutputsSpec.scala
deleted file mode 100644
index 434d92a72..000000000
--- a/core/src/test/scala/vapors/interpreter/DivideOutputsSpec.scala
+++ /dev/null
@@ -1,128 +0,0 @@
-package com.rallyhealth
-
-package vapors.interpreter
-
-import vapors.algebra.Expr
-import vapors.data.FactTable
-import vapors.dsl
-import vapors.dsl._
-import vapors.example.FactTypes
-
-import org.scalatest.freespec.AnyFreeSpec
-
-class DivideOutputsSpec extends AnyFreeSpec {
-
- "Expr.DivideOutputs" - {
-
- "Int" - {
-
- "expression divided by an expression" in {
- VaporsEvalTestHelpers.producesTheSameResultOrException[Int, Int, Int, ArithmeticException](
- _ / _,
- const(_) / const(_),
- )
- }
-
- "expression divided by a value" in {
- VaporsEvalTestHelpers.producesTheSameResultOrException[Int, Int, Int, ArithmeticException](
- _ / _,
- const(_) / _,
- )
- }
-
- "value divided from an expression" in {
- VaporsEvalTestHelpers.producesTheSameResultOrException[Int, Int, Int, ArithmeticException](
- (a, b) => b / a,
- const(_).divideFrom(_),
- )
- }
-
- lazy val humanAgeFromDogYears: Expr[FactTable, Seq[Int], Unit] = {
- valuesOfType(FactTypes.Age).map {
- _ / 7
- }
- }
-
- "48 dog years is 6 human years" in {
- val result = eval(FactTable(FactTypes.Age(48))) {
- humanAgeFromDogYears.withOutputFoldable.exists {
- _ === 6
- }
- }
- assert(result.output.value)
- }
-
- "49 dog years is 7 human years" in {
- val result = eval(FactTable(FactTypes.Age(49))) {
- humanAgeFromDogYears.withOutputFoldable.exists {
- _ === 7
- }
- }
- assert(result.output.value)
- }
-
- "50 dog years is 7 human years" in {
- val result = eval(FactTable(FactTypes.Age(50))) {
- humanAgeFromDogYears.withOutputFoldable.exists {
- _ === 7
- }
- }
- assert(result.output.value)
- }
- }
-
- "Double" - {
-
- "expression divided by an expression" in {
- VaporsEvalTestHelpers.producesTheSameResultOrException[Double, Double, Double, ArithmeticException](
- _ / _,
- const(_) / const(_),
- )
- }
-
- "expression divided by a value" in {
- VaporsEvalTestHelpers.producesTheSameResultOrException[Double, Double, Double, ArithmeticException](
- _ / _,
- const(_) / _,
- )
- }
-
- "value divided from an expression" in {
- VaporsEvalTestHelpers.producesTheSameResultOrException[Double, Double, Double, ArithmeticException](
- (a, b) => b / a,
- const(_).divideFrom(_),
- )
- }
-
- lazy val celciusFromFahrenheit: Expr[FactTable, Seq[Double], Unit] = {
- valuesOfType(FactTypes.TempFahrenheit).map { tempF =>
- (tempF - 32.0) / 1.8
- }
- }
-
- "is 32F === 0C (shorter form)" in {
- val result = eval(FactTable(FactTypes.TempFahrenheit(32.0))) {
- celciusFromFahrenheit.withOutputFoldable.exists { v =>
- // TODO Support tolerance here
- // === 0.0 works here, too
- val matchVal = 0.0
- dsl.not(and(v > matchVal, v < matchVal))
- }
- }
- assert(result.output.value)
- }
-
- "is 50F === 10C (shorter form)" in {
- val result = eval(FactTable(FactTypes.TempFahrenheit(50.0))) {
- celciusFromFahrenheit.withOutputFoldable.exists { v =>
- // TODO support tolerance here
- // === 10.0 works here, too
- val matchVal = 10.0
- dsl.not(and(v > matchVal, v < matchVal))
- }
- }
- assert(result.output.value)
- }
- }
- }
-}
diff --git a/core/src/test/scala/vapors/interpreter/EmbedExprSpec.scala b/core/src/test/scala/vapors/interpreter/EmbedExprSpec.scala
deleted file mode 100644
index 7a5a403f2..000000000
--- a/core/src/test/scala/vapors/interpreter/EmbedExprSpec.scala
+++ /dev/null
@@ -1,186 +0,0 @@
-package com.rallyhealth
-
-package vapors.interpreter
-
-import vapors.data._
-import vapors.dsl._
-import vapors.example.{FactTypes, JoeSchmoe}
-
-import org.scalatest.matchers.should.Matchers._
-import org.scalatest.wordspec.AnyWordSpec
-
-class EmbedExprSpec extends AnyWordSpec {
-
- "embedding an expression inside a logical operator inside a 'withFactsOfType'" when {
-
- def insideProbOfWeightloss(cond: ValCondExpr[Double, Unit]): RootExpr[Boolean, Unit] = {
- valuesOfType(FactTypes.ProbabilityToUse)
- .flatMap {
- _.getFoldable {
- _.select(_.scores).at("weightloss").to(Seq)
- }
- }
- .exists { _ =>
- cond
- }
- }
-
- def weightMeasuredWithin(window: Window[Int]): RootExpr[Boolean, Unit] = {
- import cats.syntax.invariant._
- val doubleWindow = window.imap(_.toDouble)(_.toInt)
- valuesOfType(FactTypes.WeightMeasurement).exists {
- _.get(_.select(_.value)).within(doubleWindow)
- }
- }
-
- val trueEmbedded = weightMeasuredWithin(Window.greaterThan(200))
- val falseEmbedded = weightMeasuredWithin(Window.greaterThan(300))
- val embeddedFacts = FactSet(JoeSchmoe.weight)
-
- def trueLiteral: ValCondExpr[Double, Unit] = {
- within(input, const(Window.greaterThan(0.7)))
- }
-
- def falseLiteral: ValCondExpr[Double, Unit] = {
- within(input, const(Window.greaterThan(0.9)))
- }
-
- val literalFacts = FactSet(JoeSchmoe.probs)
-
- "inside an 'or'" should {
-
- "return 'true' when embedding a 'true' expression BEFORE a 'true' literal" in {
- val q = insideProbOfWeightloss(or(trueEmbedded, trueLiteral))
- val result = eval(JoeSchmoe.factTable)(q)
- assert(result.output.value)
- assertResult(Evidence(embeddedFacts | literalFacts))(result.output.evidence)
- }
-
- "return 'true' when embedding a 'true' expression BEFORE a 'false' literal" in {
- val q = insideProbOfWeightloss(or(trueEmbedded, falseLiteral))
- val result = eval(JoeSchmoe.factTable)(q)
- assert(result.output.value)
- assertResult(Evidence(embeddedFacts))(result.output.evidence)
- }
-
- "return 'true' when embedding a 'false' expression BEFORE a 'true' literal" in {
- val q = insideProbOfWeightloss(or(falseEmbedded, trueLiteral))
- val result = eval(JoeSchmoe.factTable)(q)
- assert(result.output.value)
- assertResult(Evidence(literalFacts))(result.output.evidence)
- }
-
- "return 'false' when embedding a 'false' expression BEFORE a 'false' literal" in {
- val q = insideProbOfWeightloss(or(falseEmbedded, falseLiteral))
- val result = eval(JoeSchmoe.factTable)(q)
- assert(!result.output.value)
- assertResult(Evidence.none)(result.output.evidence)
- }
-
- "return 'true' when embedding a 'true' expression AFTER a 'true' literal" in {
- val q = insideProbOfWeightloss(or(trueLiteral, trueEmbedded))
- val result = eval(JoeSchmoe.factTable)(q)
- assert(result.output.value)
- assertResult(Evidence(literalFacts | embeddedFacts))(result.output.evidence)
- }
-
- "return 'true' when embedding a 'true' expression AFTER a 'false' literal" in {
- val q = insideProbOfWeightloss(or(falseLiteral, trueEmbedded))
- val result = eval(JoeSchmoe.factTable)(q)
- assert(result.output.value)
- assertResult(Evidence(embeddedFacts))(result.output.evidence)
- }
-
- "return 'true' when embedding a 'false' expression AFTER a 'true' literal" in {
- val q = insideProbOfWeightloss(or(trueLiteral, falseEmbedded))
- val result = eval(JoeSchmoe.factTable)(q)
- assert(result.output.value)
- assertResult(Evidence(literalFacts))(result.output.evidence)
- }
-
- "return 'false' when embedding a 'false' expression AFTER a 'false' literal" in {
- val q = insideProbOfWeightloss(or(falseLiteral, falseEmbedded))
- val result = eval(JoeSchmoe.factTable)(q)
- assert(!result.output.value)
- assertResult(Evidence.none)(result.output.evidence)
- }
-
- "disallows embedding an invalid return type" in {
- val listOfNumberExpr = valuesOfType(FactTypes.ProbabilityToUse).flatMap {
- _.getFoldable(_.select(_.scores).at("weightloss").to(Seq))
- }
- assertDoesNotCompile {
- """insideProbOfWeightloss(or(trueLiteral, listOfNumberExpr))"""
- }
- }
- }
-
- "inside an 'and'" should {
-
- "return 'true' when embedding a 'true' expression BEFORE a 'true' literal" in {
- val q = insideProbOfWeightloss(and(trueEmbedded, trueLiteral))
- val result = eval(JoeSchmoe.factTable)(q)
- assert(result.output.value)
- assertResult(Evidence(embeddedFacts | literalFacts))(result.output.evidence)
- }
-
- "return 'false' when embedding a 'true' expression BEFORE a 'false' literal" in {
- val q = insideProbOfWeightloss(and(trueEmbedded, falseLiteral))
- val result = eval(JoeSchmoe.factTable)(q)
- assert(!result.output.value)
- assertResult(Evidence.none)(result.output.evidence)
- }
-
- "return 'false' when embedding a 'false' expression BEFORE a 'true' literal" in {
- val q = insideProbOfWeightloss(and(falseEmbedded, trueLiteral))
- val result = eval(JoeSchmoe.factTable)(q)
- assert(!result.output.value)
- assertResult(Evidence.none)(result.output.evidence)
- }
-
- "return 'false' when embedding a 'false' expression BEFORE a 'false' literal" in {
- val q = insideProbOfWeightloss(and(falseEmbedded, falseLiteral))
- val result = eval(JoeSchmoe.factTable)(q)
- assert(!result.output.value)
- assertResult(Evidence.none)(result.output.evidence)
- }
-
- "return 'true' when embedding a 'true' expression AFTER a 'true' literal" in {
- val q = insideProbOfWeightloss(and(trueLiteral, trueEmbedded))
- val result = eval(JoeSchmoe.factTable)(q)
- assert(result.output.value)
- assertResult(Evidence(literalFacts | embeddedFacts))(result.output.evidence)
- }
-
- "return 'false' when embedding a 'true' expression AFTER a 'false' literal" in {
- val q = insideProbOfWeightloss(and(falseLiteral, trueEmbedded))
- val result = eval(JoeSchmoe.factTable)(q)
- assert(!result.output.value)
- assertResult(Evidence.none)(result.output.evidence)
- }
-
- "return 'false' when embedding a 'false' expression AFTER a 'true' literal" in {
- val q = insideProbOfWeightloss(and(trueLiteral, falseEmbedded))
- val result = eval(JoeSchmoe.factTable)(q)
- assert(!result.output.value)
- assertResult(Evidence.none)(result.output.evidence)
- }
-
- "return 'false' when embedding a 'false' expression AFTER a 'false' literal" in {
- val q = insideProbOfWeightloss(and(falseLiteral, falseEmbedded))
- val result = eval(JoeSchmoe.factTable)(q)
- assert(!result.output.value)
- assertResult(Evidence.none)(result.output.evidence)
- }
-
- "disallows embedding an invalid return type" in {
- val listOfNumberExpr = valuesOfType(FactTypes.ProbabilityToUse).flatMap {
- _.getFoldable(_.select(_.scores).at("weightloss").asIterable.to(Seq))
- }
- assertDoesNotCompile {
- """insideProbOfWeightloss(and(trueLiteral, listOfNumberExpr))"""
- }
- }
- }
- }
-}
diff --git a/core/src/test/scala/vapors/interpreter/ExponentiateOutputsSpec.scala b/core/src/test/scala/vapors/interpreter/ExponentiateOutputsSpec.scala
deleted file mode 100644
index a94a107c6..000000000
--- a/core/src/test/scala/vapors/interpreter/ExponentiateOutputsSpec.scala
+++ /dev/null
@@ -1,31 +0,0 @@
-package com.rallyhealth
-
-package vapors.interpreter
-
-import vapors.dsl
-import vapors.dsl._
-
-import org.scalacheck.{Arbitrary, Gen}
-import org.scalatest.freespec.AnyFreeSpec
-
-import scala.reflect.classTag
-
-class ExponentiateOutputsSpec extends AnyFreeSpec {
-
- "Expr.ExponentiateOutputs" - {
-
- "reasonable positive number raised to a reasonable positive exponent" in {
- VaporsEvalTestHelpers.producesTheSameResultOrException[Double, Double, Double, ArithmeticException](
- Math.pow,
- (b, e) => dsl.pow(const(b), const(e)),
- )(Arbitrary(Gen.choose(0d, 100d)), Arbitrary(Gen.choose(1d, 10d)), classTag[ArithmeticException])
- }
-
- "arbitrary number raised to a arbitrary exponent" in {
- VaporsEvalTestHelpers.producesTheSameResultOrException[Double, Double, Double, ArithmeticException](
- Math.pow,
- (b, e) => dsl.pow(const(b), const(e)),
- )
- }
- }
-}
diff --git a/core/src/test/scala/vapors/interpreter/FilterOutputSpec.scala b/core/src/test/scala/vapors/interpreter/FilterOutputSpec.scala
deleted file mode 100644
index 30e124f14..000000000
--- a/core/src/test/scala/vapors/interpreter/FilterOutputSpec.scala
+++ /dev/null
@@ -1,203 +0,0 @@
-package com.rallyhealth
-
-package vapors.interpreter
-
-import vapors.data.{Evidence, FactTable}
-import vapors.dsl._
-import vapors.example.{FactTypes, Tags}
-
-import org.scalatest.matchers.should.Matchers._
-import org.scalatest.wordspec.AnyWordSpec
-
-class FilterOutputSpec extends AnyWordSpec {
-
- "Expr.FilterOutput" when {
-
- "using with an 'OutputWithinSet' op" when {
- val tagFacts = FactTable(Tags.smoker, Tags.asthma, Tags.normalBmi)
-
- "comparing facts" should {
-
- "return all matching facts from a given subset" in {
- val q = factsOfType(FactTypes.Tag).filter {
- _ in Set(Tags.asthma)
- }
- val res = eval(tagFacts)(q)
- res.output.value should contain theSameElementsAs Seq(Tags.asthma)
- assertResult(Evidence(Tags.asthma))(res.output.evidence)
- }
-
- "return all matching facts from a given superset" in {
- val q = factsOfType(FactTypes.Tag).filter {
- _ in Set(Tags.asthma, Tags.obeseBmi)
- }
- val res = eval(tagFacts)(q)
- res.output.value should contain theSameElementsAs Seq(Tags.asthma)
- assertResult(Evidence(Tags.asthma))(res.output.evidence)
- }
-
- "return an empty list of facts when given a set that contains no common elements" in {
- val q = factsOfType(FactTypes.Tag).filter {
- _ in Set(Tags.obeseBmi)
- }
- val res = eval(tagFacts)(q)
- assert(res.output.value.isEmpty)
- assert(res.output.evidence.isEmpty)
- }
- }
-
- "comparing values" should {
-
- "return all matching values from a given subset" in {
- val q = factsOfType(FactTypes.Tag).map(_.value).filter {
- _ in Set(Tags.asthma).map(_.value)
- }
- val res = eval(tagFacts)(q)
- res.output.value should contain theSameElementsAs Seq(Tags.asthma).map(_.value)
- }
-
- "return the correct evidence for the matching values from a given subset" in {
- val q = factsOfType(FactTypes.Tag).map(_.value).filter {
- _ in Set(Tags.asthma).map(_.value)
- }
- val res = eval(tagFacts)(q)
- pendingUntilFixed {
- // TODO: Merge this assertion the above unit test when it passes
- assertResult(Evidence(Tags.asthma))(res.output.evidence)
- }
- }
-
- "return the matching values from a given superset" in {
- val q = factsOfType(FactTypes.Tag).map(_.value).filter {
- _ in Set(Tags.asthma, Tags.obeseBmi).map(_.value)
- }
- val res = eval(tagFacts)(q)
- res.output.value should contain theSameElementsAs Seq(Tags.asthma).map(_.value)
- }
-
- "return the correct evidence for the matching values from a given superset" in {
- val q = factsOfType(FactTypes.Tag).map(_.value).filter {
- _ in Set(Tags.asthma, Tags.obeseBmi).map(_.value)
- }
- val res = eval(tagFacts)(q)
- pendingUntilFixed {
- // TODO: Merge this assertion the above unit test when it passes
- assertResult(Evidence(Tags.asthma))(res.output.evidence)
- }
- }
-
- "return an empty list of values when given a set that contains no common elements" in {
- val q = factsOfType(FactTypes.Tag).map(_.value).filter {
- _ in Set(Tags.obeseBmi).map(_.value)
- }
- val res = eval(tagFacts)(q)
- assert(res.output.value.isEmpty)
- assert(res.output.evidence.isEmpty)
- }
- }
-
- "using the 'containsAny' op" should {
-
- "return 'true' when the fact table contains a superset of the given set" in {
- val q = factsOfType(FactTypes.Tag).map(_.value).containsAny {
- Set(Tags.asthma).map(_.value)
- }
- val res = eval(tagFacts)(q)
- assert(res.output.value)
- }
-
- "return the correct evidence for the facts that contain a superset of the given set" in {
- val q = factsOfType(FactTypes.Tag).map(_.value).containsAny {
- Set(Tags.asthma).map(_.value)
- }
- val res = eval(tagFacts)(q)
- pendingUntilFixed {
- // TODO: Merge this assertion the above unit test when it passes
- assertResult(Evidence(Tags.asthma))(res.output.evidence)
- }
- }
-
- "return 'true' when the fact table contains a subset of the given set" in {
- val q = factsOfType(FactTypes.Tag).map(_.value).containsAny {
- Set(Tags.asthma, Tags.obeseBmi).map(_.value)
- }
- val res = eval(tagFacts)(q)
- assert(res.output.value)
- }
-
- "return the correct evidence for the facts that contain a subset of the given set" in {
- val q = factsOfType(FactTypes.Tag).map(_.value).containsAny {
- Set(Tags.asthma, Tags.obeseBmi).map(_.value)
- }
- val res = eval(tagFacts)(q)
- pendingUntilFixed {
- // TODO: Merge this assertion the above unit test when it passes
- assertResult(Evidence(Tags.asthma))(res.output.evidence)
- }
- }
-
- "return 'false' with no Evidence when the facts do not contain anything in the given set" in {
- val q = factsOfType(FactTypes.Tag).map(_.value).containsAny {
- Set(Tags.obeseBmi).map(_.value)
- }
- val res = eval(tagFacts)(q)
- assert(!res.output.value)
- assert(res.output.evidence.isEmpty)
- }
- }
- }
-
- "using with an 'OutputWithinRange' operator" should {
- val low = FactTypes.Age(10)
- val middle = FactTypes.Age(18)
- val high = FactTypes.Age(85)
- val numericFacts = FactTable(low, middle, high)
-
- "return all values that match the condition" in {
- val q = factsOfType(FactTypes.Age).map(_.value).filter {
- _ >= middle.value
- }
- val res = eval(numericFacts)(q)
- res.output.value should contain theSameElementsAs Seq(middle, high).map(_.value)
- }
-
- "return the correct evidence for the matching values from a given subset" in {
- val q = factsOfType(FactTypes.Age).map(_.value).filter {
- _ >= middle.value
- }
- val res = eval(numericFacts)(q)
- pendingUntilFixed {
- // TODO: Merge this assertion the above unit test when it passes
- assertResult(Evidence(middle, high))(res.output.evidence)
- }
- }
-
- "return all facts that match the condition" in {
- val q = factsOfType(FactTypes.Age).filter {
- _.value >= middle.value
- }
- val res = eval(numericFacts)(q)
- res.output.value should contain theSameElementsAs Seq(middle, high)
- assertResult(Evidence(middle, high))(res.output.evidence)
- }
-
- "return an empty list of values when none of the elements meet the condition" in {
- val q = factsOfType(FactTypes.Age).map(_.value).filter {
- _ > high.value
- }
- val res = eval(numericFacts)(q)
- assert(res.output.value.isEmpty)
- assert(res.output.evidence.isEmpty)
- }
-
- "return an empty list of facts when none meet the condition" in {
- val q = factsOfType(FactTypes.Age).filter {
- _.value > high.value
- }
- val res = eval(numericFacts)(q)
- assert(res.output.value.isEmpty)
- assert(res.output.evidence.isEmpty)
- }
- }
- }
-}
diff --git a/core/src/test/scala/vapors/interpreter/FoldOutputSpec.scala b/core/src/test/scala/vapors/interpreter/FoldOutputSpec.scala
deleted file mode 100644
index 81252395b..000000000
--- a/core/src/test/scala/vapors/interpreter/FoldOutputSpec.scala
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.rallyhealth
-
-package vapors.interpreter
-
-import vapors.data.FactTable
-import vapors.dsl._
-
-import org.scalatest.freespec.AnyFreeSpec
-
-class FoldOutputSpec extends AnyFreeSpec {
-
- "Expr.FoldOutput" - {
-
- "fold a list of ints into its sum" in {
- val query = const(List(1, 2, 3)).withOutputFoldable.fold
- val result = eval(FactTable.empty)(query)
- assertResult(6)(result.output.value)
- }
-
- "fold a list of options of int into an option containing the sum" in {
- val query = const(List(Some(1), None, Some(3))).withOutputFoldable.fold
- val result = eval(FactTable.empty)(query)
- assertResult(Some(4))(result.output.value)
- }
-
- "fold a list of options of int into a None" in {
- val query = const(List[Option[Int]](None, None, None)).withOutputFoldable.fold
- val result = eval(FactTable.empty)(query)
- assertResult(None)(result.output.value)
- }
- }
-}
diff --git a/core/src/test/scala/vapors/interpreter/GroupOutputSpec.scala b/core/src/test/scala/vapors/interpreter/GroupOutputSpec.scala
deleted file mode 100644
index 96bcf824e..000000000
--- a/core/src/test/scala/vapors/interpreter/GroupOutputSpec.scala
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.rallyhealth
-
-package vapors.interpreter
-
-import vapors.dsl._
-import vapors.example.{FactTypes, User1}
-
-import org.scalatest.freespec.AnyFreeSpec
-
-class GroupOutputSpec extends AnyFreeSpec {
-
- "groupBy should" - {
-
- "create a map from a list using groupBy and mapValues" in {
- val query = valuesOfType(FactTypes.TagsUpdate).groupBy(_.select(_.source))
- val expected = User1.factTable.getSortedSeq(FactTypes.TagsUpdate).groupMap(_.value.source)(_.value)
- val result = eval(User1.factTable)(query)
- assertResult(expected) {
- result.output.value.toMap
- }
- }
- }
-}
diff --git a/core/src/test/scala/vapors/interpreter/InterpretExprAsResultFnSpec.scala b/core/src/test/scala/vapors/interpreter/InterpretExprAsResultFnSpec.scala
deleted file mode 100644
index b2b40b0a4..000000000
--- a/core/src/test/scala/vapors/interpreter/InterpretExprAsResultFnSpec.scala
+++ /dev/null
@@ -1,49 +0,0 @@
-package com.rallyhealth
-
-package vapors.interpreter
-
-import vapors.data.Evidence
-import vapors.dsl._
-import vapors.example.{FactTypes, JoeSchmoe}
-
-import org.scalatest.wordspec.AnyWordSpec
-
-class InterpretExprAsResultFnSpec extends AnyWordSpec {
-
- "InterpretExprAsFunction" when {
-
- "using no post processing" should {
-
- "find a single fact from a query" in {
- val q = valuesOfType(FactTypes.Age).exists {
- _ >= 18
- }
- val result = eval(JoeSchmoe.factTable)(q)
- assert(result.param.value === ())
- assert(result.output.value)
- assert(result.output.evidence.nonEmpty)
- assertResult(Evidence(JoeSchmoe.age))(result.output.evidence)
- }
-
- "find a complex fact from a query" in {
- val q = valuesOfType(FactTypes.ProbabilityToUse).exists {
- _.getFoldable(_.select(_.scores).at("weightloss")).exists {
- _ > 0.5
- }
- }
- val result = eval(JoeSchmoe.factTable)(q)
- assertResult(Evidence(JoeSchmoe.probs))(result.output.evidence)
- }
-
- "define a fact expression" in {
- val likelyToJoinWeightloss = valuesOfType(FactTypes.ProbabilityToUse).exists {
- _.getFoldable(_.select(_.scores).at("weightloss")).exists {
- _ > 0.5
- }
- }
- val result = eval(JoeSchmoe.factTable)(likelyToJoinWeightloss)
- assertResult(Evidence(JoeSchmoe.probs))(result.output.evidence)
- }
- }
- }
-}
diff --git a/core/src/test/scala/vapors/interpreter/LogicalExprSpec.scala b/core/src/test/scala/vapors/interpreter/LogicalExprSpec.scala
deleted file mode 100644
index 3243e20ce..000000000
--- a/core/src/test/scala/vapors/interpreter/LogicalExprSpec.scala
+++ /dev/null
@@ -1,332 +0,0 @@
-package com.rallyhealth
-
-package vapors.interpreter
-
-import vapors.algebra.Expr
-import vapors.data.{Evidence, ExtractBoolean, FactSet, FactTable}
-import vapors.dsl._
-import vapors.example.JoeSchmoe
-import vapors.logic._
-
-import org.scalactic.source.Position
-import org.scalatest.wordspec.AnyWordSpec
-
-class LogicalExprSpec extends AnyWordSpec {
-
- private type LogicExpr[R] = Expr[Unit, R, Unit]
-
- private type LogicOpBuilder[R] =
- (LogicExpr[R], LogicExpr[R], Seq[LogicExpr[R]]) => LogicExpr[R]
-
- private type UnaryLogicOpBuilder[R] = LogicExpr[R] => LogicExpr[R]
-
- private def evalUnit[R](facts: FactSet)(expr: LogicExpr[R]): ExprOutput[R] = {
- InterpretExprAsResultFn(expr)(ExprInput((), Evidence(facts), FactTable(facts))).output
- }
-
- private def validLogicalOperators[R](
- andBuilder: LogicOpBuilder[R],
- orBuilder: LogicOpBuilder[R],
- notBuilder: UnaryLogicOpBuilder[R],
- trueBuilder: LogicExpr[R],
- falseBuilder: LogicExpr[R],
- facts: FactSet,
- assertTrue: Position => ExprOutput[R] => Unit,
- assertFalse: Position => ExprOutput[R] => Unit,
- ): Unit = {
-
- val T = trueBuilder
- val F = falseBuilder
- val not = notBuilder
-
- def and(
- one: LogicExpr[R],
- two: LogicExpr[R],
- tail: LogicExpr[R]*,
- ): LogicExpr[R] = andBuilder(one, two, tail)
-
- def or(
- one: LogicExpr[R],
- two: LogicExpr[R],
- tail: LogicExpr[R]*,
- ): LogicExpr[R] = orBuilder(one, two, tail)
-
- val evalOutput = evalUnit[R](facts)(_)
-
- def shouldBeTrue(output: ExprOutput[R])(implicit pos: Position): Unit = {
- assertTrue(pos)(output)
- }
-
- def shouldBeFalse(output: ExprOutput[R])(implicit pos: Position): Unit = {
- assertFalse(pos)(output)
- }
-
- "return 'false' for 'not true'" in {
- val q = {
- not(T)
- }
- shouldBeFalse(evalOutput(q))
- }
-
- "return 'true' for 'not false'" in {
- val q = {
- not(F)
- }
- shouldBeTrue(evalOutput(q))
- }
-
- "return 'true' for double negation of 'true'" in {
- val q = {
- not(not(T))
- }
- shouldBeTrue(evalOutput(q))
- }
-
- "return 'false' for double negation of 'false'" in {
- val q = {
- not(not(F))
- }
- shouldBeFalse(evalOutput(q))
- }
-
- "return 'true' for one 'true' and one 'false' in an 'or'" in {
- val q = {
- or(T, F)
- }
- shouldBeTrue(evalOutput(q))
- }
-
- "return 'true' for one 'false' and one 'not false' in an 'or'" in {
- val q = {
- or(F, not(F))
- }
- shouldBeTrue(evalOutput(q))
- }
-
- "return 'false' for one 'false' and one 'not true' in an 'or'" in {
- val q = {
- or(F, not(T))
- }
- shouldBeFalse(evalOutput(q))
- }
-
- "return 'true' for a complex 'or'" in {
- val q = {
- or(F, F, T, F)
- }
- shouldBeTrue(evalOutput(q))
- }
-
- "return 'false' for negating a complex 'or'" in {
- val q = {
- not(or(F, not(T), T, not(not(F))))
- }
- shouldBeFalse(evalOutput(q))
- }
-
- "return 'false' for a long 'or'" in {
- val q = {
- or(F, F, F, F)
- }
- shouldBeFalse(evalOutput(q))
- }
-
- "return 'true' for negating a long 'or'" in {
- val q = {
- not(or(F, F, not(T), not(not(F))))
- }
- shouldBeTrue(evalOutput(q))
- }
-
- "return 'false' for a 'true' and 'false' in an 'and'" in {
- val q = {
- and(T, F)
- }
- shouldBeFalse(evalOutput(q))
- }
-
- "return 'false' for a 'true' and 'not true' in an 'and'" in {
- val q = {
- and(T, not(T))
- }
- shouldBeFalse(evalOutput(q))
- }
-
- "return 'true' for two trues in an and" in {
- val q = {
- and(T, T)
- }
- shouldBeTrue(evalOutput(q))
- }
-
- "return 'true' for two 'not false's in an 'and'" in {
- val q = {
- and(not(F), not(F))
- }
- shouldBeTrue(evalOutput(q))
- }
-
- "return 'false' for a complex 'and'" in {
- val q = {
- and(T, T, F, T)
- }
- shouldBeFalse(evalOutput(q))
- }
-
- "return 'true' for the negation of a complex 'and'" in {
- val q = {
- not(and(T, not(F), F, not(not(T))))
- }
- shouldBeTrue(evalOutput(q))
- }
-
- "return 'true' for a long 'and'" in {
- val q = {
- and(T, T, T, T)
- }
- shouldBeTrue(evalOutput(q))
- }
-
- "return 'false' for the negation of a long 'and'" in {
- val q = {
- not(and(T, not(F), not(not(T)), not(not(not(F)))))
- }
- shouldBeFalse(evalOutput(q))
- }
-
- "return true for nested true 'or's in an 'and'" in {
- val q = {
- and(or(T, T), or(T, T))
- }
- shouldBeTrue(evalOutput(q))
- }
-
- "return 'true' for two nested 'not false or's in an 'and'" in {
- val q = {
- and(not(or(F, F)), not(or(F, F)))
- }
- shouldBeTrue(evalOutput(q))
- }
-
- "return 'false' for a nested 'false or' before some 'true' expressions" in {
- val q = {
- and(or(F, F), T, T)
- }
- shouldBeFalse(evalOutput(q))
- }
-
- "return 'true' for a nested 'not true or' before some 'true' expressions" in {
- val q = {
- and(not(or(F, T)), T, not(F))
- }
- shouldBeFalse(evalOutput(q))
- }
-
- "return 'false' for a nested 'false or' after some 'true' expressions" in {
- val q = {
- and(T, or(T, F), or(F, F))
- }
- shouldBeFalse(evalOutput(q))
- }
-
- "return 'false' for a nested 'not true or' after some 'true' expressions" in {
- val q = {
- and(T, not(F), or(not(T), T), or(F, not(T)))
- }
- shouldBeFalse(evalOutput(q))
- }
-
- "return 'true' for a nested 'false and' in an 'or'" in {
- val q = {
- or(F, and(F, F), and(T, T), and(T, F))
- }
- shouldBeTrue(evalOutput(q))
- }
-
- "return 'false' for the negation of a nested 'false and' in an 'or'" in {
- val q = {
- not(or(F, and(F, F), not(and(T, T)), and(T, not(F), not(T))))
- }
- shouldBeTrue(evalOutput(q))
- }
-
- "return 'true' for a complex structure" in {
- val q = {
- or(F, and(F, T), or(F, F), and(or(T, F), F), or(and(T, F), T))
- }
- shouldBeTrue(evalOutput(q))
- }
-
- "return 'false' for a complex structure" in {
- val q = {
- not(
- or(
- F,
- not(T),
- and(F, T),
- or(F, F),
- not(and(T, T)),
- not(or(T, F)),
- not(not(F)),
- and(or(T, F), F, not(T)),
- or(F, not(T), and(T, F), not(and(T, not(F)))),
- ),
- )
- }
- shouldBeTrue(evalOutput(q))
- }
- }
-
- private abstract class DslLogicOpBuilder {
-
- def andBuilder[R : Conjunction : ExtractBoolean]: LogicOpBuilder[R]
-
- def orBuilder[R : Disjunction : ExtractBoolean]: LogicOpBuilder[R]
-
- def notBuilder[R : Negation]: UnaryLogicOpBuilder[R]
- }
-
- def validDslLogicalOperators(builder: DslLogicOpBuilder): Unit = {
-
- "operating on boolean results" should {
-
- behave like validLogicalOperators[Boolean](
- builder.andBuilder,
- builder.orBuilder,
- builder.notBuilder,
- trueBuilder = const(true),
- falseBuilder = const(false),
- facts = JoeSchmoe.facts,
- assertTrue = { implicit pos => o =>
- assert(o.value)
- // TODO: Is is sufficient to only test all the facts or no facts?
- assertResult(Evidence(JoeSchmoe.facts.toList))(o.evidence)
- },
- assertFalse = { implicit pos => o =>
- assert(!o.value)
- assertResult(Evidence(JoeSchmoe.facts.toList))(o.evidence)
- },
- )
- }
- }
-
- "and / or" should {
-
- behave like validDslLogicalOperators {
- new DslLogicOpBuilder {
-
- override def andBuilder[R : Conjunction : ExtractBoolean]: LogicOpBuilder[R] = { (one, two, tail) =>
- and(one, two, tail: _*)
- }
-
- override def orBuilder[R : Disjunction : ExtractBoolean]: LogicOpBuilder[R] = { (one, two, tail) =>
- or(one, two, tail: _*)
- }
-
- override def notBuilder[R : Negation]: UnaryLogicOpBuilder[R] = {
- not(_)
- }
- }
- }
- }
-}
diff --git a/core/src/test/scala/vapors/interpreter/MultiplyOutputsSpec.scala b/core/src/test/scala/vapors/interpreter/MultiplyOutputsSpec.scala
deleted file mode 100644
index 3975e4910..000000000
--- a/core/src/test/scala/vapors/interpreter/MultiplyOutputsSpec.scala
+++ /dev/null
@@ -1,61 +0,0 @@
-package com.rallyhealth
-
-package vapors.interpreter
-
-import vapors.dsl._
-
-import org.scalatest.freespec.AnyFreeSpec
-
-class MultiplyOutputsSpec extends AnyFreeSpec {
-
- "Expr.MultiplyOutputs" - {
-
- "Int" - {
-
- "expression multiplied by an expression" in {
- VaporsEvalTestHelpers.producesTheSameResultOrException[Int, Int, Int, ArithmeticException](
- _ * _,
- const(_) * const(_),
- )
- }
-
- "expression multiplied by a value" in {
- VaporsEvalTestHelpers.producesTheSameResultOrException[Int, Int, Int, ArithmeticException](
- _ * _,
- const(_) * _,
- )
- }
-
- "value multiplied to an expression" in {
- VaporsEvalTestHelpers.producesTheSameResultOrException[Int, Int, Int, ArithmeticException](
- _ * _,
- const(_).multiplyTo(_),
- )
- }
- }
-
- "Double" - {
-
- "expression multiplied by an expression" in {
- VaporsEvalTestHelpers.producesTheSameResultOrException[Double, Double, Double, ArithmeticException](
- _ * _,
- const(_) * const(_),
- )
- }
-
- "expression multiplied by a value" in {
- VaporsEvalTestHelpers.producesTheSameResultOrException[Int, Int, Int, ArithmeticException](
- _ * _,
- const(_) * _,
- )
- }
-
- "value multiplied to an expression" in {
- VaporsEvalTestHelpers.producesTheSameResultOrException[Int, Int, Int, ArithmeticException](
- _ * _,
- const(_).multiplyTo(_),
- )
- }
- }
- }
-}
diff --git a/core/src/test/scala/vapors/interpreter/OutputWithinSetExprSpec.scala b/core/src/test/scala/vapors/interpreter/OutputWithinSetExprSpec.scala
deleted file mode 100644
index 0084cbab3..000000000
--- a/core/src/test/scala/vapors/interpreter/OutputWithinSetExprSpec.scala
+++ /dev/null
@@ -1,33 +0,0 @@
-package com.rallyhealth
-
-package vapors.interpreter
-
-import vapors.data.Evidence
-import vapors.dsl._
-import vapors.example.{FactTypes, JoeSchmoe}
-
-import org.scalatest.wordspec.AnyWordSpec
-
-class OutputWithinSetExprSpec extends AnyWordSpec {
-
- "Expr.OutputWithinSet" should {
-
- "find an asthma tag in a set that contains it" in {
- val q = valuesOfType(FactTypes.Tag).exists {
- _ in Set("asthma", "diabetes")
- }
- val result = eval(JoeSchmoe.factTable)(q)
- assert(result.output.value)
- assertResult(Evidence(JoeSchmoe.asthmaTag))(result.output.evidence)
- }
-
- "not find an asthma tag in a set that does not contain it" in {
- val q = valuesOfType(FactTypes.Tag).exists {
- _ in Set("diabetes")
- }
- val result = eval(JoeSchmoe.factTable)(q)
- assert(!result.output.value)
- assertResult(Evidence.none)(result.output.evidence)
- }
- }
-}
diff --git a/core/src/test/scala/vapors/interpreter/OutputWithinWindowSpec.scala b/core/src/test/scala/vapors/interpreter/OutputWithinWindowSpec.scala
deleted file mode 100644
index 704bb7068..000000000
--- a/core/src/test/scala/vapors/interpreter/OutputWithinWindowSpec.scala
+++ /dev/null
@@ -1,44 +0,0 @@
-package com.rallyhealth
-
-package vapors.interpreter
-
-import vapors.data.FactTable
-import vapors.dsl._
-
-import org.scalatest.wordspec.AnyWordSpec
-
-class OutputWithinWindowSpec extends AnyWordSpec {
-
- "Expr.OutputWithinWindow" when {
-
- "using the === operator" should {
-
- "return 'true' when the values are equal" in {
- val q = const(2 + 2) === 4
- val result = eval(FactTable.empty)(q)
- assert(result.output.value)
- }
-
- "return 'false' when the values are not equal" in {
- val q = const(2 + 2) === 5
- val result = eval(FactTable.empty)(q)
- assert(!result.output.value)
- }
- }
-
- "using the !== operator" should {
-
- "return 'false' when the values are equal" in {
- val q = const(2 + 2) !== 4
- val result = eval(FactTable.empty)(q)
- assert(!result.output.value)
- }
-
- "return 'true' when the values are not equal" in {
- val q = const(2 + 2) !== 5
- val result = eval(FactTable.empty)(q)
- assert(result.output.value)
- }
- }
- }
-}
diff --git a/core/src/test/scala/vapors/interpreter/SelectFromOutputSpec.scala b/core/src/test/scala/vapors/interpreter/SelectFromOutputSpec.scala
deleted file mode 100644
index 967d02248..000000000
--- a/core/src/test/scala/vapors/interpreter/SelectFromOutputSpec.scala
+++ /dev/null
@@ -1,52 +0,0 @@
-package com.rallyhealth
-
-package vapors.interpreter
-
-import vapors.dsl._
-import vapors.example._
-
-import cats.instances.order._
-import org.scalatest.freespec.AnyFreeSpec
-import shapeless.Nat
-
-import scala.collection.View
-
-class SelectFromOutputSpec extends AnyFreeSpec {
-
- "create a map from a converting a list of facts to tuples" in {
- val query = valuesOfType(FactTypes.TagsUpdate).map { update =>
- wrap(
- update.get(_.select(_.source)).returnOutput,
- update.get(_.select(_.tags)).returnOutput,
- ).asTuple.withOutputValue
- }.toMap
- val expected = User1.factTable
- .getSortedSeq(FactTypes.TagsUpdate)
- .map { fact =>
- (fact.value.source, fact.value.tags)
- }
- .toMap
- val result = eval(User1.factTable)(query)
- assertResult(expected) {
- result.output.value.toMap
- }
- }
-
- "create a set from a list using groupBy, flatMap, sorted, and headOption" in {
- val query = factsOfType(FactTypes.TagsUpdate)
- .groupBy(_.select(_.value.source))
- .flatMap { sourceAndFacts =>
- val facts = sourceAndFacts.getFoldable(_.at(Nat._1))
- val latestFactTags = facts.sorted.headOption.toSet.flatMap(_.getFoldable(_.select(_.value.tags)))
- latestFactTags.to(View)
- }
- val expected = User1.factTable.getSortedSeq(FactTypes.TagsUpdate).groupBy(_.value.source).view.flatMap {
- case (_, facts) =>
- facts.map(_.value).sorted.headOption.toList.flatMap(_.tags)
- }
- val result = eval(User1.factTable)(query)
- assertResult(expected.toVector) {
- result.output.value.toVector
- }
- }
-}
diff --git a/core/src/test/scala/vapors/interpreter/SortOutputSpec.scala b/core/src/test/scala/vapors/interpreter/SortOutputSpec.scala
deleted file mode 100644
index 195a2634e..000000000
--- a/core/src/test/scala/vapors/interpreter/SortOutputSpec.scala
+++ /dev/null
@@ -1,54 +0,0 @@
-package com.rallyhealth
-
-package vapors.interpreter
-
-import vapors.data.FactTable
-import vapors.dsl._
-import vapors.example.{BloodPressure, FactTypes}
-
-import org.scalatest.freespec.AnyFreeSpec
-
-import java.time.Instant
-
-class SortOutputSpec extends AnyFreeSpec {
-
- "Expr.SortOutput" - {
-
- val bpNow = Instant.now()
- val bp5MinAgo = bpNow.minusSeconds(5 * 60)
- val bp15MinAgo = bpNow.minusSeconds(15 * 60)
- val lowDiastolic = BloodPressure(70, 100, bp15MinAgo)
- val medDiastolic = BloodPressure(80, 100, bp5MinAgo)
- val highDiastolic = BloodPressure(90, 100, bpNow)
-
- val bpFacts = FactTable(
- Seq(
- lowDiastolic,
- medDiastolic,
- highDiastolic,
- ).map(FactTypes.BloodPressureMeasurement(_)),
- )
-
- "sorted using natural ordering" in {
- val query = valuesOfType(FactTypes.BloodPressureMeasurement).map(_.get(_.select(_.diastolic))).sorted
- assertResult(Some(highDiastolic)) {
- bpFacts.getSortedSeq(FactTypes.BloodPressureMeasurement).headOption.map(_.value)
- }
- val result = eval(bpFacts)(query)
- assertResult(lowDiastolic.diastolic) {
- result.output.value.head
- }
- }
-
- "sortBy ordered field" in {
- val query = valuesOfType(FactTypes.BloodPressureMeasurement).sortBy(_.select(_.diastolic))
- assertResult(Some(highDiastolic)) {
- bpFacts.getSortedSeq(FactTypes.BloodPressureMeasurement).headOption.map(_.value)
- }
- val result = eval(bpFacts)(query)
- assertResult(lowDiastolic) {
- result.output.value.head
- }
- }
- }
-}
diff --git a/core/src/test/scala/vapors/interpreter/SubtractOutputsSpec.scala b/core/src/test/scala/vapors/interpreter/SubtractOutputsSpec.scala
deleted file mode 100644
index 1e11a1977..000000000
--- a/core/src/test/scala/vapors/interpreter/SubtractOutputsSpec.scala
+++ /dev/null
@@ -1,61 +0,0 @@
-package com.rallyhealth
-
-package vapors.interpreter
-
-import vapors.dsl._
-
-import org.scalatest.freespec.AnyFreeSpec
-
-class SubtractOutputsSpec extends AnyFreeSpec {
-
- "Expr.SubtractOutputs" - {
-
- "Int" - {
-
- "expression subtracted by an expression" in {
- VaporsEvalTestHelpers.producesTheSameResultOrException[Int, Int, Int, ArithmeticException](
- _ - _,
- const(_) - const(_),
- )
- }
-
- "expression subtracted by a value" in {
- VaporsEvalTestHelpers.producesTheSameResultOrException[Int, Int, Int, ArithmeticException](
- _ - _,
- const(_) - _,
- )
- }
-
- "value subtracted by an expression" in {
- VaporsEvalTestHelpers.producesTheSameResultOrException[Int, Int, Int, ArithmeticException](
- (a, b) => b - a,
- const(_).subtractFrom(_),
- )
- }
- }
-
- "Double" - {
-
- "expression subtracted by an expression" in {
- VaporsEvalTestHelpers.producesTheSameResultOrException[Double, Double, Double, ArithmeticException](
- _ - _,
- const(_) - const(_),
- )
- }
-
- "expression subtracted by a value" in {
- VaporsEvalTestHelpers.producesTheSameResultOrException[Double, Double, Double, ArithmeticException](
- _ - _,
- const(_) - _,
- )
- }
-
- "value subtracted by an expression" in {
- VaporsEvalTestHelpers.producesTheSameResultOrException[Double, Double, Double, ArithmeticException](
- (a, b) => b - a,
- const(_).subtractFrom(_),
- )
- }
- }
- }
-}
diff --git a/core/src/test/scala/vapors/interpreter/TakeFromOutputSpec.scala b/core/src/test/scala/vapors/interpreter/TakeFromOutputSpec.scala
deleted file mode 100644
index 49f4c6360..000000000
--- a/core/src/test/scala/vapors/interpreter/TakeFromOutputSpec.scala
+++ /dev/null
@@ -1,87 +0,0 @@
-package com.rallyhealth
-
-package vapors.interpreter
-
-import vapors.data.FactTable
-import vapors.dsl._
-import vapors.example.{FactTypes, TagsUpdate}
-
-import org.scalatest.wordspec.AnyWordSpec
-
-import java.time.Instant
-
-class TakeFromOutputSpec extends AnyWordSpec {
-
- "Expr.TakeFromOutput" when {
- val now = Instant.now()
- val updateABC =
- FactTypes.TagsUpdate(TagsUpdate("ABC", Set("A", "B", "C"), now.minusSeconds(60 * 60 * 24)))
- val updateDEF = FactTypes.TagsUpdate(TagsUpdate("DEF", Set("D", "E", "F"), now))
-
- "using .take(n) with a positive number" should {
-
- "return an empty list if the collection is empty" in {
- val q = factsOfType(FactTypes.TagsUpdate).take(1)
- val res = eval(FactTable.empty)(q)
- assert(res.output.value.isEmpty)
- }
-
- "return the number of elements selected from the start of the list by fact ordering" in {
- val q = factsOfType(FactTypes.TagsUpdate).take(1)
- val res = eval(FactTable(updateABC, updateDEF))(q)
- assertResult(Seq(updateDEF))(res.output.value)
- }
-
- "return all the elements of the list by fact ordering when the number requested is greater than the size" in {
- val q = factsOfType(FactTypes.TagsUpdate).take(3)
- val res = eval(FactTable(updateABC, updateDEF))(q)
- assertResult(Seq(updateDEF, updateABC))(res.output.value)
- }
- }
-
- "using .take(n) with a negative number" should {
-
- "return an empty list if the collection is empty" in {
- val q = factsOfType(FactTypes.TagsUpdate).take(-1)
- val res = eval(FactTable.empty)(q)
- assert(res.output.value.isEmpty)
- }
-
- "return the number of elements selected from the end of the list by fact ordering" in {
- val q = factsOfType(FactTypes.TagsUpdate).take(-1)
- val res = eval(FactTable(updateABC, updateDEF))(q)
- assertResult(Seq(updateABC))(res.output.value)
- }
-
- "return all the elements of the list by fact ordering when the number requested is greater than the size" in {
- val q = factsOfType(FactTypes.TagsUpdate).take(-3)
- val res = eval(FactTable(updateABC, updateDEF))(q)
- assertResult(Seq(updateDEF, updateABC))(res.output.value)
- }
- }
-
- "using .take(n) with 0" should {
-
- "return an empty collection" in {
- val q = factsOfType(FactTypes.TagsUpdate).take(0)
- val res = eval(FactTable(updateABC, updateDEF))(q)
- assertResult(Seq.empty)(res.output.value)
- }
- }
-
- "using .headOption" should {
-
- "return None if the collection is empty" in {
- val q = factsOfType(FactTypes.TagsUpdate).headOption
- val res = eval(FactTable.empty)(q)
- assertResult(None)(res.output.value)
- }
-
- "return the head of the collection by fact ordering" in {
- val q = factsOfType(FactTypes.TagsUpdate).headOption
- val res = eval(FactTable(updateABC, updateDEF))(q)
- assertResult(Some(updateDEF))(res.output.value)
- }
- }
- }
-}
diff --git a/core/src/test/scala/vapors/interpreter/TimeFunctionsSpec.scala b/core/src/test/scala/vapors/interpreter/TimeFunctionsSpec.scala
deleted file mode 100644
index 3082080e2..000000000
--- a/core/src/test/scala/vapors/interpreter/TimeFunctionsSpec.scala
+++ /dev/null
@@ -1,230 +0,0 @@
-package com.rallyhealth
-
-package vapors.interpreter
-
-import vapors.data.FactTable
-import vapors.dsl._
-import vapors.example.{FactTypes, Snippets}
-
-import org.scalacheck.Arbitrary.arbitrary
-import org.scalacheck.ops._
-import org.scalacheck.{Arbitrary, Gen}
-import org.scalatest.freespec.AnyFreeSpec
-
-import java.time._
-import java.time.temporal.ChronoUnit
-
-class TimeFunctionsSpec extends AnyFreeSpec {
- import TimeFunctionsSpec._
-
- "dateAdd" - {
-
- "Instant with" - {
-
- "Duration works the same as .plus" in {
- VaporsEvalTestHelpers.producesTheSameResultOrException[Instant, Duration, Instant, DateTimeException](
- _.plus(_),
- (t, d) => dateAdd(const(t), const(d)),
- )
- }
-
- "Period fails to compile" in {
- val now = Instant.now()
- val period = Period.ofYears(1)
- assertDoesNotCompile {
- "dateAdd(const(now), const(period))"
- }
- assertThrows[DateTimeException] {
- now.plus(period)
- }
- }
- }
-
- "LocalDate with" - {
-
- "Duration fails to compile" in {
- val today = LocalDate.now()
- val duration = Duration.ofSeconds(10)
- assertDoesNotCompile {
- "dateAdd(const(today), const(duration))"
- }
- assertThrows[DateTimeException] {
- today.plus(duration)
- }
- }
-
- "Period works the same as .plus" in {
- VaporsEvalTestHelpers.producesTheSameResultOrException[LocalDate, Period, LocalDate, DateTimeException](
- _.plus(_),
- (t, d) => dateAdd(const(t), const(d)),
- )
- }
- }
-
- "LocalDateTime with" - {
-
- "Duration works the same as .plus" in {
- VaporsEvalTestHelpers
- .producesTheSameResultOrException[LocalDateTime, Duration, LocalDateTime, DateTimeException](
- _.plus(_),
- (t, d) => dateAdd(const(t), const(d)),
- )
- }
-
- "Period works the same as .plus" in {
- VaporsEvalTestHelpers
- .producesTheSameResultOrException[LocalDateTime, Period, LocalDateTime, DateTimeException](
- _.plus(_),
- (t, d) => dateAdd(const(t), const(d)),
- )
- }
- }
-
- "ZonedDateTime with" - {
-
- "Duration works the same as .plus" in {
- VaporsEvalTestHelpers
- .producesTheSameResultOrException[ZonedDateTime, Duration, ZonedDateTime, DateTimeException](
- _.plus(_),
- (t, d) => dateAdd(const(t), const(d)),
- )
- }
-
- "Period works the same as .plus" in {
- VaporsEvalTestHelpers
- .producesTheSameResultOrException[ZonedDateTime, Period, ZonedDateTime, DateTimeException](
- _.plus(_),
- (t, d) => dateAdd(const(t), const(d)),
- )
- }
- }
- }
-
- "dateDiff" - {
-
- "computing Age from DateOfBirth" - {
-
- val feb28Year2021 = LocalDate.of(2021, 2, 28)
- val onFeb28Year2021 = new Snippets(feb28Year2021)
-
- // leap year
- val feb29Year2020 = LocalDate.of(2020, 2, 29)
- val onFeb29Year2020 = new Snippets(feb29Year2020)
-
- "rounds the year down" in {
- val feb1Minus20Years = LocalDate.of(feb28Year2021.getYear - 20, 2, 1)
- // validate that it works outside of vapors
- assertResult(20) {
- feb1Minus20Years.until(feb28Year2021, ChronoUnit.YEARS)
- }
- // validate that it works inside of vapors
- val result = eval(FactTable(FactTypes.DateOfBirth(feb1Minus20Years))) {
- onFeb28Year2021.ageFromDateOfBirth
- }
- assertResult(Seq(20)) { // Just turned 20 this month
- result.output.value
- }
- }
-
- "rounds the year down, even when close" in {
- val feb29Year2000 = feb28Year2021.minusYears(21).plusDays(1)
- // validate that it works outside of vapors
- assertResult(20) {
- feb29Year2000.until(feb28Year2021, ChronoUnit.YEARS)
- }
- // validate that it works inside of vapors
- val result = eval(FactTable(FactTypes.DateOfBirth(feb29Year2000))) {
- onFeb28Year2021.ageFromDateOfBirth
- }
- assertResult(Seq(20)) { // Sorry, birthday is tomorrow
- result.output.value
- }
- }
-
- "counts the current year on their birthday" in {
- val feb28Year2000 = feb28Year2021.minusYears(21)
- // validate that it works outside of vapors
- assertResult(21) {
- feb28Year2000.until(feb28Year2021, ChronoUnit.YEARS)
- }
- // validate that it works inside of vapors
- val result = eval(FactTable(FactTypes.DateOfBirth(feb28Year2000))) {
- onFeb28Year2021.ageFromDateOfBirth
- }
- assertResult(Seq(21)) { // 🎉 happy birthday! 🍻
- result.output.value
- }
- }
-
- "returns the correct number of years between leap years" in {
- val feb29Year2000 = LocalDate.of(2000, 2, 29)
- // validate that it works outside of vapors
- assertResult(20) {
- feb29Year2000.until(feb29Year2020, ChronoUnit.YEARS)
- }
- // validate that it works inside of vapors
- val result = eval(FactTable(FactTypes.DateOfBirth(feb29Year2000))) {
- new Snippets(feb29Year2020).ageFromDateOfBirth
- }
- assertResult(Seq(20)) { // leap years work as expected
- result.output.value
- }
- }
-
- "returns the correct number of years on a leap year" in {
- val mar1Year1999 = LocalDate.of(1999, 3, 1)
- // validate that it works outside of vapors
- assertResult(20) {
- mar1Year1999.until(feb29Year2020, ChronoUnit.YEARS)
- }
- // validate that it works inside of vapors
- val result = eval(FactTable(FactTypes.DateOfBirth(mar1Year1999))) {
- onFeb29Year2020.ageFromDateOfBirth
- }
- assertResult(Seq(20)) {
- result.output.value
- }
- }
-
- "returns the correct number of years from a leap year birthday" in {
- val feb29Year2000 = LocalDate.of(2000, 2, 29)
- // validate that it works outside of vapors
- assertResult(20) {
- feb29Year2000.until(feb28Year2021, ChronoUnit.YEARS)
- }
- // validate that it works inside of vapors
- val result = eval(FactTable(FactTypes.DateOfBirth(feb29Year2000))) {
- onFeb28Year2021.ageFromDateOfBirth
- }
- assertResult(Seq(20)) {
- result.output.value
- }
- }
- }
- }
-}
-
-object TimeFunctionsSpec {
-
- // TODO: Add to scalacheck-ops
-
- // $COVERAGE-OFF$
- implicit val arbChronoUnit: Arbitrary[ChronoUnit] = Arbitrary {
- Gen.oneOf(ChronoUnit.values())
- }
-
- implicit val arbJDuration: Arbitrary[Duration] = Arbitrary {
- for {
- a <- arbitrary[Instant]
- b <- arbitrary[Instant]
- } yield Duration.between(a, b)
- }
-
- implicit val arbJPeriod: Arbitrary[Period] = Arbitrary {
- for {
- a <- arbitrary[LocalDate]
- b <- arbitrary[LocalDate]
- } yield Period.between(a, b)
- }
- // $COVERAGE-ON$
-}
diff --git a/core/src/test/scala/vapors/interpreter/UsingDefinitionsExprSpec.scala b/core/src/test/scala/vapors/interpreter/UsingDefinitionsExprSpec.scala
deleted file mode 100644
index 66f727c4b..000000000
--- a/core/src/test/scala/vapors/interpreter/UsingDefinitionsExprSpec.scala
+++ /dev/null
@@ -1,65 +0,0 @@
-package com.rallyhealth
-
-package vapors.interpreter
-
-import vapors.data.{DerivedFactOfType, Evidence, FactTable}
-import vapors.dsl._
-import vapors.example.{FactTypes, JoeSchmoe, Role, Snippets}
-
-import org.scalatest.matchers.should.Matchers._
-import org.scalatest.wordspec.AnyWordSpec
-
-import java.time.LocalDate
-
-class UsingDefinitionsExprSpec extends AnyWordSpec {
-
- "Expr.UsingDefinitions" should {
-
- "add the defined facts to the fact table" in {
- val result = eval(JoeSchmoe.factTable) {
- usingDefinitions(Snippets.ageFromDateOfBirthDef) {
- valuesOfType(FactTypes.Age)
- }
- }
- val ages = result.output.value
- ages should contain only JoeSchmoe.age.value
- }
-
- "return the result of an expression with the Definition-produced facts as DerivedFacts" in {
- val yearWhen19 = LocalDate.now().getYear - 19
- val expiredAge = FactTypes.Age(17)
- val dob = FactTypes.DateOfBirth(LocalDate.of(yearWhen19, 1, 1))
- val facts = FactTable(expiredAge, dob)
- val result = eval(facts)(Snippets.isOver18)
- assert(result.output.value)
- val ageFromYear = LocalDate.now().getYear - dob.value.getYear
- val expectedDerivedFact = DerivedFactOfType(FactTypes.Age, ageFromYear, Evidence(dob))
- assertResult(Evidence(expectedDerivedFact))(result.output.evidence)
- assertResult(Evidence(dob))(result.output.evidence.derivedFromSources)
- }
-
- "support nested fact definitions" in {
- val yearWhen19 = LocalDate.now().getYear - 19
- val userRole = FactTypes.Role(Role.User)
- val expiredAge = FactTypes.Age(17)
- val dob = FactTypes.DateOfBirth(LocalDate.of(yearWhen19, 1, 1))
- val facts = FactTable(expiredAge, dob, userRole)
- val definition = Snippets.isEligibleDef
- val result = eval(facts) {
- usingDefinitions(definition) {
- factsOfType(definition.factType).exists {
- _.get(_.select(_.value))
- }
- }
- }
- assert(result.output.value)
- val correctAge = DerivedFactOfType(FactTypes.Age, 19, Evidence(dob))
- val evidenceOfEligibility = Evidence(
- DerivedFactOfType(definition.factType, true, Evidence(correctAge, userRole)),
- )
- assertResult(evidenceOfEligibility)(result.output.evidence)
- assertResult(Evidence(dob, userRole))(result.output.evidence.derivedFromSources)
- }
-
- }
-}
diff --git a/core/src/test/scala/vapors/interpreter/VaporsEvalTestHelpers.scala b/core/src/test/scala/vapors/interpreter/VaporsEvalTestHelpers.scala
deleted file mode 100644
index b2a9d067d..000000000
--- a/core/src/test/scala/vapors/interpreter/VaporsEvalTestHelpers.scala
+++ /dev/null
@@ -1,117 +0,0 @@
-package com.rallyhealth
-
-package vapors.interpreter
-
-import vapors.data.FactTable
-import vapors.dsl.{eval, RootExpr}
-
-import org.scalacheck.Arbitrary
-import org.scalactic.Tolerance._
-import org.scalactic.TripleEqualsSupport._
-import org.scalactic.source.Position
-import org.scalatest.Assertion
-import org.scalatest.Assertions._
-import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks._
-
-import scala.Fractional.Implicits._
-import scala.reflect.ClassTag
-import scala.util.Try
-
-object VaporsEvalTestHelpers {
-
- trait CompareEquality[E, A] {
-
- def assertEqual(
- expected: E,
- actual: A,
- )(implicit
- pos: Position,
- ): Assertion
- }
-
- object CompareEquality extends LowPriorityDefaultTolerance {
-
- def apply[E, A](build: Position => (E, A) => Assertion): CompareEquality[E, A] = new CompareEquality[E, A] {
- override def assertEqual(
- expected: E,
- actual: A,
- )(implicit
- pos: Position,
- ): Assertion = build(pos)(expected, actual)
- }
-
- implicit def tolerantFractional[A : Fractional : DefaultTolerance]: CompareEquality[A, A] = CompareEquality {
- implicit pos => (expected, actual) =>
- assert(DefaultTolerance[A].toSpread(expected) === actual)
- }
-
- implicit def tolerantIntegral[A : Integral : DefaultTolerance]: CompareEquality[A, A] = CompareEquality {
- implicit pos => (expected, actual) =>
- assert(DefaultTolerance[A].toSpread(expected) === actual)
- }
- }
-
- trait LowPriorityDefaultTolerance {
-
- implicit def zeroToleranceIntegral[A : Integral]: CompareEquality[A, A] = CompareEquality {
- implicit pos => (expected, actual) =>
- assert(expected == actual)
- }
- }
-
- trait DefaultTolerance[A] {
- def toSpread(value: A): Spread[A]
- }
-
- object DefaultTolerance {
-
- @inline def apply[A : DefaultTolerance]: DefaultTolerance[A] = implicitly
-
- implicit def onePercentFractionalTolerance[A : Fractional]: DefaultTolerance[A] = {
- val F = Fractional[A]
- val onePercent = F.one / F.fromInt(100)
- value => {
- val onePercentOfValue = value * onePercent
- value +- onePercentOfValue
- }
- }
- }
-
- def producesTheSameResultOrException[A : Arbitrary, B : Arbitrary, R, E <: Throwable : ClassTag](
- evaluate: (A, B) => R,
- buildExpr: (A, B) => RootExpr[R, Unit],
- ): Assertion = {
- forAll { (a: A, b: B) =>
- val query = buildExpr(a, b)
- Try(evaluate(a, b)).fold(
- {
- case expectedExc: E =>
- val exc = intercept[E] {
- eval(FactTable.empty)(query)
- }
- assertResult(expectedExc.getMessage) {
- exc.getMessage
- }
- case unexpected =>
- fail("Unexpected exception", unexpected)
- },
- expectedValue => {
- val result = eval(FactTable.empty)(query)
- expectedValue match {
- case num: Double if num.isNaN =>
- result.output.value match {
- case obs: Double =>
- assert(obs.isNaN, "Expected output to be NaN")
- case _ =>
- fail("Expected output to be a Double")
- }
- case _ =>
- assertResult(expectedValue) {
- result.output.value
- }
- }
- },
- )
- }
- }
-}
diff --git a/core/src/test/scala/vapors/interpreter/WhenExprSpec.scala b/core/src/test/scala/vapors/interpreter/WhenExprSpec.scala
deleted file mode 100644
index 191fdf3cb..000000000
--- a/core/src/test/scala/vapors/interpreter/WhenExprSpec.scala
+++ /dev/null
@@ -1,87 +0,0 @@
-package com.rallyhealth
-
-package vapors.interpreter
-
-import vapors.data.FactTable
-import vapors.dsl._
-
-import org.scalatest.wordspec.AnyWordSpec
-
-class WhenExprSpec extends AnyWordSpec {
-
- // a set of ordered constants for comparison
- private final val a = "A"
- private final val b = "B"
- private final val c = "C"
- private final val d = "D"
-
- "Expr.When" when {
-
- "operating on constants" should {
-
- "return the first branch of an if / else when the first condition is 'true'" in {
- val q = when(const(true)).thenReturn(const(a)).elseReturn(const(b))
- val res = eval(FactTable.empty)(q)
- assertResult(a)(res.output.value)
- }
-
- "return the second branch of an if / else when the first condition is 'false'" in {
- val q = when(const(false)).thenReturn(const(a)).elseReturn(const(b))
- val res = eval(FactTable.empty)(q)
- assertResult(b)(res.output.value)
- }
-
- "return the first branch of a if / elif / else when the first condition is 'true' and the second condition is 'false'" in {
- val q = when(const(true))
- .thenReturn(const(a))
- .elif(const(false))
- .thenReturn(const(b))
- .elseReturn(const(c))
- val res = eval(FactTable.empty)(q)
- assertResult(a)(res.output.value)
- }
-
- "return the first branch of a if / elif / else when the first condition is 'true' and the second condition is 'true'" in {
- val q = when(const(true))
- .thenReturn(const(a))
- .elif(const(true))
- .thenReturn(const(b))
- .elseReturn(const(c))
- val res = eval(FactTable.empty)(q)
- assertResult(a)(res.output.value)
- }
-
- "return the second branch of a if / elif / else when the first condition is 'false' and the second condition is 'true'" in {
- val q = when(const(false))
- .thenReturn(const(a))
- .elif(const(true))
- .thenReturn(const(b))
- .elseReturn(const(c))
- val res = eval(FactTable.empty)(q)
- assertResult(b)(res.output.value)
- }
-
- "return the last branch of a if / elif / else when all conditions are 'false'" in {
- val q = when(const(false))
- .thenReturn(const(a))
- .elif(const(false))
- .thenReturn(const(b))
- .elseReturn(const(c))
- val res = eval(FactTable.empty)(q)
- assertResult(c)(res.output.value)
- }
-
- "return the third branch of a if / elif / elif / else when the first two conditions are 'false' and the third condition is 'true'" in {
- val q = when(const(false))
- .thenReturn(const(a))
- .elif(const(false))
- .thenReturn(const(b))
- .elif(const(true))
- .thenReturn(const(c))
- .elseReturn(const(d))
- val res = eval(FactTable.empty)(q)
- assertResult(c)(res.output.value)
- }
- }
- }
-}
diff --git a/core/src/test/scala/vapors/interpreter/WrapOutputHListSpec.scala b/core/src/test/scala/vapors/interpreter/WrapOutputHListSpec.scala
deleted file mode 100644
index 95dbde927..000000000
--- a/core/src/test/scala/vapors/interpreter/WrapOutputHListSpec.scala
+++ /dev/null
@@ -1,84 +0,0 @@
-package com.rallyhealth
-
-package vapors.interpreter
-
-import vapors.data.{Evidence, FactTable}
-import vapors.dsl._
-import vapors.example.{ColorCoding, FactTypes, JoeSchmoe, TagsUpdate}
-
-import org.scalatest.freespec.AnyFreeSpec
-import shapeless.HNil
-
-class WrapOutputHListSpec extends AnyFreeSpec {
-
- import vapors.example.SimpleTagUpdates._
-
- "wrap, when given const nodes, should" - {
-
- "convert to a case class with the correct number of inputs" in {
- val query = {
- wrap(const(tagsNow.source), const(tagsNow.tags), const(tagsNow.timestamp)).as[TagsUpdate]
- }
- val result = eval(FactTable.empty)(query)
- assertResult(tagsNow)(result.output.value)
- }
-
- "NOT compile when attempting to convert fewer inputs than required into a case class" in {
- assertDoesNotCompile {
- "wrap(const(tagsNow.tags)).as[TagsUpdate]"
- }
- }
-
- "NOT compile when attempting to convert inputs into a case class in the wrong order" in {
- assertDoesNotCompile {
- "wrap(const(tagsNow.tags), const(tagsNow.timestamp), const(tagsNow.source)).as[TagsUpdate]"
- }
- }
-
- "convert into a tuple-3" in {
- val t = (1, "two", ColorCoding.Blue)
- val query = {
- wrap(const(t._1), const(t._2), const(t._3)).asTuple
- }
- val result = eval(FactTable.empty)(query)
- assertResult(t)(result.output.value)
- }
-
- "convert into an hlist of size 3" in {
- val hlist = 1 :: "two" :: ColorCoding.Blue :: HNil
- val t = hlist.tupled
- val query = {
- wrap(const(t._1), const(t._2), const(t._3)).asHList
- }
- val result = eval(FactTable.empty)(query)
- assertResult(hlist)(result.output.value)
- }
- }
-
- "wrap, when comparing evidence, should" - {
-
- "combine all non-empty evidence" in {
- val query = {
- wrap(
- factsOfType(FactTypes.Name).headOption,
- factsOfType(FactTypes.Age).headOption,
- ).asHList
- }
- val facts = List(JoeSchmoe.name, JoeSchmoe.age)
- val result = eval(FactTable(facts))(query)
- assertResult(Evidence(facts))(result.output.evidence)
- }
-
- "return no evidence if any branch has no evidence" in {
- val query = {
- wrap(
- factsOfType(FactTypes.Name).headOption,
- factsOfType(FactTypes.Age).headOption,
- ).asHList
- }
- val result = eval(FactTable(JoeSchmoe.name))(query)
- assertResult(Evidence.none)(result.output.evidence)
- }
- }
-
-}
diff --git a/core/src/test/scala/vapors/interpreter/WrapOutputSeqSpec.scala b/core/src/test/scala/vapors/interpreter/WrapOutputSeqSpec.scala
deleted file mode 100644
index 2ce3cc0d9..000000000
--- a/core/src/test/scala/vapors/interpreter/WrapOutputSeqSpec.scala
+++ /dev/null
@@ -1,64 +0,0 @@
-package com.rallyhealth
-
-package vapors.interpreter
-
-import vapors.data.{Evidence, FactTable, FactType}
-import vapors.dsl._
-import vapors.example.{FactTypes, HasTimestamp, JoeSchmoe}
-
-import org.scalatest.Inside.inside
-import org.scalatest.freespec.AnyFreeSpec
-
-class WrapOutputSeqSpec extends AnyFreeSpec {
-
- "wrapSeq / sequence should" - {
-
- "wrap a list of constant expressions into an expression of a list of the values" in {
- val query = wrapSeq(
- const(1),
- const(2),
- const(3),
- )
- val result = eval(FactTable.empty)(query)
- assertResult(Seq(1, 2, 3)) {
- result.output.value
- }
- }
-
- "not force the resulting lazy list" in {
- val query = wrapSeq(
- const(1),
- const(2),
- const(3),
- )
- val result = eval(FactTable.empty)(query)
- inside(result.output.value) {
- case values: LazyList[_] =>
- // confirm that the collection does not start with a definite size because it was unforced
- assert(!values.hasDefiniteSize)
- // confirm that forcing the collection causes it to have a definite size
- assert(values.force.hasDefiniteSize)
- }
- }
-
- "wrap a list of expressions and combine the evidence from all of them" in {
- val factTypes = List[FactType[_ <: HasTimestamp]](
- FactTypes.BloodPressureMeasurement,
- FactTypes.WeightSelfReported,
- FactTypes.TagsUpdate,
- )
- val subExpressions =
- factTypes.map(t => valuesOfType(t).map(_.get(_.select(_.timestamp))).returnOutput)
- val query = sequence(subExpressions)
- val factsPerType = factTypes.map(JoeSchmoe.factTable.getSortedSeq(_))
- val expectedValues = factsPerType.map(_.map(_.value.timestamp))
- val result = eval(JoeSchmoe.factTable)(query)
- assertResult(expectedValues) {
- result.output.value
- }
- assertResult(Evidence(factsPerType.flatten)) {
- result.output.evidence
- }
- }
- }
-}
diff --git a/core/src/test/scala/vapors/interpreter/ZipOutputSpec.scala b/core/src/test/scala/vapors/interpreter/ZipOutputSpec.scala
deleted file mode 100644
index 329fc5212..000000000
--- a/core/src/test/scala/vapors/interpreter/ZipOutputSpec.scala
+++ /dev/null
@@ -1,148 +0,0 @@
-package com.rallyhealth
-
-package vapors.interpreter
-
-import vapors.data.FactTable
-import vapors.dsl._
-import vapors.example.TagsUpdate
-
-import org.scalatest.freespec.AnyFreeSpec
-import shapeless.HNil
-
-import java.time.Instant
-
-class ZipOutputSpec extends AnyFreeSpec {
-
- import vapors.example.SimpleTagUpdates._
-
- "zippedToShortest should" - {
-
- "return a list as long as the shortest input list of" - {
-
- "tuple values" in {
- val query = wrapEach(
- const(List("A", "B", "C")),
- const(List(1, 2, 3, 4, 5)),
- ).zippedToShortest.asTuple
- val result = eval(FactTable.empty)(query)
- assertResult(List(("A", 1), ("B", 2), ("C", 3))) {
- result.output.value
- }
- }
-
- "HList values" in {
- val query = wrapEach(
- const(List("A", "B", "C")),
- const(List(1, 2, 3, 4, 5)),
- ).zippedToShortest.asHList
- val result = eval(FactTable.empty)(query)
- assertResult(List("A" :: 1 :: HNil, "B" :: 2 :: HNil, "C" :: 3 :: HNil)) {
- result.output.value
- }
- }
-
- "case class values" in {
- val query = wrapEach(
- const(List(tagsNow, tags5MinAgo, tags15MinAgo).map(_.source)),
- const(List(tagsNow, tags5MinAgo).map(_.tags)),
- const(List(tagsNow, tags5MinAgo, tags15MinAgo).map(_.timestamp)),
- ).zippedToShortest.as[TagsUpdate]
- val result = eval(FactTable.empty)(query)
- assertResult(List(tagsNow, tags5MinAgo)) {
- result.output.value
- }
- }
- }
-
- "return nil when any input list is nil for" - {
-
- "tuple values" in {
- val query = wrapEach(
- const(List("A", "B", "C")),
- const(List.empty[Int]),
- ).zippedToShortest.asTuple
- val result = eval(FactTable.empty)(query)
- assertResult(Nil) {
- result.output.value
- }
- }
-
- "HList values" in {
- val query = wrapEach(
- const(List.empty[String]),
- const(List(1, 2, 3, 4, 5)),
- ).zippedToShortest.asHList
- val result = eval(FactTable.empty)(query)
- assertResult(Nil) {
- result.output.value
- }
- }
-
- "case class values" in {
- val query = wrapEach(
- const(List(tagsNow).map(_.source)),
- const(List(tagsNow, tags5MinAgo).map(_.tags)),
- const(List.empty[Instant]),
- ).zippedToShortest.asHList
- val result = eval(FactTable.empty)(query)
- assertResult(Nil) {
- result.output.value
- }
- }
- }
-
- "not force a LazyList when" - {
-
- "taking the headOption" in {
- val query = wrapEach(
- const((tagsNow #:: fail("forced source") #:: LazyList.empty).map(_.source)),
- const((tagsNow #:: fail("forced tags") #:: LazyList.empty).map(_.tags)),
- const((tagsNow #:: fail("forced timestamp") #:: LazyList.empty).map(_.timestamp)),
- ).zippedToShortest.as[TagsUpdate].withOutputFoldable.headOption
- val result = eval(FactTable.empty)(query)
- assertResult(Some(tagsNow)) {
- result.output.value
- }
- }
- }
-
- "not compile when" - {
-
- "given too many arguments for a case class" in {
- assertDoesNotCompile {
- """
- wrapEach(
- const(List.empty[String]),
- const(List.empty[Set[String]]),
- const(List.empty[Instant]),
- const(List.empty[Int]), // too many
- ).zippedToShortest.as[TagsUpdate]
- """
- }
- }
-
- "given too few arguments for a case class" in {
- assertDoesNotCompile {
- """
- wrapEach(
- const(List.empty[String]),
- const(List.empty[Set[String]]),
- ).zippedToShortest.as[TagsUpdate]
- """
- }
- }
-
- "given arguments out of order for a case class" in {
- assertDoesNotCompile {
- """
- wrapEach(
- const(List.empty[Set[String]]),
- const(List.empty[Instant]),
- const(List.empty[String]),
- ).zippedToShortest.as[TagsUpdate]
- """
- }
- }
- }
- }
-}
diff --git a/core/src/test/scala/vapors/lens/NamedLensSpec.scala b/core/src/test/scala/vapors/lens/NamedLensSpec.scala
deleted file mode 100644
index 6bf2db69f..000000000
--- a/core/src/test/scala/vapors/lens/NamedLensSpec.scala
+++ /dev/null
@@ -1,85 +0,0 @@
-package com.rallyhealth
-
-package vapors.lens
-
-import vapors.data.TypedFact
-import vapors.example.{AddressUpdate, BloodPressure, JoeSchmoe}
-
-import cats.data.Chain
-import org.scalatest.wordspec.AnyWordSpec
-import shapeless.{::, HNil, Nat}
-
-import java.time.LocalDate
-
-class NamedLensSpec extends AnyWordSpec {
-
- "NamedLens.at" should {
-
- "select a value from an HList using a Nat literal" in {
- val lens = NamedLens.id[Double :: Int :: HNil].at(Nat._1)
- val expected = 1
- assertResult(expected) {
- lens.get(2.0 :: expected :: HNil)
- }
- }
-
- "fail to compile when using an index out of range" in {
- assertDoesNotCompile {
- "NamedLens.id[Double :: Int :: HNil].at(Nat._2)"
- }
- }
- }
-
- "NamedLens.select" should {
-
- "select a field of a case class" in {
- val lens = NamedLens.id[BloodPressure].select(_.diastolic)
- assertResult(DataPath(Chain(DataPath.Field("diastolic"))))(lens.path)
- assertResult(JoeSchmoe.bloodPressure.value.diastolic) {
- lens.get(JoeSchmoe.bloodPressure.value)
- }
- }
-
- "select a field of a case class within another case class" in {
- val lens = NamedLens.id[AddressUpdate].select(_.address.zip)
- assertResult(DataPath(Chain(DataPath.Field("address"), DataPath.Field("zip"))))(lens.path)
- assertResult(JoeSchmoe.lastAddressUpdate.value.address.zip) {
- lens.get(JoeSchmoe.lastAddressUpdate.value)
- }
- }
-
- "select a field of a case class inside of a Fact" in {
- val lens = NamedLens.id[TypedFact[BloodPressure]].select(_.value.diastolic)
- assertResult(DataPath(Chain(DataPath.Field("value"), DataPath.Field("diastolic"))))(lens.path)
- assertResult(JoeSchmoe.bloodPressure.value.diastolic) {
- lens.get(JoeSchmoe.bloodPressure)
- }
- }
-
- "select a field of a case class within another case class inside of a fact" in {
- val lens = NamedLens.id[TypedFact[AddressUpdate]].select(_.value.address.zip)
- assertResult(DataPath(Chain(DataPath.Field("value"), DataPath.Field("address"), DataPath.Field("zip"))))(
- lens.path,
- )
- assertResult(JoeSchmoe.lastAddressUpdate.value.address.zip) {
- lens.get(JoeSchmoe.lastAddressUpdate)
- }
- }
-
- "select a Java bean style 'get' method with the prefix removed" in {
- val lens = NamedLens.id[LocalDate].select(_.getYear())
- assertResult(DataPath(Chain(DataPath.Field("year"))))(lens.path)
- assertResult(JoeSchmoe.dateOfBirth.value.getYear) {
- lens.get(JoeSchmoe.dateOfBirth.value)
- }
- }
-
- "select a Java bean style 'is' method without removing the prefix" in {
- val lens = NamedLens.id[LocalDate].select(_.isLeapYear())
- assertResult(DataPath(Chain(DataPath.Field("isLeapYear"))))(lens.path)
- assertResult(JoeSchmoe.dateOfBirth.value.isLeapYear) {
- lens.get(JoeSchmoe.dateOfBirth.value)
- }
- }
- }
-}
diff --git a/project/Dependencies.scala b/project/Dependencies.scala
index 899d38144..e39995822 100644
--- a/project/Dependencies.scala
+++ b/project/Dependencies.scala
@@ -16,7 +16,6 @@ object Dependencies {
private final val shapelessVersion = "2.3.7"
private final val sourcecodeVersion = "0.2.7"
- private val alleyCatsCore = "org.typelevel" %% "alleycats-core" % catsVersion
private val catsCore = "org.typelevel" %% "cats-core" % catsVersion
private val circeCore = "io.circe" %% "circe-core" % circeVersion
private val circeLiteral = "io.circe" %% "circe-literal" % circeVersion
@@ -30,7 +29,6 @@ object Dependencies {
private val scalactic = "org.scalactic" %% "scalactic" % scalacticVersion
private val scalaTest = "org.scalatest" %% "scalatest" % scalaTestVersion
private val scalaTestPlusScalaCheck = "org.scalatestplus" %% "scalacheck-1-15" % scalaTestPlusScalaCheckVersion
- private def scalaReflect(scalacVersion: String): ModuleID = "org.scala-lang" % "scala-reflect" % scalacVersion
private val shapeless = "com.chuusai" %% "shapeless" % shapelessVersion
private val sourcecode = "com.lihaoyi" %% "sourcecode" % sourcecodeVersion
@@ -41,26 +39,6 @@ object Dependencies {
).map(_ % Test)
}
- final object CoreProject {
-
- def all(scalaVersion: String): Seq[ModuleID] =
- Seq(
- alleyCatsCore,
- catsCore,
- scalactic,
- scalaReflect(scalaVersion),
- shapeless,
- ) ++ Seq(
- // Test-only dependencies
- munit,
- munitScalaCheck,
- scalaCheck,
- scalaCheckOps,
- scalaTest,
- scalaTestPlusScalaCheck,
- ).map(_ % Test)
- }
-
final object CoreV1Project {
val all: Seq[ModuleID] =