Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move ToView into FromIterable #536

Merged
merged 3 commits into from
Dec 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Dsl/src/main/scala/com/thoughtworks/dsl/Dsl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ object Dsl extends LowPriorityDsl0 {
/** The AST returned from a `for`...`yield` or a `for`...`do` expression.
*
* Note that a [[For]] does not directly support !-notation.
* Instead, [[keywords.ToView]] is used to convert a [[For]] to a
* Instead, [[keywords.FromIterable.ToView]] is used to convert a [[For]] to a
* [[Keyword]] that supports !-notation.
*/
sealed trait For
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ We also provide some built-in keywords, including:
* The `NullSafe` keyword for the null safe operator, similar to the `?` operator in Kotlin and Groovy.
* The `NoneSafe` keyword for the `None` safe operator, similar to the `Maybe` monad in Haskell.

All the above keywords can be used together with each others. For example you can perform list comprehension to manipulate native resources in an asynchronous task by using `ToView.FromIterable`, `Using` and `Shift` together.
All the above keywords can be used together with each others. For example you can perform list comprehension to manipulate native resources in an asynchronous task by using `FromIterable`, `Using` and `Shift` together.

## Getting Started

Expand Down
15 changes: 7 additions & 8 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,13 @@ lazy val `domains-Task` =
`keywords-Shift`,
reset,
`domains-Continuation`,
`keywords-ToView` % Test,
`keywords-FromIterable` % Test,
`keywords-Using` % Test,
`keywords-Yield` % Test,
`keywords-ToView` % Test
`keywords-FromIterable` % Test
)

lazy val `keywords-ToView` =
lazy val `keywords-FromIterable` =
crossProject(JSPlatform, JVMPlatform)
.crossType(CrossType.Pure)
.dependsOn(Dsl, reset, `keywords-Shift`)
Expand Down Expand Up @@ -116,9 +116,9 @@ lazy val `keywords-AsynchronousIo` =
.crossType(CrossType.Pure)
.dependsOn(
`keywords-Shift`,
`keywords-ToView` % Test,
`keywords-FromIterable` % Test,
`keywords-Using` % Test,
`keywords-ToView` % Test,
`keywords-FromIterable` % Test,
`domains-Task` % Test
)

Expand Down Expand Up @@ -150,11 +150,10 @@ lazy val `keywords-Await` =
`domains-Continuation`,
reset % Test,
`domains-Task` % Test,
`keywords-ToView` % Test,
`keywords-Get` % Test,
`keywords-Return` % Test,
`keywords-Yield` % Test,
`keywords-ToView` % Test
`keywords-FromIterable` % Test
)

