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

FS-165 Module looks from Root #239

Closed
wants to merge 2 commits into from
Closed
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
31 changes: 31 additions & 0 deletions docs/src/main/scala/docs.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright 2017 47 Degrees, LLC. <http://www.47deg.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package freestyle.docs

import freestyle._

@free
trait Validation {
def minSize(s: String, n: Int): FS[Boolean]
def hasNumber(s: String): FS[Boolean]
}

@free
trait Interaction {
def tell(msg: String): FS[Unit]
def ask(prompt: String): FS[String]
}
29 changes: 29 additions & 0 deletions docs/src/main/scala/integrations.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright 2017 47 Degrees, LLC. <http://www.47deg.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package freestyle.docs.integrations

import freestyle._

@free
trait Calc {
def subtract(a: Int, b: Int): FS[Int]
}

@free
trait Interact {
def tell(msg: String): FS[Unit]
}
38 changes: 38 additions & 0 deletions docs/src/main/scala/interpreters.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright 2017 47 Degrees, LLC. <http://www.47deg.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package freestyle.docs.core.interpreters

import cats.syntax.applicative._
import freestyle._

@free
trait KVStore {
def put[A](key: String, value: A): FS[Unit]
def get[A](key: String): FS[Option[A]]
def delete(key: String): FS[Unit]
def update[A](key: String, f: A => A): FS.Seq[Unit] =
get[A](key).freeS flatMap {
case Some(a) => put[A](key, f(a)).freeS
case None => ().pure[FS.Seq]
}
}

@free
trait Log {
def info(msg: String): FS[Unit]
def warn(msg: String): FS[Unit]
}
47 changes: 47 additions & 0 deletions docs/src/main/scala/modules.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright 2017 47 Degrees, LLC. <http://www.47deg.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package freestyle.docs.core.modules

import freestyle._

@free
trait Cache {
def get(id: Int): FS[Option[Int]]
}
@free
trait Database {
def get(id: Int): FS[Int]
}
@free
trait IdValidation {
def validate(id: Option[Int]): FS[Int]
}
@free
trait Presenter {
def show(id: Int): FS[Int]
}

@module
trait Persistence[F[_]] {
val database: Database[F]
val cache: Cache[F]
}
@module
trait Display[F[_]] {
val presenter: Presenter[F]
val validator: IdValidation[F]
}
29 changes: 29 additions & 0 deletions docs/src/main/scala/patterns.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright 2017 47 Degrees, LLC. <http://www.47deg.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package freestyle.docs.patterns

import freestyle._

@free
trait CustomerService {
def customers: FS[List[String]]
}

@free
trait IssuesService {
def states: FS[List[String]]
}
46 changes: 46 additions & 0 deletions docs/src/main/scala/stack.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright 2017 47 Degrees, LLC. <http://www.47deg.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package freestyle.docs.stack

import freestyle._

object types {
type CustomerId = java.util.UUID
}

import types._

case class Customer(id: CustomerId, name: String)
case class Order(crates: Int, variety: String, customerId: CustomerId)
case class Config(varieties: Set[String])

@free
trait CustomerPersistence {
def getCustomer(id: CustomerId): FS[Option[Customer]]
}

@free
trait StockPersistence {
def checkQuantityAvailable(variety: String): FS[Int]
def registerOrder(order: Order): FS[Unit]
}

@module
trait Persistence[F[_]] {
val customer: CustomerPersistence[F]
val stock: StockPersistence[F]
}
11 changes: 8 additions & 3 deletions docs/src/main/tut/docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ In the example below we will define two algebras with intermixed sequential and

