Compare commits
No commits in common. "main" and "presentation-01" have entirely different histories.
main
...
presentati
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