define recursive algorithms once and for all
define your recursive data types in fixed point style
case class CompositeTree[A](leftChild: A, rightChild: A)
final class Participant(value: String) extends AnyVal
sealed trait Draw
case class FutureMatch(left: Draw, right: Draw) extends Draw
case class Match(left: Participant, right: Participant) extends Draw
Match
FutureMatch
final class Participant(value: String) extends AnyVal
sealed trait Draw
case class FutureMatch(left: Draw, right: Draw) extends Draw
case class Match(left: Participant, right: Participant) extends Draw
def size(d: Draw): Int = {
d match {
case Match(_,_) => 2
case FutureMatch(left, right) => size(left) + size(right)
}
}
final class Participant(value: String) extends AnyVal
type Draw = Fix[DrawF]
sealed trait DrawF[A]
case class FutureMatchF[A](left: A, right: A) extends DrawF[A]
case class MatchF[A](left: Participant, right: Participant) extends DrawF[A]
Match
FutureMatch
def size(d: Draw): Int = {
d.cata {
case MatchF(_,_) => 2
case FutureMatchF(left, right) => left + right
}
}
final class Participant(value: String) extends AnyVal
type Draw = Fix[DrawF]
sealed trait DrawF[A]
case class FutureMatchF[A](left: A, right: A) extends DrawF[A]
case class MatchF[A](left: Participant, right: Participant) extends DrawF[A]
sealed trait Draw
case class FutureMatch(left: Draw, right: Draw) extends Draw
case class Match(left: Participant, right: Participant) extends Draw
// The participant in the draw with the best chance of winning the tournament
def bestChanceOfWinning(d: Draw): Task[Participant] = {
def bestChanceOfWinningR(d: Draw): Task[(Participant,Float)] =
d match {
case Match(left, right) => chanceOfWining(left, right).map(chance =>
if (chance > 0.5) (left, chance) else (right, (1 - chance))
)
case FutureMatch(left, right) =>
for {
left <- bestChanceOfWinningR(left)
(leftPart, leftChance) = left
right <- bestChanceOfWinningR(right)
(rightPart, rightChance) = right
chance <- chanceOfWining(leftPart, rightPart)
} yield {
val leftNewChance = leftChance * chance
val rightNewChance = rightChance * (1 - chance)
if (leftNewChance > rightNewChance) (leftPart, leftNewChance)
else (rightPart, rightNewChance)
}
}
bestChanceOfWinningR(d)._1
}
def probabilityOfWin(candidate: Participant, over: Participant): Task[Float]
// The participant in the draw with the best chance of winning the tournament
def bestChanceOfWinning(d: Draw) =
d.cataM{
case MatchF(left, right) =>
chanceOfWining(left, right).map( chance =>
if (chance > 0.5) (left, chance) else (right, (1 - chance))
)
case FutureMatchF((leftPart, leftChance), (rightPart, rightChance)) =>
chanceOfWining(leftPart, rightPart).map { chance =>
val leftNewChance = leftChance * chance
val rightNewChance = rightChance * (1 - chance)
if (leftNewChance > rightNewChance) (leftPart, leftNewChance)
else (rightPart, rightNewChance)
}
}._1
def probabilityOfWin(candidate: Participant, over: Participant): Task[Float]
type Draw = Fix[DrawF]
sealed trait DrawF[A]
case class FutureMatchF[A](left: A, right: A) extends DrawF[A]
case class MatchF[A](left: Participant, right: Participant) extends DrawF[A]
def bestChanceOfWinning(d: Draw) =
d.cataM{
case FutureMatchF((leftPart, leftChance), (rightPart, rightChance)) =>
chanceOfWining(leftPart, rightPart).map { chance =>
val leftNewChance = leftChance * chance
val rightNewChance = rightChance * (1 - chance)
if (leftNewChance > rightNewChance) (leftPart, leftNewChance)
else (rightPart, rightNewChance)
}
}._1
def bestChanceOfWinning(d: Draw): Task[Participant] = {
def bestChanceOfWinningR(d: Draw): Task[(Participant,Float)] =
d match {
case FutureMatch(left, right) =>
for {
left <- bestChanceOfWinningR(left)
(leftPart, leftChance) = left
right <- bestChanceOfWinningR(right)
(rightPart, rightChance) = right
chance <- chanceOfWining(leftPart, rightPart)
} yield {
val leftNewChance = leftChance * chance
val rightNewChance = rightChance * (1 - chance)
if (leftNewChance > rightNewChance) (leftPart, leftNewChance)
else (rightPart, rightNewChance)
}
}
bestChanceOfWinningR(d)._1
}
sealed trait Draw
case class FutureMatch(left: Draw, right: Draw) extends Draw
case class Match(left: Participant, right: Participant) extends Draw
a match {
case xs if xs.size < 2 => None
case x1 :: x2 :: Nil => Some(Match(x1, x2))
case xs =>
val (left,right) = xs.split(xs.size / 2)
(fromList(left) ⊛ fromList(right))(FutureMatch)
}
def fromList(a: List[Participant]): Option[Draw] =
Fix[DrawF].anaM(a){
case xs if xs.size < 2 => None
case x1 :: x2 :: Nil => Some(MatchF(x1,x2))
case xs =>
val (left,right) = xs.split(xs.size / 2)
Some(FutureMatchF(left,right))
}
def fromList(a: List[Participant]): Option[Draw] =
type Draw = Fix[DrawF]
sealed trait DrawF[A]
case class FutureMatchF[A](left: A, right: A) extends DrawF[A]
case class MatchF[A](left: Participant, right: Participant) extends DrawF[A]
def fromList(a: List[Participant]): Option[Draw] =
Fix[DrawF].anaM(a){
case xs if xs.size < 2 => None
case x1 :: x2 :: Nil => Some(MatchF(x1,x2))
case xs =>
val (left,right) = xs.split(xs.size / 2)
Some(FutureMatchF(left,right))
}
def fromList(a: List[Participant]): Option[Draw] =
a match {
case xs if xs.size < 2 => None
case x1 :: x2 :: Nil => Some(Match(x1, x2))
case xs =>
val (left,right) = xs.split(xs.size / 2)
(fromList(left) ⊛ fromList(right))(FutureMatch)
}
sealed trait DrawF[A]
case class FutureMatchF[A](left: A, right: A) extends DrawF[A]
case class MatchF[A](left: Participant, right: Participant) extends DrawF[A]
FutureMatch[Int] = FutureMatch(3,4)
FutureMatch[String] = FutureMatch("Bob", "Dylan")
val draw: FutureMatch[Draw[Draw[Draw[...]]]] // How to model a recursive draw?
val draw: FutureMatch[Draw[Draw[Draw[...]]]] // How to model a recursive draw?
final case class Fix[F[_]](unFix: F[Fix[F]]) {
def cata...
def cataM...
def ana...
def anaM...
...
}
type Draw = Fix[DrawF]
Theory:
val draw: Fix[DrawF]
val futureMatch: FutureMatchF[Fix[DrawF]] = draw.unfix
val leftSide: Fix[DrawF] = futureMatch.left
val result: FutureMatchF[Fix[DrawF]] = leftSide.unfix
val result1: Fix[DrawF] = result.left
val result2: MatchF[Fix[Draw]] = result1.unfix
val leftParticipant: Participant = result2.left
def cata[F[_]: Functor, A](t: T[F])(f: F[A] => A): A =
f(project(t) ∘ (cata(_)(f)))
data Expr
= Index Expr Expr
| Call Expr [Expr]
| Unary String Expr
| Binary Expr String Expr
| Paren Expr
| Literal Lit
deriving (Show, Eq)
-- this would turn the expression
-- (((anArray[(10)])))
-- into
-- anArray[10]
flatten :: Expr -> Expr
flatten (Literal i) = Literal i
flatten (Paren e) = flatten e
flatten (Index e i) = Index (flatten e) (flatten i)
flatten (Call e args) = Call (flatten e) (map flatten args)
flatten (Unary op arg) = Unary op (flatten arg)
flatten (Binary l op r) = Binary (flatten l) op (flatten r)
data Expr a
= Index a a
| Call [a]
| Unary String a
| Binary a String a
| Paren a
| Literal Lit
deriving (Show, Eq, Functor)
-- this would turn the expression
-- (((anArray[(10)])))
-- into
-- anArray[10]
flatten :: Term Expr -> Term Expr
flatten (In (Paren e)) = e -- remove all Parens
flatten other = other -- do nothing otherwise
// final case class InvokeF[A](func: Func, values: List[A]) extends LogicalPlan[A]
def simpleEvaluation(lp: Fix[LogicalPlan]): FileSystemErrT[InMemoryFs, Vector[Data]] = {
val optLp = Optimizer.optimize(lp)
EitherT[InMemoryFs, FileSystemError, Vector[Data]](State.gets { mem =>
import quasar.LogicalPlan._
import quasar.std.StdLib.set.{Drop, Take}
import quasar.std.StdLib.identity.Squash
optLp.para[FileSystemError \/ Vector[Data]] {
case ReadF(path) =>
// Documentation on `QueryFile` guarantees absolute paths, so calling `mkAbsolute`
val aPath = mkAbsolute(rootDir, path)
fileL(aPath).get(mem).toRightDisjunction(pathErr(pathNotFound(aPath)))
case InvokeF(Drop, (_,src) :: (Fix(ConstantF(Data.Int(skip))),_) :: Nil) =>
src.flatMap(s => skip.safeToInt.map(s.drop).toRightDisjunction(unsupported(optLp)))
case InvokeF(Take, (_,src) :: (Fix(ConstantF(Data.Int(limit))),_) :: Nil) =>
src.flatMap(s => limit.safeToInt.map(s.take).toRightDisjunction(unsupported(optLp)))
case InvokeF(Squash,(_,src) :: Nil) => src
case ConstantF(data) => Vector(data).right
case other =>
queryResponsesL
.get(mem)
.mapKeys(Optimizer.optimize)
.get(Fix(other.map(_._1)))
.toRightDisjunction(unsupported(optLp))
}
})
}
def para[F[_]: Functor, A](t: Fix[F])(f: F[(Fix[F], A)] => A): A
libraryDependencies += "com.slamdata" %% "matryoshka-core" % "0.11.1"