```tut:book
import freestyle._
import freestyle.implicits._

@free trait Validation {
def minSize(s: String, n: Int): FS[Boolean]
Expand All @@ -60,6 +59,10 @@ Learn more about [algebras](./core/algebras) in the extended documentation.
Freestyle algebras can be combined into `@module` definitions which provide aggregation and unification over the
parametrization of Free programs.

```tut:reset:silent
import freestyle._
import freestyle.docs._
```
```tut:book
@module trait Application[F[_]] {
val validation: Validation[F]
Expand All @@ -80,9 +83,11 @@ Abstract definitions it's all it takes to start building programs that support s
The example below combines both algebras to produce a more complex program

```tut:book
import cats.syntax.cartesian._
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cats documentation choose to always use import cats.implicits._ instead of the piecemeal imports as it is more beginner friendly, should we do the same?

Copy link
Contributor Author

@diesalbla diesalbla Apr 20, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMHO, it is more beginner-friendly to narrow down, as much as possible, what is it that the code snippet is using from this big cats library. Not everybody may know all of cats.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that was my initial point of view as well, but it is even more difficult to figure out where exactly which syntax is coming from before you know the relation between all the concepts Cats provides, see typelevel/cats#1026.

import freestyle.implicits._

def program[F[_]](implicit A: Application[F]) = {
import A._
import cats.implicits._

for {
userInput <- interaction.ask("Give me something with at least 3 chars and a number on it")
Expand Down Expand Up @@ -119,7 +124,7 @@ The mere fact that you provide implicit evidences for the individual steps enabl
At this point we can run our pure programs at the edge of the world.

```tut:book
import cats.implicits._
import cats.instances.future._
import scala.concurrent.duration.Duration
import scala.concurrent.Await

Expand Down
10 changes: 8 additions & 2 deletions docs/src/main/tut/docs/core/interpreters/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ import cats.implicits._
```

To define a runtime interpreter for this, we simply extend `KVStore.Handler[M[_]]` and implement its abstract members:
```tut:reset:invisible
import freestyle._
import freestyle.docs.core.interpreters._
```

```tut:book
import cats.data.State
Expand Down Expand Up @@ -81,9 +85,10 @@ implicit def manualKvStoreHandler: KVStore.Op ~> KVStoreState =

Freestyle performs automatic composition of interpreters by providing the implicit machinery necessary to derive a Module interpreter
by the evidence of it's algebras' interpreters.
To illustrate interpreter composition, let's define a new algebra `Log` which we will compose with our `KVStore` operations:
To illustrate interpreter composition, we define a new algebra `Log`, which we will compose with our `KVStore` operations.
The code for `Log` is available [here](../../../../scala/interpreters.scala).

```tut:book
```scala
@free trait Log {
def info(msg: String): FS[Unit]
def warn(msg: String): FS[Unit]
Expand All @@ -94,6 +99,7 @@ Once our algebra is defined we can easily write an interpreter for it:

```tut:book
import cats.implicits._
import freestyle.docs.core.interpreters

implicit def logHandler: Log.Handler[KVStoreState] =
new Log.Handler[KVStoreState] {
Expand Down
72 changes: 38 additions & 34 deletions docs/src/main/tut/docs/core/modules/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,54 +11,58 @@ In the same way that architectures are traditionally built in layers where separ
help organize algebras in groups that can be arbitrarily nested.

Let’s first define a few algebras to illustrate how Modules work. We will start with some basic low-level style ops related to persistence. In our Persistence related algebras, we have a few ops that can go against a DB and others to a Cache service or system. On the presentation side, an application can display or perform input validation.
The code for these algebras is available [here](../../../../scala/modules.scala).

```tut:book
```scala
import freestyle._

object algebras {
@free trait Database {
def get(id: Int): FS[Int]
}
@free trait Cache {
def get(id: Int): FS[Option[Int]]
}
@free trait Presenter {
def show(id: Int): FS[Int]
}
@free trait IdValidation {
def validate(id: Option[Int]): FS[Int]
}
@free trait Cache {
def get(id: Int): FS[Option[Int]]
}
@free trait Database {
def get(id: Int): FS[Int]
}
@free trait IdValidation {
def validate(id: Option[Int]): FS[Int]
}
@free trait Presenter {
def show(id: Int): FS[Int]
}
```

At this point, we can group these different application concerns in modules.
Modules can be further nested so they become part of the tree that conforms an application or library:
At this point, we can group these different application concerns in modules.
A module is a trait (or abstract class) bearing the `@module` macro annotation.
The trait declares several `val` variables that refer to the algebras used in the module.

```tut:reset:book
import freestyle._
import freestyle.docs.core.modules.{ Cache, Database, IdValidation, Presenter }

```tut:book
import algebras._

object modules {
@module trait Persistence[F[_]] {
val database: Database[F]
val cache: Cache[F]
}
@module trait Display[F[_]] {
val presenter: Presenter[F]
val validator: IdValidation[F]
}
@module trait App[F[_]] {
val persistence: Persistence[F]
val display: Display[F]
}
@module trait Persistence[F[_]] {
val cache: Cache[F]
val database: Database[F]
}
@module trait Display[F[_]] {
val presenter: Presenter[F]
val validator: IdValidation[F]
}
```
The code for these modules is available at [here](../../../../scala/modules.scala).
In addtition to algebras, modules can also refer to other modules.
Modules can be further nested so they become part of the tree that conforms an application or library:

```tut:reset:book
import freestyle._
import freestyle.docs.core.modules._
@module trait App[F[_]] {
val persistence: Persistence[F]
val display: Display[F]
}
```

This enables one to build programs that are properly typed and parameterized in a modular and composable way:

```tut:book
import modules._

def program[F[_]](
implicit
app: App[F]): FreeS[F, Int] = {
Expand Down
Loading