Skip to content

Commit

Permalink
Merge pull request #8 from julianpeeters/dev
Browse files Browse the repository at this point in the history
Reduce scope, refactor
  • Loading branch information
julianpeeters committed Dec 18, 2023
2 parents 900e100 + 1e087af commit 63005a3
Show file tree
Hide file tree
Showing 7 changed files with 156 additions and 218 deletions.
122 changes: 55 additions & 67 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,107 +1,95 @@
# destructured

Common typeclasses and constructors, but parameterized by `A` instead of `F[_]`

#### Why?

This library can be useful if your model uses subtypes in its definition.

For example, if the compiler knows that a type `A`, is, at a call site, a
`Some[T]` or a `None.type`, then `destructured` typeclasses can be used to
summon `cats` `Applicative` typeclass for the underlying `Option`:
Typeclasses that provide data constructors of `F[_]`, but parameterized by `A`
instead of `F[_]`.
- libarary for Scala 3 (JS, JVM, and Native platforms)

### Add the dependency:

```scala
import destructured.cats.{ApplicativeOf, given}

def f[A](a: A)(using A: ApplicativeOf[A]): ApplicativeOf[A] = A
val a: Some[Int] = Some(1)
// a: Some[Int] = Some(value = 1)
val b: Option[String] = f(a).pure("foo")
// b: Option[String] = Some(value = "foo")
"com.julianpeeters" %% "destructured" % "0.2.0"
```

