diff --git a/examples/stdlib/search/noteach.check b/examples/stdlib/search/noteach.check new file mode 100644 index 000000000..e440e5c84 --- /dev/null +++ b/examples/stdlib/search/noteach.check @@ -0,0 +1 @@ +3 \ No newline at end of file diff --git a/examples/stdlib/search/noteach.effekt b/examples/stdlib/search/noteach.effekt new file mode 100644 index 000000000..bc0c70906 --- /dev/null +++ b/examples/stdlib/search/noteach.effekt @@ -0,0 +1,35 @@ + +import stream +import search + +type Tree[A] { + Nil() + Branch(v: A, l: Tree[A], r: Tree[A]) +} + +def notEach(t: Tree[Bool]): Tree[Bool] / {fork, fail} = t match { + case Nil() => + do fail() + case Branch(v, l, r) => + choice { + Branch(not(v), l, r) + } { + choice { + Branch(v, notEach(l), r) + } { + Branch(v, l, notEach(r)) + } + } +} + +def count[A] { stream: => Unit / emit[A] }: Int = { + var n = 0 + for[A] { stream() } { _ => n = n + 1 } + n +} + +def main() = { + val example = Branch(false, Branch(false, Nil(), Branch(false, Nil(), Nil())), Nil()) + println(count[Tree[Bool]] { results { notEach(example) } }) +} + diff --git a/libraries/common/search.effekt b/libraries/common/search.effekt new file mode 100644 index 000000000..5d357b461 --- /dev/null +++ b/libraries/common/search.effekt @@ -0,0 +1,64 @@ +module search + +import stream + + +effect fork(): Bool +effect fail(): Nothing + +def select[A] { stream: () => Unit / emit[A] }: A / {fork, fail} = { + def body(): A / emit[A] = { + stream() + do fail() + } + try { + body() + } with emit[A] { value => + if (do fork()) { + return value + } else { + resume(()) + } + } +} + +def results[R] { query: () => R / {fork, fail} }: Unit / emit[R] = + try { + do emit(query()) + } with fork { () => + resume(true) + resume(false) + } with fail { () => + () + } + +def choose[A](items: List[A]): A / {fork, fail} = + select { items.each } + +def choice[A] { action1: () => A } { action2: () => A }: A / fork = + if (do fork()) { action1() } else { action2() } + +def where(condition: Bool): Unit / fail = + if (condition) { () } else { do fail() } + + +type Key = String +type Option = String + +type Menu = List[(Key, List[Option])] +type Meal = List[(Key, Option)] + +def allMeals(menu: Menu): Meal / {fork, fail} = + menu.map { case (category, options) => (category, options.choose) } + +def main() = { + val menu = [ + ("Protein", ["Chicken", "Beef", "Tofu"]), + ("Carbs", ["Rice", "Pasta", "French Fries"]), + ("Veggie", ["Bell Pepper", "Brocolli"]) + ] + for[Meal] { results { allMeals(menu) } } { meal => + meal.foreach { case (key, option) => println(key ++ "," ++ option ++ " ") } + println("") + } +} \ No newline at end of file