Compare commits
No commits in common. "main" and "presentation-02" have entirely different histories.
main
...
presentati
.scalafmt.conf
src
main/scala
conversions
data
extensions
applicative
applicativeError
flatMap
functor
identity
lisplist
map
monad
monadError
monoid
pure
schrodinger
semigroup
state
superposition
instances
identity
lisplist
schrodinger
state
superposition
ops
identity
lisplist
schrodinger
state
superposition
typeclasses
test/scala
2
.scalafmt.conf
Normal file
2
.scalafmt.conf
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
version = 2.5.0
|
||||||
|
maxColumn = 120
|
6
src/main/scala/conversions/identity/package.scala
Normal file
6
src/main/scala/conversions/identity/package.scala
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package conversions
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implicit conversions for Identity.
|
||||||
|
*/
|
||||||
|
package object identity {}
|
21
src/main/scala/conversions/lisplist/package.scala
Normal file
21
src/main/scala/conversions/lisplist/package.scala
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package conversions
|
||||||
|
|
||||||
|
import data.{Cons, LispList, Nil}
|
||||||
|
|
||||||
|
import scala.annotation.tailrec
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implicit conversions for LispList.
|
||||||
|
*/
|
||||||
|
package object lisplist {
|
||||||
|
|
||||||
|
implicit def lispListToList[A](lispList: LispList[A]): List[A] = {
|
||||||
|
@tailrec
|
||||||
|
def go(acc: List[A], l: LispList[A]): List[A] =
|
||||||
|
l match {
|
||||||
|
case Cons(car, cdr) => go(car +: acc, cdr)
|
||||||
|
case Nil => acc
|
||||||
|
}
|
||||||
|
go(List(), lispList).reverse
|
||||||
|
}
|
||||||
|
}
|
@ -1,19 +0,0 @@
|
|||||||
import data._
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implicit conversions
|
|
||||||
*/
|
|
||||||
package object conversions {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wholesale conversion of a LispList to a Scala Seq
|
|
||||||
*/
|
|
||||||
implicit def convertToSeq[A](list: LispList[A]): Seq[A] = ???
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wholesale conversion of a LispList to a Scala List
|
|
||||||
*/
|
|
||||||
implicit def convertToList[A](list: LispList[A]): List[A] = ???
|
|
||||||
|
|
||||||
// TODO what other conversions?
|
|
||||||
}
|
|
6
src/main/scala/conversions/schrodinger/package.scala
Normal file
6
src/main/scala/conversions/schrodinger/package.scala
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package conversions
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implicit conversions for Schrodinger.
|
||||||
|
*/
|
||||||
|
package object schrodinger {}
|
6
src/main/scala/conversions/state/package.scala
Normal file
6
src/main/scala/conversions/state/package.scala
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package conversions
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implicit conversions for State.
|
||||||
|
*/
|
||||||
|
package object state {}
|
6
src/main/scala/conversions/superposition/package.scala
Normal file
6
src/main/scala/conversions/superposition/package.scala
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package conversions
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implicit conversions for Superposition.
|
||||||
|
*/
|
||||||
|
package object superposition {}
|
@ -1,11 +1,14 @@
|
|||||||
|
/**
|
||||||
|
* DO NOT MODIFY THIS FILE. All exercises are performed using implicits only.
|
||||||
|
*/
|
||||||
package data
|
package data
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Lisply-named representation of a singly-linked list and an analogue to
|
* A Lisply-named representation of a singly-linked list and an analogue to
|
||||||
* Scala's immutable List. This is a special case of any type A where there
|
* Scala's immutable List. This is a special case of any type A where there
|
||||||
* exists a nondeterministic selection of its values that must be specially
|
* exists a nondeterministic selection of its values that must be specially
|
||||||
* handled such that the number of values is inconsequential.
|
* handled such that the number of values is inconsequential.
|
||||||
*/
|
*/
|
||||||
sealed trait LispList[+A] {
|
sealed trait LispList[+A] {
|
||||||
|
|
||||||
def car: A
|
def car: A
|
||||||
@ -13,9 +16,9 @@ sealed trait LispList[+A] {
|
|||||||
def cdr: LispList[A]
|
def cdr: LispList[A]
|
||||||
}
|
}
|
||||||
|
|
||||||
case class LispCons[+A](car: A, cdr: LispList[A]) extends LispList[A]
|
case class Cons[+A](car: A, cdr: LispList[A]) extends LispList[A]
|
||||||
|
|
||||||
case object LispNil extends LispList[Nothing] {
|
case object Nil extends LispList[Nothing] {
|
||||||
|
|
||||||
def car: Nothing = throw new Exception("LispList with no car!")
|
def car: Nothing = throw new Exception("LispList with no car!")
|
||||||
|
|
||||||
@ -24,10 +27,7 @@ case object LispNil extends LispList[Nothing] {
|
|||||||
|
|
||||||
object LispList {
|
object LispList {
|
||||||
|
|
||||||
def apply[A](): LispList[A] = LispNil
|
def apply[A](items: A*): LispList[A] = items.foldRight(LispList[A]())(Cons[A])
|
||||||
|
|
||||||
def apply[A](items: A*): LispList[A] = items.foldRight(LispList[A]())(LispCons[A])
|
def apply[A](): LispList[A] = Nil
|
||||||
|
|
||||||
// TODO how to make a Seq
|
|
||||||
// def unapplySeq[A](list: LispList[A]): Option[Seq[A]] = Some(list.toSeq)
|
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,26 @@
|
|||||||
|
/**
|
||||||
|
* DO NOT MODIFY THIS FILE. All exercises are performed using implicits only.
|
||||||
|
*/
|
||||||
package data
|
package data
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Schrodinger is an analogue to Scala's Option and a special case of
|
* Schrodinger is an analogue to Scala's Option and a special case of
|
||||||
* Superposition where a cat may or may not exist and the cat must be specially
|
* Superposition where a cat may or may not exist and the cat must be specially
|
||||||
* handled as if it were simultaneously alive or dead.
|
* handled as if it were simultaneously alive or dead.
|
||||||
*/
|
*/
|
||||||
sealed trait Schrodinger[+A] {
|
sealed trait Schrodinger[+A] {
|
||||||
|
|
||||||
def cat: A
|
def cat: A
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The cat is here for pets and he is fluffy.
|
||||||
|
*/
|
||||||
case class Alive[+A](cat: A) extends Schrodinger[A]
|
case class Alive[+A](cat: A) extends Schrodinger[A]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* :(
|
||||||
|
*/
|
||||||
case object Dead extends Schrodinger[Nothing] {
|
case object Dead extends Schrodinger[Nothing] {
|
||||||
|
|
||||||
def cat: Nothing = throw new Exception("He's dead Jim!")
|
def cat: Nothing = throw new Exception("He's dead Jim!")
|
||||||
|
@ -1,27 +1,33 @@
|
|||||||
|
/**
|
||||||
|
* DO NOT MODIFY THIS FILE. All exercises are performed using implicits only.
|
||||||
|
*/
|
||||||
package data
|
package data
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Superposition is an analogue to Scala's Either and \a special case of a
|
* Superposition is an analogue to Scala's Either and a special case of a
|
||||||
* product (any type of A × B) where only A or B exists, but must be treated
|
* Product (any type of A × B) where only A or B exists, but must be treated
|
||||||
* specially as though it could be either one.
|
* specially as though it could be either one but not both.
|
||||||
*/
|
*/
|
||||||
sealed trait Superposition[+A, +B]
|
sealed trait Superposition[+A, +B] {
|
||||||
|
|
||||||
|
def downside: A
|
||||||
|
|
||||||
|
def upside: B
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implied negative case of the Superposition. This is probably not the one you
|
* Implied negative case of the Superposition. This is probably not the one you
|
||||||
* want.
|
* want.
|
||||||
*
|
*/
|
||||||
* @param value The thing you probably don't want.
|
case class Downside[+A, +B](downside: A) extends Superposition[A, B] {
|
||||||
* @tparam A Downside type
|
|
||||||
* @tparam B Upside type
|
def upside = throw new Exception("I got the downside!")
|
||||||
*/
|
}
|
||||||
case class Downside[+A, +B](value: A) extends Superposition[A, B]
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implied positive case of the Superposition. This is usually the one you want.
|
* Implied positive case of the Superposition. This is usually the one you want.
|
||||||
*
|
*/
|
||||||
* @param value The thing you usually want.
|
case class Upside[+A, +B](upside: B) extends Superposition[A, B] {
|
||||||
* @tparam A Downside type
|
|
||||||
* @tparam B Upside type
|
def downside = throw new Exception("I got the upside!")
|
||||||
*/
|
}
|
||||||
case class Upside[+A, +B](value: B) extends Superposition[A, B]
|
|
||||||
|
@ -1,17 +1,21 @@
|
|||||||
|
/**
|
||||||
|
* DO NOT MODIFY THIS FILE. All exercises are performed using implicits only.
|
||||||
|
*/
|
||||||
package object data {
|
package object data {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A modeled stateful computation that for any state of type S there exists
|
* A structure for any type S for which a function exists that derives from
|
||||||
* a computation that derives from S a product of type A and a successive
|
* S a product of a value of itself and a value of type A. This can model
|
||||||
* instance of S representing the state of the next computation.
|
* stateful computation where state S is given to a function which produces
|
||||||
*
|
* a potentially-changed state and the result of the computation.
|
||||||
* @tparam S The state type
|
*
|
||||||
* @tparam A The value returned by the operation
|
* @tparam S The state type
|
||||||
*/
|
* @tparam A The type returned by the operation
|
||||||
|
*/
|
||||||
type State[S, +A] = S => (S, A)
|
type State[S, +A] = S => (S, A)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A special case of any type A that is just itself.
|
* A special case of any type A that is simply itself.
|
||||||
*/
|
*/
|
||||||
type Identity[+A] = A
|
type Identity[+A] = A
|
||||||
}
|
}
|
||||||
|
6
src/main/scala/extensions/applicative/package.scala
Normal file
6
src/main/scala/extensions/applicative/package.scala
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package extensions
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extension methods for Applicative operations.
|
||||||
|
*/
|
||||||
|
package object applicative {}
|
6
src/main/scala/extensions/applicativeError/package.scala
Normal file
6
src/main/scala/extensions/applicativeError/package.scala
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package extensions
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extension methods for ApplicativeError operations.
|
||||||
|
*/
|
||||||
|
package object applicativeError {}
|
@ -1,8 +0,0 @@
|
|||||||
package extensions
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implicit method extensions for flatMap().
|
|
||||||
*/
|
|
||||||
package object flatMap {
|
|
||||||
|
|
||||||
}
|
|
6
src/main/scala/extensions/functor/package.scala
Normal file
6
src/main/scala/extensions/functor/package.scala
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package extensions
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extension methods for Functor operations.
|
||||||
|
*/
|
||||||
|
package object functor {}
|
6
src/main/scala/extensions/identity/package.scala
Normal file
6
src/main/scala/extensions/identity/package.scala
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package extensions
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extension methods for Identity.
|
||||||
|
*/
|
||||||
|
package object identity {}
|
20
src/main/scala/extensions/lisplist/package.scala
Normal file
20
src/main/scala/extensions/lisplist/package.scala
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package extensions
|
||||||
|
|
||||||
|
import data.{Cons, LispList, Nil}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extension methods for LispList.
|
||||||
|
*/
|
||||||
|
package object lisplist {
|
||||||
|
|
||||||
|
implicit class LispListOps[A](val lispList: LispList[A]) extends AnyVal {
|
||||||
|
import conversions.lisplist._
|
||||||
|
def asList: List[A] = lispListToList(lispList)
|
||||||
|
|
||||||
|
def length: Int =
|
||||||
|
lispList match {
|
||||||
|
case Cons(_, cdr) => 1 + LispListOps(cdr).length
|
||||||
|
case Nil => 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,29 +0,0 @@
|
|||||||
package extensions
|
|
||||||
|
|
||||||
import data._
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implicit method extensions for map().
|
|
||||||
*/
|
|
||||||
package object map {
|
|
||||||
|
|
||||||
implicit class LispListOps[+A](val list: LispList[A]) extends AnyVal {
|
|
||||||
|
|
||||||
def map[B](f: A => B): LispList[B] = ???
|
|
||||||
}
|
|
||||||
|
|
||||||
implicit class SuperpositionOps[+A, +B](val fallible: Superposition[A, B]) extends AnyVal {
|
|
||||||
|
|
||||||
def map[C](f: B => C): Superposition[A, C] = ???
|
|
||||||
}
|
|
||||||
|
|
||||||
implicit class SchrodingerOps[+A](val possibly: Schrodinger[A]) extends AnyVal {
|
|
||||||
|
|
||||||
def map[B](f: A => B): Schrodinger[B] = ???
|
|
||||||
}
|
|
||||||
|
|
||||||
implicit class StateOps[S, +A](val state: State[S, A]) extends AnyVal {
|
|
||||||
|
|
||||||
def map[B](f: A => B): State[S, B] = ???
|
|
||||||
}
|
|
||||||
}
|
|
6
src/main/scala/extensions/monad/package.scala
Normal file
6
src/main/scala/extensions/monad/package.scala
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package extensions
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extension methods for Monad operations.
|
||||||
|
*/
|
||||||
|
package object monad {}
|
6
src/main/scala/extensions/monadError/package.scala
Normal file
6
src/main/scala/extensions/monadError/package.scala
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package extensions
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extension methods for MonadError operations.
|
||||||
|
*/
|
||||||
|
package object monadError {}
|
6
src/main/scala/extensions/monoid/package.scala
Normal file
6
src/main/scala/extensions/monoid/package.scala
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package extensions
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extension methods for Monoid operations.
|
||||||
|
*/
|
||||||
|
package object monoid {}
|
@ -1,8 +0,0 @@
|
|||||||
package extensions
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implicit method extensions for pure().
|
|
||||||
*/
|
|
||||||
package object pure {
|
|
||||||
|
|
||||||
}
|
|
6
src/main/scala/extensions/schrodinger/package.scala
Normal file
6
src/main/scala/extensions/schrodinger/package.scala
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package extensions
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extension methods for Schrodinger.
|
||||||
|
*/
|
||||||
|
package object schrodinger {}
|
6
src/main/scala/extensions/semigroup/package.scala
Normal file
6
src/main/scala/extensions/semigroup/package.scala
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package extensions
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extension methods for Semigroup operations.
|
||||||
|
*/
|
||||||
|
package object semigroup {}
|
6
src/main/scala/extensions/state/package.scala
Normal file
6
src/main/scala/extensions/state/package.scala
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package extensions
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extension methods for State.
|
||||||
|
*/
|
||||||
|
package object state {}
|
6
src/main/scala/extensions/superposition/package.scala
Normal file
6
src/main/scala/extensions/superposition/package.scala
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package extensions
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extension methods for Superposition.
|
||||||
|
*/
|
||||||
|
package object superposition {}
|
@ -4,8 +4,8 @@ import data._
|
|||||||
import typeclasses._
|
import typeclasses._
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Typeclass instances for Identity
|
* Typeclass instances for Identity
|
||||||
*/
|
*/
|
||||||
package object identity {
|
package object identity {
|
||||||
|
|
||||||
implicit val identityFunctor: Functor[Identity] = ???
|
implicit val identityFunctor: Functor[Identity] = ???
|
||||||
|
@ -4,8 +4,8 @@ import data._
|
|||||||
import typeclasses._
|
import typeclasses._
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Typeclass instances for LispList
|
* Typeclass instances for LispList
|
||||||
*/
|
*/
|
||||||
package object lisplist {
|
package object lisplist {
|
||||||
|
|
||||||
implicit val lispListFunctor: Functor[LispList] = ???
|
implicit val lispListFunctor: Functor[LispList] = ???
|
||||||
|
@ -4,15 +4,16 @@ import data._
|
|||||||
import typeclasses._
|
import typeclasses._
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Typeclass instances for Schrodinger
|
* Typeclass instances for Schrodinger
|
||||||
*/
|
*/
|
||||||
package object schrodinger {
|
package object schrodinger {
|
||||||
|
|
||||||
implicit val schrodingerFunctor: Functor[Schrodinger[*]] = ???
|
implicit val schrodingerFunctor: Functor[Schrodinger[*]] = ???
|
||||||
|
|
||||||
implicit val schrodingerApplicative: Applicative[Schrodinger[*]] = ???
|
implicit val schrodingerApplicative: Applicative[Schrodinger[*]] = ???
|
||||||
|
|
||||||
implicit def schrodingerApplicativeError[E]: ApplicativeError[Schrodinger[*], E] = ???
|
implicit def schrodingerApplicativeError[E]
|
||||||
|
: ApplicativeError[Schrodinger[*], E] = ???
|
||||||
|
|
||||||
implicit val schrodingerMonad: Monad[Schrodinger[*]] = ???
|
implicit val schrodingerMonad: Monad[Schrodinger[*]] = ???
|
||||||
|
|
||||||
|
@ -4,15 +4,16 @@ import data._
|
|||||||
import typeclasses._
|
import typeclasses._
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Typeclass instances for State
|
* Typeclass instances for State
|
||||||
*/
|
*/
|
||||||
package object state {
|
package object state {
|
||||||
|
|
||||||
implicit def stateFunctor[S]: Functor[State[S, *]] = ???
|
implicit def stateFunctor[S]: Functor[State[S, *]] = ???
|
||||||
|
|
||||||
implicit def stateApplicative[S]: Applicative[State[S, *]] = ???
|
implicit def stateApplicative[S]: Applicative[State[S, *]] = ???
|
||||||
|
|
||||||
implicit def stateApplicativeError[S, E]: ApplicativeError[State[S, *], E] = ???
|
implicit def stateApplicativeError[S, E]: ApplicativeError[State[S, *], E] =
|
||||||
|
???
|
||||||
|
|
||||||
implicit def stateMonad[S]: Monad[State[S, *]] = ???
|
implicit def stateMonad[S]: Monad[State[S, *]] = ???
|
||||||
|
|
||||||
|
@ -4,21 +4,25 @@ import data._
|
|||||||
import typeclasses._
|
import typeclasses._
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Typeclass instances for Superposition
|
* Typeclass instances for Superposition
|
||||||
*/
|
*/
|
||||||
package object superposition {
|
package object superposition {
|
||||||
|
|
||||||
implicit def superpositionFunctor[A]: Functor[Superposition[A, *]] = ???
|
implicit def superpositionFunctor[A]: Functor[Superposition[A, *]] = ???
|
||||||
|
|
||||||
implicit def superpositionApplicative[A]: Applicative[Superposition[A, *]] = ???
|
implicit def superpositionApplicative[A]: Applicative[Superposition[A, *]] =
|
||||||
|
???
|
||||||
|
|
||||||
implicit def superpositionApplicativeError[A]: ApplicativeError[Superposition[A, *], A] = ???
|
implicit def superpositionApplicativeError[A]
|
||||||
|
: ApplicativeError[Superposition[A, *], A] = ???
|
||||||
|
|
||||||
implicit def superpositionMonad[A]: Monad[Superposition[A, *]] = ???
|
implicit def superpositionMonad[A]: Monad[Superposition[A, *]] = ???
|
||||||
|
|
||||||
implicit def superpositionMonadError[A]: MonadError[Superposition[A, *], A] = ???
|
implicit def superpositionMonadError[A]: MonadError[Superposition[A, *], A] =
|
||||||
|
???
|
||||||
|
|
||||||
implicit def superpositionMonoid[A, B]: Monoid[Superposition[A, B]] = ???
|
implicit def superpositionMonoid[A, B]: Monoid[Superposition[A, B]] = ???
|
||||||
|
|
||||||
implicit def superpositionSemigroup[A, B]: Semigroup[Superposition[A, B]] = ???
|
implicit def superpositionSemigroup[A, B]: Semigroup[Superposition[A, B]] =
|
||||||
|
???
|
||||||
}
|
}
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
package ops
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Typeclass extension methods for Identity
|
|
||||||
*/
|
|
||||||
package object identity {
|
|
||||||
|
|
||||||
}
|
|
@ -1,8 +0,0 @@
|
|||||||
package ops
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Typeclass extension methods for LispList
|
|
||||||
*/
|
|
||||||
package object lisplist {
|
|
||||||
|
|
||||||
}
|
|
@ -1,8 +0,0 @@
|
|||||||
package ops
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Typeclass extension methods for Schrodinger.
|
|
||||||
*/
|
|
||||||
package object schrodinger {
|
|
||||||
|
|
||||||
}
|
|
@ -1,8 +0,0 @@
|
|||||||
package ops
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Typeclass extension methods for State.
|
|
||||||
*/
|
|
||||||
package object state {
|
|
||||||
|
|
||||||
}
|
|
@ -1,8 +0,0 @@
|
|||||||
package ops
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Typeclass extension methods for Superposition.
|
|
||||||
*/
|
|
||||||
package object superposition {
|
|
||||||
|
|
||||||
}
|
|
@ -1,24 +1,24 @@
|
|||||||
package typeclasses
|
package typeclasses
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines the Applicative operations for any type of kind F[_]. Applicative
|
* Defines the Applicative operations for any type of kind F[_]. Applicative
|
||||||
* is a special case of Functor that can apply a function lifted into F[_] to
|
* is a special case of Functor that can apply a function lifted into F[_] to
|
||||||
* a value also lifted into F[_].
|
* a value also lifted into F[_].
|
||||||
*/
|
*/
|
||||||
trait Applicative[F[_]] extends Functor[F] {
|
trait Applicative[F[_]] extends Functor[F] {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lift a value into F[_].
|
* Lift a value into F[_].
|
||||||
*/
|
*/
|
||||||
def pure[A](a: A): F[A] = ???
|
def pure[A](a: A): F[A] = ???
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lift a value into F[_] and apply it to a lifted function.
|
* Lift a value into F[_] and apply it to a lifted function.
|
||||||
*/
|
*/
|
||||||
def ap[A, B](ff: F[A => B])(fa: F[A]): F[B]
|
def ap[A, B](ff: F[A => B])(fa: F[A]): F[B]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This can be defined in terms of ap and pure alone, try it out!
|
* This can be defined in terms of ap and pure alone, try it out!
|
||||||
*/
|
*/
|
||||||
override def map[A, B](fa: F[A])(f: A => B): F[B] = ???
|
override def map[A, B](fa: F[A])(f: A => B): F[B] = ???
|
||||||
}
|
}
|
||||||
|
@ -1,25 +1,25 @@
|
|||||||
package typeclasses
|
package typeclasses
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines the ApplicativeError operations for any type of kind F[_] for error
|
* Defines the ApplicativeError operations for any type of kind F[_] for error
|
||||||
* type E. ApplicativeError is a special case of Applicative where the type
|
* type E. ApplicativeError is a special case of Applicative where the type
|
||||||
* kind of F[_] may represent a superposition of "success" or "error" cases
|
* kind of F[_] may represent a superposition of "success" or "error" cases
|
||||||
* and affords operations to create and recover these error cases.
|
* and affords operations to create and recover these error cases.
|
||||||
*/
|
*/
|
||||||
trait ApplicativeError[F[_], E] extends Applicative[F] {
|
trait ApplicativeError[F[_], E] extends Applicative[F] {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lift an error handler into F[_] to apply to E.
|
* Lift an error handler into F[_] to apply to E.
|
||||||
*/
|
*/
|
||||||
def handleError[A](fa: F[A])(f: E => A): F[A]
|
def handleError[A](fa: F[A])(f: E => A): F[A]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lift an error handler into F[_] to apply to E, returning a lifted result.
|
* Lift an error handler into F[_] to apply to E, returning a lifted result.
|
||||||
*/
|
*/
|
||||||
def handleErrorWith[A](fa: F[A])(f: E => F[A]): F[A]
|
def handleErrorWith[A](fa: F[A])(f: E => F[A]): F[A]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A special case of pure() which lifts an error E into F[_].
|
* A special case of pure() which lifts an error E into F[_].
|
||||||
*/
|
*/
|
||||||
def raiseError[A](e: E): F[A] = ???
|
def raiseError[A](e: E): F[A] = ???
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
package typeclasses
|
package typeclasses
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines the Functor operations for any type of kind F[_]. Functors allow for
|
* Defines the Functor operations for any type of kind F[_]. Functors allow for
|
||||||
* a function to be applied to a value lifted into F[_].
|
* a function to be applied to a value lifted into F[_].
|
||||||
*/
|
*/
|
||||||
trait Functor[F[_]] {
|
trait Functor[F[_]] {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Applies a lifted value to a function.
|
* Applies a lifted value to a function.
|
||||||
*/
|
*/
|
||||||
def map[A, B](fa: F[A])(f: A => B): F[B]
|
def map[A, B](fa: F[A])(f: A => B): F[B]
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
package typeclasses
|
package typeclasses
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines the Monad operations for any type of kind F[_]. A Monad is a special
|
* Defines the Monad operations for any type of kind F[_]. A Monad is a special
|
||||||
* case of Applicative where the application of a function to a lifted value
|
* case of Applicative where the application of a function to a lifted value
|
||||||
* in F[_] may itself return a lifted value. This is especially powerful because
|
* in F[_] may itself return a lifted value. This is especially powerful because
|
||||||
* the lifted result may represent a case against which no further operations
|
* the lifted result may represent a case against which no further operations
|
||||||
* may be performed, which can model short-circuiting on errors!
|
* may be performed, which can model short-circuiting on errors!
|
||||||
*/
|
*/
|
||||||
trait Monad[F[_]] extends Applicative[F] {
|
trait Monad[F[_]] extends Applicative[F] {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lift an apply a function into F[_] and apply it to the value. The function
|
* Lift an apply a function into F[_] and apply it to the value. The function
|
||||||
* returns its own lifted result.
|
* returns its own lifted result.
|
||||||
*/
|
*/
|
||||||
def flatMap[A, B](fa: F[A])(f: A => F[B]): F[B]
|
def flatMap[A, B](fa: F[A])(f: A => F[B]): F[B]
|
||||||
}
|
}
|
||||||
|
@ -3,29 +3,29 @@ package typeclasses
|
|||||||
import data.Superposition
|
import data.Superposition
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines the MonadOperations operations for any type of kind F[_] for error
|
* Defines the MonadOperations operations for any type of kind F[_] for error
|
||||||
* type E. MonadError is a special case of ApplicativeError and Monad that
|
* type E. MonadError is a special case of ApplicativeError and Monad that
|
||||||
* further augments error handling operations.
|
* further augments error handling operations.
|
||||||
*/
|
*/
|
||||||
trait MonadError[F[_], E] extends Monad[F] with ApplicativeError[F, E] {
|
trait MonadError[F[_], E] extends Monad[F] with ApplicativeError[F, E] {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Replaces A with E if the lifted A does not satisfy the predicate.
|
* Replaces A with E if the lifted A does not satisfy the predicate.
|
||||||
*/
|
*/
|
||||||
def ensure[A](fa: F[A])(error: => E)(predicate: A => Boolean): F[A]
|
def ensure[A](fa: F[A])(error: => E)(predicate: A => Boolean): F[A]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Replaces A with E by means of A if the lifted A does not satisfy the predicate.
|
* Replaces A with E by means of A if the lifted A does not satisfy the predicate.
|
||||||
*/
|
*/
|
||||||
def ensureOr[A](fa: F[A])(error: A => E)(predicate: A => Boolean): F[A]
|
def ensureOr[A](fa: F[A])(error: A => E)(predicate: A => Boolean): F[A]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Applies a partial function to the E, if any.
|
* Applies a partial function to the E, if any.
|
||||||
*/
|
*/
|
||||||
def adaptError[A](fa: F[A])(pf: PartialFunction[E, E]): F[A]
|
def adaptError[A](fa: F[A])(pf: PartialFunction[E, E]): F[A]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inverse of ApplicativeError attempt().
|
* Inverse of ApplicativeError attempt().
|
||||||
*/
|
*/
|
||||||
def rethrow[A, EE <: E](fa: F[Superposition[EE, A]]): F[A]
|
def rethrow[A, EE <: E](fa: F[Superposition[EE, A]]): F[A]
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
package typeclasses
|
package typeclasses
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Monoid is a special case of a Semigroup for which an element of A, when
|
* A Monoid is a special case of a Semigroup for which an element of A, when
|
||||||
* applied to any other element of A in any order, returns that other element.
|
* applied to any other element of A in any order, returns that other element.
|
||||||
* It forms an identity value with which its application merely returns the
|
* It forms an identity value with which its application merely returns the
|
||||||
* identity of its associated operand, similar in concept to the identity
|
* identity of its associated operand, similar in concept to the identity
|
||||||
* function.
|
* function.
|
||||||
*/
|
*/
|
||||||
trait Monoid[A] extends Semigroup[A] {
|
trait Monoid[A] extends Semigroup[A] {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The identity of A.
|
* The identity of A.
|
||||||
*/
|
*/
|
||||||
def empty: A
|
def empty: A
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
package typeclasses
|
package typeclasses
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A semigroup is a special case of a binary operation that is both associative
|
* A semigroup is a special case of a binary operation that is both associative
|
||||||
* and for any two A the operation returns another member of A. In a sense, the
|
* and for any two A the operation returns another member of A. In a sense, the
|
||||||
* Semigroup operation can be used from any two starting members of A to produce
|
* Semigroup operation can be used from any two starting members of A to produce
|
||||||
* all successive members of A.
|
* all successive members of A.
|
||||||
*/
|
*/
|
||||||
trait Semigroup[A] {
|
trait Semigroup[A] {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Binary, associative operation against two of A to produce another A.
|
* Binary, associative operation against two of A to produce another A.
|
||||||
*/
|
*/
|
||||||
def <>(x: A, b: A): A
|
def <>(x: A, b: A): A
|
||||||
}
|
}
|
||||||
|
56
src/test/scala/conversions/LispListSpec.scala
Normal file
56
src/test/scala/conversions/LispListSpec.scala
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
package conversions
|
||||||
|
|
||||||
|
import data.{Cons, LispList, Nil}
|
||||||
|
import org.scalatest.matchers.should.Matchers
|
||||||
|
import org.scalatest.wordspec.AnyWordSpecLike
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream
|
||||||
|
|
||||||
|
class LispListSpec extends AnyWordSpecLike with Matchers {
|
||||||
|
|
||||||
|
"LispList" can {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exercise: Implicit Conversions
|
||||||
|
*/
|
||||||
|
"convert types" which {
|
||||||
|
val lispList: LispList[Int] = Cons(1, Cons(2, Cons(3, Nil)))
|
||||||
|
def lengthAsList[A](list: List[A]): Int = list.length
|
||||||
|
|
||||||
|
"become a List" in {
|
||||||
|
import conversions.lisplist._
|
||||||
|
lengthAsList(lispList) shouldBe 3
|
||||||
|
}
|
||||||
|
|
||||||
|
"become a Seq, but loudly" in {
|
||||||
|
val out = new ByteArrayOutputStream()
|
||||||
|
Console.withOut(out) {
|
||||||
|
pending
|
||||||
|
//lengthAsSeq(lispList) shouldBe 3
|
||||||
|
}
|
||||||
|
out.toString should contain("THREE OF THEM!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exercise: Explicit conversions with extension methods
|
||||||
|
*/
|
||||||
|
"explicitly convert types" which {
|
||||||
|
val lispList = Cons(1, Cons(2, Cons(3, Nil)))
|
||||||
|
|
||||||
|
"asList" can {
|
||||||
|
import extensions.lisplist._
|
||||||
|
|
||||||
|
"explicitly become a List" in {
|
||||||
|
lispList.asList shouldBe List(1, 2, 3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"asSeq" can {
|
||||||
|
"explicitly become a Seq" in {
|
||||||
|
pending
|
||||||
|
//lispList.asList should eq(Seq(1, 2, 3))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
48
src/test/scala/extensions/LispListSpec.scala
Normal file
48
src/test/scala/extensions/LispListSpec.scala
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
package extensions
|
||||||
|
|
||||||
|
import data.{Cons, Nil}
|
||||||
|
import org.scalatest.matchers.should.Matchers
|
||||||
|
import org.scalatest.wordspec.AnyWordSpecLike
|
||||||
|
|
||||||
|
class LispListSpec extends AnyWordSpecLike with Matchers {
|
||||||
|
|
||||||
|
"LispList" can {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exercise: Create a length method
|
||||||
|
*/
|
||||||
|
"length" which {
|
||||||
|
"returns 0 if the list is Nil" in {
|
||||||
|
import extensions.lisplist._
|
||||||
|
|
||||||
|
val lispList = Nil
|
||||||
|
lispList.length shouldBe 0
|
||||||
|
}
|
||||||
|
"returns the length of the list" in {
|
||||||
|
import conversions.lisplist._
|
||||||
|
val lispList = Cons(1, Cons(2, Cons(3, Nil)))
|
||||||
|
lispList.map(_ * 2) shouldBe 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exercise: Create a schrodingersCar method
|
||||||
|
*/
|
||||||
|
"schrodingersCar" which {
|
||||||
|
"returns Dead" when {
|
||||||
|
"list is Nil" in {
|
||||||
|
val lispList = Nil
|
||||||
|
pending
|
||||||
|
//lispList.schrodingersCar should eq(Dead)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"returns Alive containing the first value" when {
|
||||||
|
"the list is not Nil" in {
|
||||||
|
val lispList = Cons("Ferrari", Cons("Lamborghini", Cons("Honda Fit", Nil)))
|
||||||
|
pending
|
||||||
|
//lispList.schrodingersCar should eq(Alive("Ferrari"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,52 +0,0 @@
|
|||||||
package extensions
|
|
||||||
|
|
||||||
import org.scalatest.matchers.should.Matchers
|
|
||||||
import org.scalatest.wordspec.AnyWordSpecLike
|
|
||||||
|
|
||||||
class MapSpec extends AnyWordSpecLike with Matchers {
|
|
||||||
"ConsList" can {
|
|
||||||
"map" which {
|
|
||||||
"transforms every element it contains" in {
|
|
||||||
pending
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"Superposition" can {
|
|
||||||
"map" which {
|
|
||||||
"ignores the value of Downside" in {
|
|
||||||
pending
|
|
||||||
}
|
|
||||||
"transforms the value of Upside" in {
|
|
||||||
pending
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"Schrodinger" can {
|
|
||||||
"map" which {
|
|
||||||
"ignores Dead cat" in {
|
|
||||||
pending
|
|
||||||
}
|
|
||||||
"transforms Alive cat" in {
|
|
||||||
pending
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"State" can {
|
|
||||||
"map" which {
|
|
||||||
"transforms the result of a stateful computation" in {
|
|
||||||
pending
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"Identity" can {
|
|
||||||
"map" which {
|
|
||||||
"transforms itself" in {
|
|
||||||
pending
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user