<small>(Note: For a more realistic example, see the [dynamical](https://github.com/julianpeeters/dynamical) library)</small>
### Why?

### Libraries for Scala 3 (JS, JVM, and Native platforms)
- [`destructured-cats`](#destructured-cats): typeclasses of the underlying functor, e.g., `Applicative[Option]`
- [`destructured-scala`](#destructured-scala): typeclass-based constructors of underlying data type, e.g., `Some[T]`
This library may be useful if your model uses subtypes in its definition.

### How?

## `destructured-cats`
The `CtorOf` typeclass is like `ValueOf`, but for constructors:
- Scala's `ValueOf` provides values like `None` for singleton types,
- here, `CtorOf` provides constructors like `Some(_)` for parameterized types

```scala
"com.julianpeeters" %% "destructured-cats" % "0.1.1"
```

Supported types: `Applicative[Option]`, `Functor[Option]`

##### Examples:

##### `ApplicativeOf`
### Example:

For example, if the compiler knows that a type `A`, is, at a call site, a
`Some[T]` or a `None.type`, then `destructured` typeclasses can be used to
summon a constructor for the underlying `Some[T]` or `None.type`:

```scala
import destructured.cats.{ApplicativeOf, given}
import destructured.{CtorOf, given}

def f[A](a: A)(using A: ApplicativeOf[A]): ApplicativeOf[A] = A
val a: Some[Int] = Some(1)
// a: Some[Int] = Some(value = 1)
val b: Option[String] = f(a).pure("foo")
// b: Option[String] = Some(value = "foo")
```


##### `FunctorOf`

```scala
import destructured.cats.{FunctorOf, given}

val fa: Option[Int] = Option(1)
// fa: Option[Int] = Some(value = 1)
def f[A](a: A)(using A: FunctorOf[A]): FunctorOf[A] = A
val fb: Option[Int] = f(fa).map(fa)(_ + 1)
// fb: Option[Int] = Some(value = 2)
```


## `destructured-scala`

```scala
"com.julianpeeters" %% "destructured-scala" % "0.1.1"
def f[A](a: A)(using C: CtorOf[Int, A]): CtorOf[Int, A] = C
val b: Some[Int] = f(a).apply(2)
// b: Some[Int] = Some(value = 2)
```

`CtorOf` can be compared to scala's built-in `ValueOf`, a
typeclass that provides values for singleton types like `None.type`.
<small>(Note: For a more realistic example, see the [dynamical](https://github.com/julianpeeters/dynamical) library)</small>

##### Supported Types:
### SupportedTypes:

| Option | Either |
| :---: | :---: |
| Some | Left |
| None | Right |

##### Examples:

##### `Some[T]`

```scala
import destructured.scala.{CtorOf, given}
import destructured.{CtorOf, given}

val a: Some[Int] = Some(1)
// a: Some[Int] = Some(value = 1)
def f[A](a: A)(using A: CtorOf[A]): CtorOf[A] = A
val b: Some[String] = f(a).apply("foo")
// b: Some[String] = Some(value = "foo")
def f[A](a: A)(using C: CtorOf[Int, A]): CtorOf[Int, A] = C
val b: Some[Int] = f(a).apply(2)
// b: Some[Int] = Some(value = 2)
```

##### `Either[L, R]`
##### `None.type`

```scala
import destructured.scala.{CtorOf, given}
import destructured.{CtorOf, given}

val a: None.type = None
// a: None = None
def f[A](a: A)(using C: CtorOf[Int, A]): CtorOf[Int, A] = C
val b: None.type = f(a).apply(2)
// b: None = None
```

##### `Right[L, R]`

```scala
import destructured.{CtorOf, given}

val a: Right[Boolean, Int] = Right(1)
// a: Right[Boolean, Int] = Right(value = 1)
def f[A](a: A)(using A: CtorOf[A]): CtorOf[A] = A
val b: Right[Boolean, String] = f(a).apply("foo")
// b: Right[Boolean, String] = Right(value = "foo")
def f[A](a: A)(using C: CtorOf[Int, A]): CtorOf[Int, A] = C
val b: Right[Boolean, Int] = f(a).apply(2)
// b: Right[Boolean, Int] = Right(value = 2)
```

##### `Left[L, R]`

```scala
import destructured.{CtorOf, given}

val a: Left[Boolean, Int] = Left(false)
// a: Left[Boolean, Int] = Left(value = false)
def f[A](a: A)(using C: CtorOf[Boolean, A]): CtorOf[Boolean, A] = C
val b: Left[Boolean, Int] = f(a).apply(true)
// b: Left[Boolean, Int] = Left(value = true)
```
24 changes: 2 additions & 22 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -27,28 +27,8 @@ inThisBuild(List(

lazy val root = crossProject(JSPlatform, JVMPlatform, NativePlatform)
.in(file("."))
.aggregate(cats, scala)
.enablePlugins(NoPublishPlugin)
.jsSettings(test := {})
.nativeSettings(test := {})

lazy val cats = crossProject(JSPlatform, JVMPlatform, NativePlatform)
.in(file("modules/cats"))
.settings(
name := "destructured-cats",
libraryDependencies ++= Seq(
"org.typelevel" %%% "cats-core" % "2.10.0",
"org.scalameta" %% "munit" % "0.7.29" % Test
)
)
.jsSettings(test := {})
.nativeSettings(test := {})


lazy val scala = crossProject(JSPlatform, JVMPlatform, NativePlatform)
.in(file("modules/scala"))
.settings(
name := "destructured-scala",
name := "destructured",
libraryDependencies ++= Seq(
"org.scalameta" %% "munit" % "0.7.29" % Test
)
Expand All @@ -64,6 +44,6 @@ lazy val docs = project.in(file("docs/gitignored"))
"VERSION" -> version.value.takeWhile(_ != '+'),
)
)
.dependsOn(cats.jvm, scala.jvm)
.dependsOn(root.jvm)
.enablePlugins(MdocPlugin)
.enablePlugins(NoPublishPlugin)
106 changes: 47 additions & 59 deletions docs/readme.md
Original file line number Diff line number Diff line change
@@ -1,97 +1,85 @@
# destructured

Common typeclasses and constructors, but parameterized by `A` instead of `F[_]`
Typeclasses that provide data constructors of `F[_]`, but parameterized by `A`
instead of `F[_]`.
- libarary for Scala @SCALA@ (JS, JVM, and Native platforms)

### Add the dependency:

#### Why?
```scala
"com.julianpeeters" %% "destructured" % "@VERSION@"
```

### Why?

This library may be useful if your model uses subtypes in its definition.

### How?

This library can be useful if your model uses subtypes in its definition.
The `CtorOf` typeclass is like `ValueOf`, but for constructors:
- Scala's `ValueOf` provides values like `None` for singleton types,
- here, `CtorOf` provides constructors like `Some(_)` for parameterized types

### Example:

For example, if the compiler knows that a type `A`, is, at a call site, a
`Some[T]` or a `None.type`, then `destructured` typeclasses can be used to
summon `cats` `Applicative` typeclass for the underlying `Option`:
summon a constructor for the underlying `Some[T]` or `None.type`:

```scala mdoc:reset
import destructured.cats.{ApplicativeOf, given}
import destructured.{CtorOf, given}

def f[A](a: A)(using A: ApplicativeOf[A]): ApplicativeOf[A] = A
val a: Some[Int] = Some(1)
val b: Option[String] = f(a).pure("foo")
def f[A](a: A)(using C: CtorOf[Int, A]): CtorOf[Int, A] = C
val b: Some[Int] = f(a).apply(2)
```

<small>(Note: For a more realistic example, see the [dynamical](https://github.com/julianpeeters/dynamical) library)</small>

### Libraries for Scala @SCALA@ (JS, JVM, and Native platforms)
- [`destructured-cats`](#destructured-cats): typeclasses of the underlying functor, e.g., `Applicative[Option]`
- [`destructured-scala`](#destructured-scala): typeclass-based constructors of underlying data type, e.g., `Some[T]`


## `destructured-cats`

```scala
"com.julianpeeters" %% "destructured-cats" % "@VERSION@"
```

Supported types: `Applicative[Option]`, `Functor[Option]`
### SupportedTypes:

##### Examples:
| Option | Either |
| :---: | :---: |
| Some | Left |
| None | Right |

##### `ApplicativeOf`

##### `Some[T]`

```scala mdoc:reset
import destructured.cats.{ApplicativeOf, given}
import destructured.{CtorOf, given}

def f[A](a: A)(using A: ApplicativeOf[A]): ApplicativeOf[A] = A
val a: Some[Int] = Some(1)
val b: Option[String] = f(a).pure("foo")
def f[A](a: A)(using C: CtorOf[Int, A]): CtorOf[Int, A] = C
val b: Some[Int] = f(a).apply(2)
```


##### `FunctorOf`
##### `None.type`

```scala mdoc:reset
import destructured.cats.{FunctorOf, given}
import destructured.{CtorOf, given}

val fa: Option[Int] = Option(1)
def f[A](a: A)(using A: FunctorOf[A]): FunctorOf[A] = A
val fb: Option[Int] = f(fa).map(fa)(_ + 1)
val a: None.type = None
def f[A](a: A)(using C: CtorOf[Int, A]): CtorOf[Int, A] = C
val b: None.type = f(a).apply(2)
```


## `destructured-scala`

```scala
"com.julianpeeters" %% "destructured-scala" % "@VERSION@"
```

`CtorOf` can be compared to scala's built-in `ValueOf`, a
typeclass that provides values for singleton types like `None.type`.

##### Supported Types:

| Option | Either |
| :---: | :---: |
| Some | Left |
| None | Right |

##### Examples:

##### `Some[T]`
##### `Right[L, R]`

```scala mdoc:reset
import destructured.scala.{CtorOf, given}
import destructured.{CtorOf, given}

val a: Some[Int] = Some(1)
def f[A](a: A)(using A: CtorOf[A]): CtorOf[A] = A
val b: Some[String] = f(a).apply("foo")
val a: Right[Boolean, Int] = Right(1)
def f[A](a: A)(using C: CtorOf[Int, A]): CtorOf[Int, A] = C
val b: Right[Boolean, Int] = f(a).apply(2)
```

##### `Either[L, R]`
##### `Left[L, R]`

```scala mdoc:reset
import destructured.scala.{CtorOf, given}
import destructured.{CtorOf, given}

val a: Right[Boolean, Int] = Right(1)
def f[A](a: A)(using A: CtorOf[A]): CtorOf[A] = A
val b: Right[Boolean, String] = f(a).apply("foo")
val a: Left[Boolean, Int] = Left(false)
def f[A](a: A)(using C: CtorOf[Boolean, A]): CtorOf[Boolean, A] = C
val b: Left[Boolean, Int] = f(a).apply(true)
```
26 changes: 26 additions & 0 deletions jvm/src/test/scala/destructured/CtorSuite.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package destructured

import munit.FunSuite

class CtorSuite extends FunSuite:

test("Some[A]"):
val a: Some[Int] = Some(1)
def f[A](a: A)(using C: CtorOf[Int, A]): CtorOf[Int, A] = C
val obtained: Some[Int] = f(a).apply(2)
val expected: Some[Int] = Some(2)
assertEquals(obtained, expected)

test("Right[A, B]"):
val a: Right[Boolean, Int] = Right(1)
def f[A](a: A)(using C: CtorOf[Int, A]): CtorOf[Int, A] = C
val obtained: Right[Boolean, Int] = f(a).apply(2)
val expected: Right[Boolean, Int] = Right(2)
assertEquals(obtained, expected)

test("Left[A, B]"):
val a: Left[Boolean, Int] = Left(true)
def f[A](a: A)(using C: CtorOf[Boolean, A]): CtorOf[Boolean, A] = C
val obtained: Left[Boolean, Int] = f(a).apply(false)
val expected: Left[Boolean, Int] = Left(false)
assertEquals(obtained, expected)

0 comments on commit 63005a3

Please sign in to comment.