Commit 8aa0bbcb authored by Arthur Bit-Monnot's avatar Arthur Bit-Monnot

Provide immutable array and sfunctor that do not box primitives.

parent b66eda0b
......@@ -4,8 +4,8 @@ import cats.Id
import dahu.graphs.DAG
import dahu.model.ir._
import dahu.model.problem.SatisfactionProblem
import dahu.model.types.{TagIsoInt, Value}
import dahu.recursion.{FAlgebra, Fix}
import dahu.model.types._
import dahu.recursion._
import dahu.utils.errors._
import dahu.model.compiler.Optimizations.{simplifications, PASS, Tree}
import dahu.model.input.Ident
......
......@@ -71,11 +71,13 @@ lazy val utils = project
.settings(commonSettings ++ utestSettings: _*)
.settings(
libraryDependencies ++= Seq(
"org.spire-math" %% "debox" % "0.8.0"
"org.spire-math" %% "debox" % "0.8.0",
"org.typelevel" %% "cats-core" % "1.1.0",
))
lazy val recursion = project
.in(file("recursion"))
.dependsOn(utils)
.settings(name := "recursion")
.settings(commonSettings ++ utestSettings: _*)
.settings(
......
package dahu.model.compiler
import dahu.model.functions.{Fun, FunN}
import dahu.model.ir.{ComputationF, CstF, ExprF, Total}
import dahu.model.math._
import dahu.model.types._
import dahu.recursion._
import dahu.utils.errors._
import dahu.ImmutableArray._
import scala.collection.mutable.ArrayBuffer
......@@ -29,7 +29,7 @@ object Optimizations {
}
val elimEmptyMonoids: PASS = namedPass("elim-empty-monoid") {
case x @ ComputationF(f: Monoid[_], Seq(), _) => f.liftedIdentity
case x @ ComputationF(f: Monoid[_], args, _) if args.isEmpty => f.liftedIdentity
case x => x
}
private val FALSE: Fix[Total] = Fix(CstF(Value(false), Tag.ofBoolean))
......@@ -80,8 +80,8 @@ object Optimizations {
}
val elimSingletonAndOr: PASS = namedPass("elim-singleton-and-or") {
case ComputationF(bool.And, Seq(arg), _) => arg.unfix
case ComputationF(bool.Or, Seq(arg), _) => arg.unfix
case ComputationF(bool.And, Arr1(arg), _) => arg.unfix
case ComputationF(bool.Or, Arr1(arg), _) => arg.unfix
case x => x
}
......@@ -92,8 +92,8 @@ object Optimizations {
}
val elimTautologies: PASS = namedPass("elim-tautologies") {
case ComputationF(int.LEQ, Seq(a1, a2), _) if a1 == a2 => TRUE.unfix
case ComputationF(int.EQ, Seq(a1, a2), _) if a1 == a2 => TRUE.unfix
case ComputationF(int.LEQ, Arr2(a1, a2), _) if a1 == a2 => TRUE.unfix
case ComputationF(int.EQ, Arr2(a1, a2), _) if a1 == a2 => TRUE.unfix
case x => x
}
}
......
......@@ -5,7 +5,7 @@ import cats.implicits._
import cats.kernel.Monoid
import dahu.model.input.Present
import dahu.model.ir._
import dahu.model.types.Value
import dahu.model.types._
import dahu.utils.errors._
import dahu.recursion._
import dahu.recursion.Recursion._
......
package dahu.model.ir
import cats.Functor
import cats.kernel.Hash
import dahu.{ImmutableArray, SFunctor}
import dahu.model.functions.Fun
import dahu.model.input.Ident
import dahu.model.types.{ProductTag, Tag, Type, Value}
import scala.{specialized => sp}
import scala.collection.mutable.ArraySeq
import scala.language.implicitConversions
import scala.reflect.ClassTag
import scala.runtime.ScalaRunTime
sealed trait ExprF[@specialized(Int) F] {
sealed trait ExprF[@sp(Int) F] {
def typ: Type
override final val hashCode: Int = ExprF.hash(this)
override final lazy val hashCode: Int = ExprF.hash(this)
}
sealed trait TotalOrOptionalF[@specialized(Int) F] { self: ExprF[F] =>
sealed trait TotalOrOptionalF[@sp(Int) F] { self: ExprF[F] =>
def typ: Type
}
sealed trait TotalOrPartialF[@specialized(Int) F] { self: ExprF[F] =>
sealed trait TotalOrPartialF[@sp(Int) F] { self: ExprF[F] =>
def typ: Type
}
object TotalOrOptionalF {
implicit val functor: Functor[TotalOrOptionalF] = new Functor[TotalOrOptionalF] {
override def map[A, B](fa: TotalOrOptionalF[A])(f: A => B): TotalOrOptionalF[B] = fa match {
case fa: Total[A] => Total.functor.map(fa)(f)
implicit val functor: SFunctor[TotalOrOptionalF] = new SFunctor[TotalOrOptionalF] {
override def smap[@sp(Int) A, @sp(Int) B: ClassTag](fa: TotalOrOptionalF[A])(f: A => B): TotalOrOptionalF[B] = fa match {
case fa: Total[A] => Total.functor.smap(fa)(f)
case OptionalF(value, present, typ) =>
OptionalF(f(value), f(present), typ)
}
......@@ -33,9 +33,9 @@ object TotalOrOptionalF {
}
object ExprF {
implicit val functor: Functor[ExprF] = new Functor[ExprF] {
override def map[A, B](fa: ExprF[A])(f: A => B): ExprF[B] = fa match {
case fa: Total[A] => Total.functor.map(fa)(f)
implicit val functor: SFunctor[ExprF] = new SFunctor[ExprF] {
override def smap[@sp(Int) A, @sp(Int) B: ClassTag](fa: ExprF[A])(f: A => B): ExprF[B] = fa match {
case fa: Total[A] => Total.functor.smap(fa)(f)
case Partial(value, condition, typ) =>
Partial(f(value), f(condition), typ)
case OptionalF(value, present, typ) =>
......@@ -45,7 +45,7 @@ object ExprF {
}
}
def hash[A](exprF: ExprF[A]): Int = exprF match {
def hash[@sp(Int) A](exprF: ExprF[A]): Int = exprF match {
case x: ComputationF[A] => ScalaRunTime._hashCode(x)
case x: InputF[A] => ScalaRunTime._hashCode(x)
case x: CstF[A] => ScalaRunTime._hashCode(x)
......@@ -62,26 +62,29 @@ object ExprF {
*
* A Fix[Pure] can always be evaluated to its value.
* */
sealed trait Total[@specialized(Int) F]
sealed trait Total[@sp(Int) F]
extends ExprF[F]
with TotalOrOptionalF[F]
with TotalOrPartialF[F]
object Total {
implicit val functor: Functor[Total] = new Functor[Total] {
override def map[@specialized(Int) A, @specialized(Int) B](fa: Total[A])(f: A => B): Total[B] =
implicit val functor: SFunctor[Total] = new SFunctor[Total] {
override def smap[@sp(Int) A, @sp(Int) B: ClassTag](fa: Total[A])(f: A => B): Total[B] =
fa match {
case x @ InputF(_, _) => x
case x @ CstF(_, _) => x
case ComputationF(fun, args, typ) => ComputationF(fun, args.map(f), typ)
case ComputationF(fun, args, typ) => new ComputationF(fun, implicitly[SFunctor[ImmutableArray]].smap(args)(f), typ)
case ProductF(members, typ) => ProductF(members.map(f), typ)
case ITEF(cond, onTrue, onFalse, typ) => ITEF(f(cond), f(onTrue), f(onFalse), typ)
}
}
trait FunctorSpec[F[_]] {
def map[A, B: ClassTag](fa: F[A])(f: A => B): F[B]
}
}
/** An (unset) input to the problem.
* Essentially a decision variable in CSP jargon. */
case class InputF[@specialized(Int) F](id: Ident, typ: Type) extends Total[F] {
case class InputF[@sp(Int) F](id: Ident, typ: Type) extends Total[F] {
override def toString: String = s"$id"
}
object InputF {
......@@ -91,7 +94,7 @@ object InputF {
implicit def typeParamConversion[F, G](fa: InputF[F]): InputF[G] = fa.asInstanceOf[InputF[G]]
}
case class CstF[@specialized(Int) F](value: Value, typ: Type) extends Total[F] {
case class CstF[@sp(Int) F](value: Value, typ: Type) extends Total[F] {
override def toString: String = value.toString
}
object CstF {
......@@ -100,25 +103,26 @@ object CstF {
implicit def typeParamConversion[F, G](fa: CstF[F]): CstF[G] = fa.asInstanceOf[CstF[G]]
}
final case class ComputationF[@specialized(Int) F](fun: Fun[_], args: ArraySeq[F], typ: Type)
final case class ComputationF[@sp(Int) F](fun: Fun[_], args: ImmutableArray[F], typ: Type)
extends Total[F] {
override def toString: String = s"$fun(${args.mkString(", ")})"
}
object ComputationF {
def apply[F](fun: Fun[_], args: Seq[F], tpe: Type): ComputationF[F] =
new ComputationF(fun, ArraySeq(args: _*), tpe)
def apply[F : ClassTag](fun: Fun[_], args: Seq[F], tpe: Type): ComputationF[F] =
new ComputationF(fun, ImmutableArray.fromArray(args.toArray), tpe)
}
final case class ProductF[@specialized(Int) F](members: ArraySeq[F], typ: ProductTag[Any])
final case class ProductF[@sp(Int) F](members: ImmutableArray[F], typ: ProductTag[Any])
extends Total[F] {
override def toString: String = members.mkString("(", ", ", ")")
}
object ProductF {
def apply[F](args: Seq[F], tpe: ProductTag[Any]): ProductF[F] =
new ProductF[F](ArraySeq(args: _*), tpe)
def apply[F: ClassTag](args: Seq[F], tpe: ProductTag[Any]): ProductF[F] =
new ProductF[F](ImmutableArray.fromArray(args.toArray), tpe)
}
final case class ITEF[@specialized(Int) F](cond: F, onTrue: F, onFalse: F, typ: Type)
final case class ITEF[@sp(Int) F](cond: F, onTrue: F, onFalse: F, typ: Type)
extends Total[F] {
override def toString: String = s"ite($cond, $onTrue, $onFalse)"
}
......@@ -129,21 +133,21 @@ final case class PresentF[F](optional: F) extends ExprF[F] {
override def toString: String = s"present($optional)"
}
final case class ValidF[F](partial: F) extends ExprF[F] {
final case class ValidF[@sp(Int) F](partial: F) extends ExprF[F] {
override def typ: Type = Tag.ofBoolean
override def toString: String = s"valid($partial)"
}
/** An Optional expression, that evaluates to Some(value) if present == true and to None otherwise. */
final case class OptionalF[F](value: F, present: F, typ: Type)
final case class OptionalF[@sp(Int) F](value: F, present: F, typ: Type)
extends ExprF[F]
with TotalOrOptionalF[F] {
override def toString: String = s"$value? (presence: $present)"
}
/** A partial expression that only produces a value if its condition evaluates to True. */
final case class Partial[F](value: F, condition: F, typ: Type)
final case class Partial[@sp(Int) F](value: F, condition: F, typ: Type)
extends ExprF[F]
with TotalOrPartialF[F] {
override def toString: String = s"$value? (constraint: $condition)"
......
......@@ -2,9 +2,8 @@ package dahu.model.problem
import cats.Functor
import cats.implicits._
import dahu.graphs.DAG
import dahu.maps.{ArrayMap, Counter, Wrapped}
import dahu.maps.growable.GrowableBiMap
import dahu.SFunctor
import dahu.ImmutableArray.Arr1
import dahu.model.functions._
import dahu.model.input.Anonymous
import dahu.model.ir._
......@@ -15,6 +14,7 @@ import dahu.model.types._
import dahu.utils.errors._
import scala.collection.mutable
import scala.reflect.ClassTag
class IntBoolSatisfactionProblem[X](val ast: RootedLazyTree[X, Total, cats.Id]) {
......@@ -59,14 +59,14 @@ class IntBoolSatisfactionProblem[X](val ast: RootedLazyTree[X, Total, cats.Id])
bool.XOr,
bool.Not)
abstract class LazyTree[K, F[_]: TreeNode: Functor, G[_], Opt[_]: Functor](
abstract class LazyTree[K, F[_]: TreeNode: SFunctor, G[_], Opt[_]: Functor](
orig: ILazyTree[K, F, Opt])
extends ILazyTree[K, G, Opt] {
def g(rec: G[ID] => ID)(prev: ID => G[ID])(node: F[ID]): G[ID]
private val treeNode = implicitly[TreeNode[F]]
private val functor = implicitly[Functor[F]]
private val functor = implicitly[SFunctor[F]]
private val idsMap = mutable.HashMap[orig.ID, ID]()
private val repMap = mutable.ArrayBuffer[G[ID]]() // ID => G[ID]
......@@ -104,7 +104,7 @@ class IntBoolSatisfactionProblem[X](val ast: RootedLazyTree[X, Total, cats.Id])
if(!processed(cur)) {
val fk = orig.getInt(cur)
if(treeNode.children(fk).forall(processed)) {
val fg: F[ID] = functor.map(fk)(id => idsMap(id))
val fg: F[ID] = functor.smap(fk)(id => idsMap(id))
val g: G[ID] = g2(fg)
val id = rec(g)
idsMap += ((cur, id))
......@@ -129,7 +129,7 @@ class IntBoolSatisfactionProblem[X](val ast: RootedLazyTree[X, Total, cats.Id])
case _ => true
}
private def TRANS[K](rec: CellOpt[K] => K)(prev: K => CellOpt[K])(
private def TRANS[K: ClassTag](rec: CellOpt[K] => K)(prev: K => CellOpt[K])(
node: Total[K]): CellOpt[K] = {
def and(conjuncts: CellOpt[K]*): CellOpt[K] = {
IntermediateExpression(
......@@ -158,7 +158,7 @@ class IntBoolSatisfactionProblem[X](val ast: RootedLazyTree[X, Total, cats.Id])
if supportedFunctions.contains(wf.f) && args.forall(x => sup(prev(x))) =>
TRANS(rec)(prev)(ComputationF(wf.f, args, t)) // unwrap and retry
case x @ ComputationF(f: Unboxed[_], Seq(arg), t) =>
case x @ ComputationF(f: Unboxed[_], Arr1(arg), t) =>
prev(arg) // unbox operation, use the previous cell
case x =>
......
......@@ -2,9 +2,7 @@ package dahu.model.problem
import cats.Functor
import cats.implicits._
import dahu.maps.{ArrayMap, Counter, Wrapped}
import dahu.maps.growable.GrowableBiMap
import dahu.model.compiler.Algebras
import dahu.SFunctor
import dahu.model.ir._
import dahu.model.math.bool
import dahu.model.problem.SatisfactionProblemFAST.{ILazyTree, RootedLazyTree}
......@@ -68,7 +66,7 @@ object SatisfactionProblem {
def and(conjuncts: Fix[Total]*): Fix[Total] = {
assert(conjuncts.forall(c => c.unfix.typ == Tag.ofBoolean))
val nonEmptyConjuncts = conjuncts.filter {
case ComputationF(bool.And, Seq(), _) => false
case ComputationF(bool.And, args, _) if args.isEmpty => false
case CstF(true, _) => false
case _ => true
}
......@@ -300,7 +298,7 @@ object SatisfactionProblemFAST {
class LazyTreeSpec[@specialized(Int) K](f: K => ExprF[K], g: Context => ExprF[IR[ID]] => IR[ID]) {
private val treeNode = implicitly[TreeNode[ExprF]]
private val functor = implicitly[Functor[ExprF]]
private val functor = implicitly[SFunctor[ExprF]]
private val idsMap = mutable.HashMap[K, IR[ID]]()
private val repMap = mutable.ArrayBuffer[Total[ID]]() // ID => Total[ID]
......@@ -332,7 +330,7 @@ object SatisfactionProblemFAST {
val cur = queue.pop()
val fk = f(cur)
if(treeNode.children(fk).forall(processed)) {
val fg = functor.map(fk)(id => idsMap(id))
val fg = functor.smap(fk)(id => idsMap(id))
val g: IR[ID] = g2(fg)
idsMap += ((cur, g))
} else {
......
......@@ -36,6 +36,9 @@ object Main extends App {
opt[Int]("warmup")
.action((t, c) => c.copy(warmupTimeSec = t))
opt[Int]("min-depth")
.action((d, c) => c.copy(minInstances = d))
opt[Int]("max-depth")
.action((d, c) => c.copy(maxInstances = d))
......
package dahu.recursion
//import scalaz.{-\/, Free, Functor, Monad, \/, \/-}
import cats.{Functor, Monad}
import cats.free.{Cofree, Free}
import cats.free.Free
import dahu.SFunctor
final class FAlgebraOps[F[_], A](private val self: FAlgebra[F, A]) extends AnyVal {
......@@ -34,7 +34,7 @@ final class FCoalgebraOps[F[_], A](private val self: FCoalgebra[F, A]) extends A
def toCVCoalgebra(implicit F: Functor[F]): CVCoalgebra[F, A] =
a => F.map(self(a))(Free.pure)
def toAttributeCoalgebra(implicit F: Functor[F]): AttributeCoalgebra[F, A] =
def toAttributeCoalgebra(implicit F: SFunctor[F]): AttributeCoalgebra[F, A] =
a => EnvT(a, self(a))
def cozip[B](that: FCoalgebra[F, B])(implicit F: Functor[F]): FCoalgebra[F, Either[A, B]] = {
......
package dahu.recursion
import cats.{Functor, Monad, Traverse}
import cats.{Monad, Traverse}
import dahu.SFunctor
import scala.reflect.ClassTag
/**
* Beginner-friendly. No Greek.
*/
object EasyRecursion {
def fold[F[_]: Functor, A](alg: FAlgebra[F, A])(f: Fix[F]): A =
def fold[F[_]: SFunctor, A: ClassTag](alg: FAlgebra[F, A])(f: Fix[F]): A =
Recursion.cata(alg)(f)
def unfold[F[_]: Functor, A](coalg: FCoalgebra[F, A])(a: A): Fix[F] =
def unfold[F[_]: SFunctor, A: ClassTag](coalg: FCoalgebra[F, A])(a: A)(implicit ct: ClassTag[F[Fix[F]]]): Fix[F] =
Recursion.ana(coalg)(a)
def unfoldIntoFold[F[_]: Functor, A, B](coalg: FCoalgebra[F, A], alg: FAlgebra[F, B])(a: A): B =
def unfoldIntoFold[F[_]: SFunctor, A, B: ClassTag](coalg: FCoalgebra[F, A], alg: FAlgebra[F, B])(a: A): B =
Recursion.hylo(coalg, alg)(a)
def monadicFold[M[_]: Monad, F[_]: Traverse, A](alg: FAlgebraM[M, F, A])(f: Fix[F]): M[A] =
......
package dahu.recursion
import cats.{~>, Functor, Monad, Traverse}
import cats.{Functor, Monad, Traverse, ~>}
import dahu.SFunctor
import scala.reflect.ClassTag
object Recursion {
def cata[F[_], A](alg: FAlgebra[F, A])(f: Fix[F])(implicit F: Functor[F]): A =
def cata[F[_], A : ClassTag](alg: FAlgebra[F, A])(f: Fix[F])(implicit F: SFunctor[F]): A =
RecursionFn.cata(alg).apply(f)
def cataM[M[_], F[_], A](alg: FAlgebraM[M, F, A])(f: Fix[F])(implicit M: Monad[M],
F: Traverse[F]): M[A] =
RecursionFn.cataM(alg).apply(f)
def ana[F[_], A](coalg: FCoalgebra[F, A])(a: A)(implicit F: Functor[F]): Fix[F] =
def ana[F[_], A: ClassTag](coalg: FCoalgebra[F, A])(a: A)(implicit F: SFunctor[F], ct: ClassTag[F[Fix[F]]]): Fix[F] =
RecursionFn.ana(coalg).apply(a)
def anaM[M[_], F[_], A](coalg: FCoalgebraM[M, F, A])(a: A)(implicit M: Monad[M],
......@@ -19,8 +22,8 @@ object Recursion {
RecursionFn.anaM(coalg).apply(a)
/** ana with immediate cata */
def hylo[F[_], A, B](coalg: FCoalgebra[F, A], alg: FAlgebra[F, B])(a: A)(
implicit F: Functor[F]): B =
def hylo[F[_], A, B: ClassTag](coalg: FCoalgebra[F, A], alg: FAlgebra[F, B])(a: A)(
implicit F: SFunctor[F]): B =
RecursionFn.hylo(coalg, alg).apply(a)
def hyloM[M[_], F[_], A, B](coalg: FCoalgebraM[M, F, A], alg: FAlgebraM[M, F, B])(
......@@ -31,14 +34,14 @@ object Recursion {
* Top-most structure (i.e. the input) is not transformed.
* Outside to inside.
*/
def prepro[F[_], A](pre: F ~> F, alg: FAlgebra[F, A])(f: Fix[F])(implicit F: Functor[F]): A =
def prepro[F[_], A: ClassTag](pre: F ~> F, alg: FAlgebra[F, A])(f: Fix[F])(implicit F: SFunctor[F], ct: ClassTag[F[Fix[F]]]): A =
RecursionFn.prepro(pre, alg).apply(f)
/** ana that creates a structure, transforming each new child (i.e. the entire structure as exists at the end of a pass).
* Top-most structure (i.e. the end result) is not transformed.
* Inside to outside.
*/
def postpro[F[_], A](coalg: FCoalgebra[F, A], pro: F ~> F)(a: A)(implicit F: Functor[F]): Fix[F] =
def postpro[F[_], A: ClassTag](coalg: FCoalgebra[F, A], pro: F ~> F)(a: A)(implicit F: SFunctor[F], ct: ClassTag[F[Fix[F]]]): Fix[F] =
RecursionFn.postpro(coalg, pro).apply(a)
/** hylo that can short-circuit on construction */
......
package dahu.recursion
import cats.{~>, Comonad, Eval, Functor, Monad, Traverse}
import cats.{Comonad, Eval, Functor, Monad, Traverse, ~>}
import cats.free.{Cofree, Free}
import dahu.SFunctor
import spire.ClassTag
object RecursionFn {
def cata[F[_], A](alg: FAlgebra[F, A])(implicit F: Functor[F]): Fix[F] => A = {
def cata[F[_], A : ClassTag](alg: FAlgebra[F, A])(implicit F: SFunctor[F]): Fix[F] => A = {
var self: Fix[F] => A = null
self = f => alg(F.map(f.unfix)(self))
self = f => alg(F.smap(f.unfix)(self))
self
}
......@@ -18,9 +20,9 @@ object RecursionFn {
self
}
def ana[F[_], A](coalg: FCoalgebra[F, A])(implicit F: Functor[F]): A => Fix[F] = {
def ana[F[_], A : ClassTag](coalg: FCoalgebra[F, A])(implicit F: SFunctor[F], ct: ClassTag[F[Fix[F]]]): A => Fix[F] = {
var self: A => Fix[F] = null
self = a => Fix[F](F.map(coalg(a))(self))
self = a => Fix[F](F.smap(coalg(a))(self))
self
}
......@@ -32,10 +34,10 @@ object RecursionFn {
}
/** ana with immediate cata */
def hylo[F[_], A, B](coalg: FCoalgebra[F, A], alg: FAlgebra[F, B])(
implicit F: Functor[F]): A => B = {
def hylo[F[_], A, B: ClassTag](coalg: FCoalgebra[F, A], alg: FAlgebra[F, B])(
implicit F: SFunctor[F]): A => B = {
var self: A => B = null
self = a => alg(F.map(coalg(a))(self))
self = a => alg(F.smap(coalg(a))(self))
self
}
......@@ -51,12 +53,12 @@ object RecursionFn {
* Top-most structure (i.e. the input) is not transformed.
* Outside to inside.
*/
def prepro[F[_], A](pre: F ~> F, alg: FAlgebra[F, A])(implicit F: Functor[F]): Fix[F] => A = {
def prepro[F[_], A: ClassTag](pre: F ~> F, alg: FAlgebra[F, A])(implicit F: SFunctor[F], ct: ClassTag[F[Fix[F]]]): Fix[F] => A = {
var self: Fix[F] => A = null
val algF: FAlgebra[F, Fix[F]] = f => Fix[F](pre(f))
val cataF: Fix[F] => Fix[F] = cata(algF)
val inner: Fix[F] => A = f => self(cataF(f))
self = f => alg(F.map(f.unfix)(inner))
self = f => alg(F.smap(f.unfix)(inner))
/*
// Inspection
var space = ""
......@@ -79,13 +81,13 @@ object RecursionFn {
* Top-most structure (i.e. the end result) is not transformed.
* Inside to outside.
*/
def postpro[F[_], A](coalg: FCoalgebra[F, A], pro: F ~> F)(
implicit F: Functor[F]): A => Fix[F] = {
def postpro[F[_], A : ClassTag](coalg: FCoalgebra[F, A], pro: F ~> F)(
implicit F: SFunctor[F], ct: ClassTag[F[Fix[F]]]): A => Fix[F] = {
var self: A => Fix[F] = null
val algF: FCoalgebra[F, Fix[F]] = f => pro(f.unfix)
val anaF: Fix[F] => Fix[F] = ana(algF)
val inner: A => Fix[F] = a => anaF(self(a))
self = a => Fix[F](F.map(coalg(a))(inner))
self = a => Fix[F](F.smap(coalg(a))(inner))
/*
// Inspection
var space = ""
......
......@@ -3,7 +3,9 @@ package dahu
import cats.{Applicative, Eval, Functor, Traverse}
import cats.free.{Cofree, Free}
import scala.language.implicitConversions
import scala.reflect.ClassTag
package object recursion {
......@@ -33,6 +35,8 @@ package object recursion {
Fix.unfix(self)
}
implicit def fixClassTag[F[_]](implicit ct: ClassTag[F[Fix[F]]]): ClassTag[Fix[F]] = ct.asInstanceOf[ClassTag[Fix[F]]]
@inline implicit def fAlgebraOps[F[_], A](self: F[A] => A): FAlgebraOps[F, A] =
new FAlgebraOps(self)
......@@ -49,6 +53,13 @@ package object recursion {
override def map[A, B](fa: EnvT[Z, F, A])(f: A => B): EnvT[Z, F, B] =
EnvT(fa.ask, F.map(fa.lower)(f))
}
implicit def envTSFunctor[Z, F[_]](implicit F: SFunctor[F]): SFunctor[EnvT[Z, F, ?]] =
new SFunctor[EnvT[Z, F, ?]] {
override def smap[@specialized(Int) A, @specialized(Int) B: ClassTag](fa: EnvT[Z, F, A])(f: A => B): EnvT[Z, F, B] =
EnvT(fa.ask, F.smap(fa.lower)(f))
}
implicit def envTTraverse[Z, F[_]](implicit F: Traverse[F]): Traverse[EnvT[Z, F, ?]] =
new Traverse[EnvT[Z, F, ?]] {
def traverse[G[_], A, B](fa: EnvT[Z, F, A])(f: A => G[B])(
......
package dahu
import scala.{specialized => sp}
import spire.syntax.cfor
import reflect.ClassTag
import collection.immutable.IndexedSeq
import collection.mutable.{ArrayBuilder, Builder}
import collection.IndexedSeqOptimized
import scala.language.implicitConversions
/**
* An immutable wrapper for arrays
*
* @tparam A type of the elements of the array
*/
sealed trait ImmutableArray[@sp A] {
protected[this] def elemTag: ClassTag[A]
def apply(index: Int): A
def copyToArray[B >: A](xs: Array[B], start: Int, len: Int): Unit
def length: Int
def isEmpty: Boolean = length == 0
def toArray[B >: A : ClassTag]: Array[B]
def slice(from: Int, until: Int): ImmutableArray[A]
def ++[B >: A: ClassTag](other: ImmutableArray[B]): ImmutableArray[B]
}
sealed abstract class ImmutableArrayInstances {
implicit object sFunctorInstance extends SFunctor[ImmutableArray] {
override def smap[@sp(Int) A, @sp(Int) B](fa: ImmutableArray[A])(f: A => B)(implicit ct: ClassTag[B]): ImmutableArray[B] = {
val fb = Array.ofDim[B](fa.length)
cfor.cfor(0)(_ < fa.length, _ + 1) { i =>
fb(i) = f(fa(i))
}
ImmutableArray.fromArray(fb)
}
}
}
object ImmutableArray extends ImmutableArrayInstances {
def make[A](x: AnyRef): ImmutableArray[A] = {
val y = x match {
case null => null
case x: Array[Byte] => new ofByte(x)
case x: Array[Short] => new ofShort(x)
case x: Array[Char] => new ofChar(x)
case x: Array[Int] => new ofInt(x)
case x: Array[Long] => new ofLong(x)
case x: Array[Float] => new ofFloat(x)
case x: Array[Double] => new ofDouble(x)
case x: Array[Boolean] => new ofBoolean(x)
case x: Array[Unit] => new ofUnit(x)
case x: Array[AnyRef] => new ofRef(x)
}
y.asInstanceOf[ImmutableArray[A]]
}
/**
* Wrap `x` in an `ImmutableArray`.
*
* Provides better type inference than `make[A]`
*/
def fromArray[A](x: Array[A]): ImmutableArray[A] = {
val y = x.asInstanceOf[AnyRef] match {
case null => null
case x: Array[Byte] => new ofByte(x)
case x: Array[Short] => new ofShort(x)
case x: Array[Char] => new ofChar(x)
case x: Array[Int] => new ofInt(x)
case x: Array[Long] => new ofLong(x)
case x: Array[Float] => new ofFloat(x)