lazy val `scala-async` =
Expand All @@ -168,7 +167,7 @@ lazy val `keywords-Yield` =
.dependsOn(
Dsl,
reset % Test,
`keywords-ToView` % Test,
`keywords-FromIterable` % Test,
`keywords-Shift` % Test,
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package domains

import scala.util._
import scala.util.control.NonFatal
import com.thoughtworks.dsl.keywords.Pure

type Continuation[R, +A] = (A => R) => R

Expand All @@ -21,7 +22,10 @@ object Continuation {
def delay[R, A](a: () => A): R !! A = _(a())

inline def apply[R, A](inline a: A): R !! A = { handler =>
reset(handler(a))
reset {
// !Pure ensures stack safety
handler(!Pure(a))
}
}

def toTryContinuation[LeftDomain, Value](
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,23 @@ import com.thoughtworks.dsl.Dsl.{!!}
import org.scalatest.Assertion
import scala.language.implicitConversions

import com.thoughtworks.dsl.keywords.{Using, ToView}
import com.thoughtworks.dsl.keywords.{Using, FromIterable}
import com.thoughtworks.dsl.domains._
import com.thoughtworks.dsl.keywords.Shift
import com.thoughtworks.dsl.keywords.Shift.given

import scala.collection.mutable.ArrayBuffer
import scala.util.control.TailCalls
import scala.util.{Failure, Success}
import org.scalatest.freespec.AsyncFreeSpec
import org.scalatest.matchers.should.Matchers

/** @author 杨博 (Yang Bo)
/** @author
* 杨博 (Yang Bo)
*/
final class taskSpec extends AsyncFreeSpec with Matchers {

"tailRecurision" in Task.toFuture(Task {
def loop(i: Int = 0, accumulator: Int = 0): Task[Int] = *[Task] {
def loop(i: Int = 0, accumulator: Int = 0): Task[Int] = Task {
if (i < 10000) {
!Shift(loop(i + 1, accumulator + i))
} else {
Expand All @@ -43,7 +43,7 @@ final class taskSpec extends AsyncFreeSpec with Matchers {
val task1: Task[Int] = Task.now(1)

val ts = *[Task]/* .join */ apply Seq {
!ToView.FromIterable(0 until 10) + !Shift(task1)
!FromIterable(0 until 10) + !Shift(task1)
}

!Shift(ts) should be(1 until 11)
Expand Down Expand Up @@ -114,8 +114,8 @@ final class taskSpec extends AsyncFreeSpec with Matchers {
"autoClose" in {
val logs = ArrayBuffer.empty[Int]

// TODO: Re-implement Using to support `Task {}` instead of `*[Task]`
val task: Task[Unit] = *[Task] {
// TODO: Re-implement Using to support `Task {}` instead of `Task`
val task: Task[Unit] = Task {

logs += 0

Expand All @@ -139,7 +139,7 @@ final class taskSpec extends AsyncFreeSpec with Matchers {
})

// TODO: Re-implement Using to support `Task{}`
!Shift(*[Task] {
!Shift(Task {
logs += 3

!Using(new AutoCloseable {
Expand Down Expand Up @@ -169,22 +169,25 @@ final class taskSpec extends AsyncFreeSpec with Matchers {
}

Task.toFuture(task).map { _ =>
logs should be(ArrayBuffer(0, 10, 11, 12, 3, 40, 41, 42, 6, 52, 51, 50, 7, 22, 21, 20))
logs should be(
ArrayBuffer(0, 10, 11, 12, 3, 40, 41, 42, 6, 52, 51, 50, 7, 22, 21, 20)
)
}

}

// Task.join is not supported any more
"nested seq of task" ignore {

def composeTask(t0: Task[Seq[Task[Seq[Task[Seq[Task[Seq[Float]]]]]]]]): Task[Seq[Seq[Seq[Seq[Float]]]]] = {
// TODO: remove explicit type parameters when https://github.com/scala/bug/issues/11068 is fixed
*[Task]/*.join*/ apply Seq {
val t1 = !ToView.FromIterable(!Shift(t0))
!Shift(*[Task]/*.join*/ apply Seq {
val t2 = !ToView.FromIterable(!Shift(t1))
!Shift(*[Task]/*.join*/ apply Seq {
val t3 = !ToView.FromIterable(!Shift(t2))
def composeTask(
t0: Task[Seq[Task[Seq[Task[Seq[Task[Seq[Float]]]]]]]]
): Task[Seq[Seq[Seq[Seq[Float]]]]] = {
Task /*.join*/ apply Seq {
val t1 = !FromIterable(!Shift(t0))
!Shift(Task /*.join*/ apply Seq {
val t2 = !FromIterable(!Shift(t1))
!Shift(Task /*.join*/ apply Seq {
val t3 = !FromIterable(!Shift(t2))
!Shift(t3)
})
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package com.thoughtworks.dsl
package domains

import com.thoughtworks.dsl.domains.Continuation, Continuation.!!
import com.thoughtworks.dsl.keywords.Pure
import com.thoughtworks.dsl.keywords.Suspend
import com.thoughtworks.dsl.keywords.Shift
import com.thoughtworks.dsl.reset, reset._

Expand All @@ -19,7 +21,7 @@ import scala.util.control.TailCalls.TailRec
*
* @template
* @example A [[Task]] can be created from `for`-comprehension,
* where [[keywords.ToView.FromIterable]] can be used together to asynchronously iterate collections.
* where [[keywords.FromIterable]] can be used together to asynchronously iterate collections.
*
* For example, the above `concatenateRemoteData` downloads and concatenates data from multiple URLs.
*
Expand All @@ -29,11 +31,11 @@ import scala.util.control.TailCalls.TailRec
* import com.thoughtworks.dsl.keywords._
* import com.thoughtworks.dsl.domains.Task
* import java.net.URL
* def concatenateRemoteData(urls: List[URL], downloader: URL => Task[Vector[Byte]]) = ToView {
* def concatenateRemoteData(urls: List[URL], downloader: URL => Task[Vector[Byte]]) = FromIterable.ToView {
* for {
* url <- ToView.FromIterable(urls)
* url <- FromIterable(urls)
* data <- Shift(downloader(url))
* byte <- ToView.FromIterable(data)
* byte <- FromIterable(data)
* } yield byte
* }.to[Task]
* }}}
Expand Down Expand Up @@ -78,7 +80,10 @@ object Task extends TaskPlatformSpecificFunctions {
def delay[A](f: () => A): Task[A] = _(f())

inline def apply[A](inline a: A): Task[A] = { handler =>
reset(handler(a))
reset {
// !Pure ensures stack safety
handler(!Pure(a))
}
}

/** Returns a task that does nothing but let the succeeding tasks run on `executionContext`
Expand All @@ -90,7 +95,7 @@ object Task extends TaskPlatformSpecificFunctions {
* import org.scalatest.Assertion
* import scala.concurrent.ExecutionContext
* import com.thoughtworks.dsl.keywords.Shift
* def myTask: Task[Assertion] = *[Task] {
* def myTask: Task[Assertion] = Task {
* val originalThread = Thread.currentThread
* !Shift(Task.switchExecutionContext(ExecutionContext.global))
* Thread.currentThread should not be originalThread
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import scala.util.control.NonFatal
* @example [[scalaz.Free.Trampoline]] is a monadic data type that performs tail call optimization.
* It can be built from a `@[[Dsl.reset reset]]` code block within some [[Dsl.Keyword#unary_$bang !-notation]],
* similar to the [[com.thoughtworks.each.Monadic.EachOps#each each]] method in
* [[https://github.com/ThoughtWorksInc/each ThoughtWorks ToView.FromIterable]].
* [[https://github.com/ThoughtWorksInc/each ThoughtWorks FromIterable]].
*
* {{{
* import _root_.scalaz.Trampoline
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ import scala.util.control.NonFatal
* and other keywords can be used together in the same `for` block.
*
* For example, the following `cat` function contains a single `for` block to concatenate file contents.
* It asynchronously iterates elements `Seq`, `ArrayBuffer` and `String` with the help of [[keywords.ToView.FromIterable]],
* It asynchronously iterates elements `Seq`, `ArrayBuffer` and `String` with the help of [[keywords.FromIterable]],
* managed native resources with the help of [[keywords.Using]],
* performs previously created `readAll` task with the help of [[keywords.Shift]],
* and finally converts the return type [[comprehension.ComprehensionOps.as as]] a `Task[Vector[Char]]`.
Expand All @@ -51,13 +51,13 @@ import scala.util.control.NonFatal
* import com.thoughtworks.dsl.domains.Task
* import com.thoughtworks.dsl.Dsl.to
* import java.net.URL
* def cat(paths: Path*) = ToView {
* def cat(paths: Path*) = FromIterable.ToView {
* for {
* path <- ToView.FromIterable(paths)
* path <- FromIterable(paths)
* channel <- Using(AsynchronousFileChannel.open(path))
* charBuffers <- Shift(readAll(channel))
* charBuffer <- ToView.FromIterable(charBuffers)
* char <- ToView.FromIterable(charBuffer.toString)
* charBuffer <- FromIterable(charBuffers)
* char <- FromIterable(charBuffer.toString)
* } yield char
* }.to[Task]
* }}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import scala.language.implicitConversions
* {{{
* import com.thoughtworks.dsl.domains.Task
* import com.thoughtworks.dsl.keywords.Await
* val myTask = *[Task] {
* val myTask = Task {
* !Await(myFuture42)
* }
* }}}
Expand All @@ -45,7 +45,7 @@ import scala.language.implicitConversions
* [[domains.task.Task.toFuture]].
*
* {{{
* val myAssertionTask = *[Task] {
* val myAssertionTask = Task {
* !Shift(myTask) should be(42)
* }
* Task.toFuture(myAssertionTask)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class AwaitTest extends AsyncFreeSpec with Matchers with Inside {
type Id[A] = A
"testComprehension1" in {
def inner1 = for {
j <- ToView.FromIterable(0 until 3)
j <- FromIterable(0 until 3)
} yield 100 + j

val ast1 = Await(Future(1)).flatMap { i =>
Expand All @@ -44,7 +44,7 @@ class AwaitTest extends AsyncFreeSpec with Matchers with Inside {
Await[Int],
Int,
Dsl.For.Yield.Map[
ToView.FromIterable[Int],
FromIterable[Int],
Int,
Int
],
Expand All @@ -54,20 +54,20 @@ class AwaitTest extends AsyncFreeSpec with Matchers with Inside {

*[Future] {
(!Await(
ToView(ast1).to[Future]
FromIterable.ToView(ast1).to[Future]
)).toVector should be(Vector(100, 101, 102))
}
}

"testComprehension2" in {
import Dsl._
val inner2 = for {
j <- ToView.FromIterable(0 until 10)
j <- FromIterable(0 until 10)
} yield 111
summon[
inner2.type
<:<
Dsl.For.Yield.Map[ToView.FromIterable[Int], Int, Int]
Dsl.For.Yield.Map[FromIterable[Int], Int, Int]
]
val ast2 = Await(Future(1)).flatMap { i =>
inner2
Expand All @@ -79,7 +79,7 @@ class AwaitTest extends AsyncFreeSpec with Matchers with Inside {
Await[Int],
Int,
Dsl.For.Yield.Map[
ToView.FromIterable[Int],
FromIterable[Int],
Int,
Int
],
Expand All @@ -91,9 +91,9 @@ class AwaitTest extends AsyncFreeSpec with Matchers with Inside {

"testComprehension3" in {
import Dsl._
val ast3 = ToView.toKeyword(for {
val ast3 = FromIterable.ToView.toKeyword(for {
i <- Await(Future(1))
j <- ToView.FromIterable(0 until 10)
j <- FromIterable(0 until 10)
} yield 111)
summon[
ast3.type
Expand All @@ -102,7 +102,7 @@ class AwaitTest extends AsyncFreeSpec with Matchers with Inside {
Await[Int],
Int,
FlatMap[
ToView.FromIterable[Int],
FromIterable[Int],
Int,
Pure[collection.View[Int]]
]
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loading