couldbe: optional Givens for Scala
Overview
couldbe is a small library, for the Scala programming language, allowing you to refer to optional given
instances (known as implicits in Scala 2).
Because given
instances are resolved at compile time, they are either available or they are not. If your code requires a given
instance, you add it to the function signature; if it doesn't, then you don't.
But what if your code could use a given
instance, but doesn't require one? Maybe you are writing an algorithm which could be simplified with evidence of a Monad, but doesn't actually require it? Or maybe you can provide a sensible default if the given
value is not defined?
That's where couldbe can help you out.
Quick example
(more examples later in the document)
- Scala 3
- Scala 2.13
// Function to return a Given string, if it is defined; or a default value otherwise.
def simpleGivenParameter(using message: CouldBeGiven[String]) =
message match
case IsGiven(actual) => actual
case IsNotGiven => "This is a default string"
// ---
// With no given String, the function returns the default value.
simpleGivenParameter == "This is a default string"
// ---
// With a given String, that is the value returned.
given String = "This string is given"
simpleGivenParameter == "This string is given"
// Function to return an implicit string, if it is defined; or a default value otherwise.
def simpleGivenParameter(implicit message: CouldBeGiven[String]) {
message match {
case IsGiven(actual) => actual
case IsNotGiven => "This is a default string"
}
}
// ---
// With no implicit String, the function returns the default value.
simpleGivenParameter == "This is a default string"
// ---
// With an implicit String, that is the value returned.
implicit val expectThis: String = "This string is given"
simpleGivenParameter == "This string is given"
Please note: it's not usually good practice to pass around something as generic as a String
type in a given
instance. This is a simple example to demonstrate the functionality.
Getting started
To include couldbe in your project, add the appropriate dependencies to your build.sbt
:
libraryDependencies += "eu.throup" %% "couldbe" % "<version>"
The available packages are:
Package | Contains |
---|---|
couldbe | umbrella meta package to pull in core and cats |
couldbe-core | minimal implementation to allow basic functionality |
couldbe-cats | extra definitions and functionality for those using the Cats library |
couldbe-testsupport | extra definitions and functionality to support writing tests |
Other examples
- Scala 3
- Scala 2.13
def yourFunction[A: CouldBeGiven, B: CouldHave[PartialOrder], F[_]: CouldBe[Monad]] =
// Maybe there was a Given A... maybe there wasn't
CouldBeGiven[A].act {
// If there is one, do something with it.
(a: A) => doSomethingWith(a)
} {
// Otherwise perform some fallback behaviour.
doSomethingElseWithout()
}
// Maybe F is a Monad... maybe it isn't
CouldBe[Monad, F].act {
// If it is, do something monadic
(monad: Monad[F]) => doSomethingMonadic(monad)
} {
// Otherwise perform some fallback behaviour.
doSomethingUnmonadic()
}
def yourFunction[A: CouldBeGiven, B, F[_]](
implicit B: CouldHave[PartialOrder, B],
F: CouldBe[Monad, F]) = {
// Maybe there was a Given A... maybe there wasn't
CouldBeGiven[A].act {
// If there is one, do something with it.
(a: A) => doSomethingWith(a)
} {
// Otherwise perform some fallback behaviour.
doSomethingElseWithout()
}
// Maybe F is a Monad... maybe it isn't
CouldBe[Monad, F].act {
// If it is, do something monadic
(monad: Monad[F]) => doSomethingMonadic(monad)
} {
// Otherwise perform some fallback behaviour.
doSomethingUnmonadic()
}
}