Skip to content

Commit

Permalink
rename Lists to Choices + add readme
Browse files Browse the repository at this point in the history
  • Loading branch information
fwbrasil committed Sep 17, 2023
1 parent b249e38 commit 3a2dfe8
Show file tree
Hide file tree
Showing 8 changed files with 112 additions and 246 deletions.
34 changes: 34 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,40 @@ val b: Int > IOs =
Resources.run(a)
```

### Choices: Decision Making and Exploration

The Choices effect is designed to aid in handling and exploring multiple options, pathways, or outcomes in a computation. This effect is particularly useful in scenarios where you're dealing with decision trees, backtracking algorithms, or any situation that involves dynamically exploring multiple options.

```scala
import kyo.choices._

// Evaluate each of the provided choices.
// Note how 'foreach' takes a 'List[T]'
// returns a 'T > Choices'
val a: Int > Choices =
Choices.foreach(List(1, 2, 3, 4))

// 'dropIf' discards the current choice if
// a condition is not met. Produces a 'List(1, 2)'
val b: Int > Choices =
a.map(v => Choices.dropIf(v > 2))

// 'drop' unconditionally discards the
// current choice. Produces a 'List(42)'
val c: Int > Choices =
b.map {
case 1 => 42
case _ => Choices.discard
}

// Handle the effect to evaluate all choices
// and return a 'List' with the results
val d: List[Int] > Any =
Choices.run(c)
```

The Choices effect becomes exceptionally powerful when combined with other effects. This allows you not just to make decisions or explore options in isolation but also to do so in contexts that might involve asynchronicity, resource management, or even user interaction.

### Aspects: Aspect-Oriented Programming (AOP)

The `Aspects` effects provide a mechanism for users to customize the behavior of a computation. Aspects in Kyo are expressed as first-class values, which enables flexible scoping. For example, users may instantiate aspects and reduce their visibility via regular field modifiers.
Expand Down
4 changes: 2 additions & 2 deletions kyo-bench/src/main/scala/kyo/bench/CollectAllBench.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import org.openjdk.jmh.annotations._
import cats.effect.IO
import kyo._
import kyo.ios._
import kyo.lists._
import kyo.choices._
import kyo.concurrent.fibers._

class CollectAllBench extends Bench.SyncAndFork[Long] {
Expand All @@ -16,7 +16,7 @@ class CollectAllBench extends Bench.SyncAndFork[Long] {
import kyo.ios._

val tasks = (0 until count).map(_ => IOs(1)).toList
Lists.collect(tasks).map(_.sum.toLong)
Choices.collect(tasks).map(_.sum.toLong)
}

def catsBench() = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,50 +5,50 @@ import kyo.core._
import kyo.options._
import scala.collection.mutable.ListBuffer

object lists {
object choices {

final class Lists private[lists] () extends Effect[List, Lists] {
final class Choices private[choices] () extends Effect[List, Choices] {

private implicit val handler: Handler[List, Lists] =
new Handler[List, Lists] {
private implicit val handler: Handler[List, Choices] =
new Handler[List, Choices] {
def pure[T](v: T) = List(v)
def apply[T, U, S](v: List[T], f: T => U > (Lists with S)): U > (Lists with S) = {
def loop(l: List[T], acc: List[List[U]]): U > (Lists with S) =
def apply[T, U, S](v: List[T], f: T => U > (Choices with S)): U > (Choices with S) = {
def loop(l: List[T], acc: List[List[U]]): U > (Choices with S) =
l match {
case Nil =>
Lists.foreach(acc.reverse.flatten: List[U])
Choices.foreach(acc.reverse.flatten: List[U])
case t :: ts =>
Lists.run[U, S](f(t)).map(l => loop(ts, l :: acc))
Choices.run[U, S](f(t)).map(l => loop(ts, l :: acc))
}
loop(v, Nil)
}
}

def run[T, S](v: T > (Lists with S)): List[T] > S =
def run[T, S](v: T > (Choices with S)): List[T] > S =
handle[T, S](v)

def foreach[T, S](v: List[T] > S): T > (Lists with S) =
def foreach[T, S](v: List[T] > S): T > (Choices with S) =
v.map {
case head :: Nil => head
case _ => suspend(v)
}

def traverse[T, U, S, S2](v: List[T] > S)(f: T => U > S2): List[U] > (S with S2) =
v.map { v =>
collect(v.map(f))
}

def filter[S](v: Boolean > S): Unit > (Lists with S) =
def dropIf[S](v: Boolean > S): Unit > (Choices with S) =
v.map {
case true =>
()
case false =>
drop
}

def drop[T]: T > Lists =
def drop[T]: T > Choices =
suspend(List.empty[T])

def traverse[T, U, S, S2](v: List[T] > S)(f: T => U > S2): List[U] > (S with S2) =
v.map { v =>
collect(v.map(f))
}

def collect[T, S](v: List[T > S]): List[T] > S = {
val buff = ListBuffer[T]()
def loop(v: List[T > S]): List[T] > S =
Expand All @@ -63,5 +63,5 @@ object lists {
loop(v)
}
}
val Lists = new Lists
val Choices = new Choices
}
4 changes: 2 additions & 2 deletions kyo-core/shared/src/main/scala/kyo/concurrent/meters.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import scala.concurrent.duration.Duration
import channels._
import fibers._
import timers._
import kyo.lists.Lists
import kyo.choices.Choices

object meters {

Expand Down Expand Up @@ -95,7 +95,7 @@ object meters {
pipeline[S1 with S2 with S3 with S4](List(m1, m2, m3, m4))

def pipeline[S](l: List[Meter > (IOs with S)]): Meter > (IOs with S) =
Lists.collect(l).map { meters =>
Choices.collect(l).map { meters =>
new Meter {

val available = {
Expand Down
45 changes: 45 additions & 0 deletions kyo-core/shared/src/test/scala/kyoTest/choicesTest.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package kyoTest

import kyo.concurrent.fibers._
import kyo._
import kyo.ios.IOs
import kyo.choices._

class choicesTest extends KyoTest {

"one" in {
checkEquals[List[Int], Nothing](
Choices.run(Choices.foreach(List(1)).map(_ + 1)),
List(2)
)
}
"multiple" in {
checkEquals[List[Int], Nothing](
Choices.run(Choices.foreach(List(1, 2, 3)).map(_ + 1)),
List(2, 3, 4)
)
}
"nested" in {
checkEquals[List[Int], Nothing](
Choices.run(Choices.foreach(List(1, 2, 3)).map(i => Choices.foreach(List(i * 10, i * 100)))),
List(10, 100, 20, 200, 30, 300)
)
}
"drop" in {
checkEquals[List[Int], Nothing](
Choices.run(Choices.foreach(List(1, 2, 3)).map(i =>
if (i < 2) Choices.drop
else Choices.foreach(List(i * 10, i * 100))
)),
List(20, 200, 30, 300)
)
}
"filter" in {
checkEquals[List[Int], Nothing](
Choices.run(Choices.foreach(List(1, 2, 3)).map(i =>
Choices.dropIf(i >= 2).map(_ => Choices.foreach(List(i * 10, i * 100)))
)),
List(20, 200, 30, 300)
)
}
}
45 changes: 0 additions & 45 deletions kyo-core/shared/src/test/scala/kyoTest/listsTest.scala

This file was deleted.

Loading

0 comments on commit 3a2dfe8

Please sign in to comment.