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

Cats all the things #1

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
20 changes: 11 additions & 9 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name := "comonadic_life"

version := "0.1"

scalaVersion := "2.12.9"
scalaVersion := "2.13.1"

scalacOptions ++= Seq(
"-deprecation",
Expand All @@ -12,17 +12,19 @@ scalacOptions ++= Seq(
"-language:higherKinds",
"-language:implicitConversions",
"-unchecked",
"-Ypartial-unification",
"-Ywarn-numeric-widen"
)
scalacOptions in (Compile, console) --= Seq("-Ywarn-unused:imports", "-Xfatal-warnings")
scalacOptions in(Compile, console) --= Seq("-Ywarn-unused:imports", "-Xfatal-warnings")

libraryDependencies ++= Seq(
"org.scalatest" %% "scalatest" % "3.0.8" % Test,
"org.scalactic" %% "scalactic" % "3.0.8",
"org.typelevel" %% "cats-effect" % "2.0.0",
"co.fs2" %% "fs2-core" % "2.1.0",
"com.lihaoyi" %% "pprint" % "0.5.6"
"org.scalactic" %% "scalactic" % "3.0.8",
"org.typelevel" %% "cats-core" % "2.0.0",
"org.typelevel" %% "cats-effect" % "2.0.0",
"co.fs2" %% "fs2-core" % "2.1.0",
"com.lihaoyi" %% "pprint" % "0.5.6",
"org.scalatest" %% "scalatest" % "3.0.8" % Test,
"com.github.alexarchambault" %% "scalacheck-shapeless_1.14" % "1.2.3" % Test,
"org.typelevel" %% "cats-testkit-scalatest" % "1.0.0-RC1" % Test
)

mainClass in (Compile, run) := Some("conway.Main")
mainClass in(Compile, run) := Some("conway.Main")
1 change: 0 additions & 1 deletion src/main/scala/conway/Console.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package conway

import cats.effect.Sync
import cats.syntax.all._
import conway.Main.Coordinates

import scala.util.Try

Expand Down
6 changes: 3 additions & 3 deletions src/main/scala/conway/Game.scala
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package conway

import typeclasses.data.GridZipper
import typeclasses.data.GridZipper._
import typeclasses.syntax.gridZipper._
import conway.data.GridZipper
import cats.syntax.comonad._
import cats.syntax.coflatMap._

object Game {

Expand Down
6 changes: 1 addition & 5 deletions src/main/scala/conway/Main.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package conway

import typeclasses.data.GridZipper
import typeclasses.syntax.gridZipper._
import conway.data.GridZipper
import cats.effect.{ExitCode, IO, IOApp, Sync, Timer}
import cats.syntax.all._
import conway.Game._
Expand All @@ -11,8 +10,6 @@ import scala.concurrent.duration._

object Main extends IOApp {

type Coordinates = (Int, Int)

def createCoordinateLists(width: Int): List[List[Coordinates]] = {
val coords: List[Coordinates] = (for {
x <- 0 until width
Expand All @@ -27,7 +24,6 @@ object Main extends IOApp {
gridZipperCoordinates.map(setCellValue)
}


def setCellValue(coord: (Int, Int), initialStateMap: Map[Coordinates, Int]): Int = {
initialStateMap.getOrElse(coord, 0)
}
Expand Down
2 changes: 0 additions & 2 deletions src/main/scala/conway/Patterns.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package conway

import conway.Main.Coordinates

sealed trait Patterns {
val shape: Map[Coordinates, Int]
val value: Int
Expand Down
7 changes: 3 additions & 4 deletions src/main/scala/conway/Renderer.scala
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
package conway

import typeclasses.data.GridZipper
import typeclasses.syntax.gridZipper._
import typeclasses.syntax.zipper._
import conway.data.GridZipper
import cats.effect.Sync
import cats.syntax.all._
import cats.syntax.functor._
import cats.syntax.flatMap._

import scala.sys.process._

Expand Down
1 change: 0 additions & 1 deletion src/main/scala/conway/Visualization.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package conway


trait Visualization {
val alive: String
val background: String
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
package typeclasses.data
package conway.data

import typeclasses.Comonad
import typeclasses.data.Zipper._
import typeclasses.syntax.gridZipper._
import typeclasses.syntax.zipper._
import cats.{Comonad, Eq}
import cats.syntax.comonad._
import cats.syntax.functor._

// 2 dimensions represented by nested Zippers
case class GridZipper[A](value: Zipper[Zipper[A]]) {
Expand All @@ -13,25 +12,20 @@ case class GridZipper[A](value: Zipper[Zipper[A]]) {
GridZipper(value.setFocus(inner))
}

def prettyPrint: String = {
def prettyPrint: String =
value.toList.map(x => x.prettyPrint).mkString("\n")
}

def north: GridZipper[A] = {
def north: GridZipper[A] =
GridZipper(value.moveLeft)
}

def south: GridZipper[A] = {
def south: GridZipper[A] =
GridZipper(value.moveRight)
}

def east: GridZipper[A] = {
def east: GridZipper[A] =
GridZipper(value.map(xAxis => xAxis.moveRight))
}

def west: GridZipper[A] = {
def west: GridZipper[A] =
GridZipper(value.map(xAxis => xAxis.moveLeft))
}

def getNeighbors: List[A] = {
List(
Expand All @@ -49,42 +43,48 @@ case class GridZipper[A](value: Zipper[Zipper[A]]) {

object GridZipper {

def fromLists[A](lists: List[List[A]]): GridZipper[A] = {
def fromLists[A](lists: List[List[A]]): GridZipper[A] =
GridZipper(Zipper.fromList(lists.map(Zipper.fromList)))
}

implicit def gridZipperComonad: Comonad[GridZipper] = {
implicit def gridZipperEq[A: Eq]: Eq[GridZipper[A]] =
Eq.by(_.value)

implicit val gridZipperComonad: Comonad[GridZipper] =
new Comonad[GridZipper] {
override def extract[A](w: GridZipper[A]): A = w.value.focus.focus
override def extract[A](w: GridZipper[A]): A =
w.value.focus.focus

override def duplicate[A](w: GridZipper[A]): GridZipper[GridZipper[A]] = {
override def coflatten[A](w: GridZipper[A]): GridZipper[GridZipper[A]] = {
val s1: Zipper[Zipper[Zipper[A]]] = nest(w.value)
val s2: Zipper[Zipper[Zipper[Zipper[A]]]] = nest(s1)
val g1: GridZipper[Zipper[Zipper[A]]] = GridZipper(s2)
val g2: GridZipper[GridZipper[A]] = map(g1)(GridZipper(_))
g2
}

override def map[A, B](fa: GridZipper[A])(f: A => B): GridZipper[B] = GridZipper(fa.value.map(s => s.map(f)))
override def coflatMap[A, B](w: GridZipper[A])(f: GridZipper[A] => B): GridZipper[B] =
map(coflatten(w))(f)

override def map[A, B](gz: GridZipper[A])(f: A => B): GridZipper[B] =
GridZipper(gz.value.map(z => z map f))

private def nest[A](s: Zipper[Zipper[A]]): Zipper[Zipper[Zipper[A]]] = {
val duplicateLefts: Stream[Zipper[Zipper[A]]] = {
// Zipper.unfold(s)(z => z.maybeLeft.flatMap(y => y.maybeLeft.map(x => (x,x))))
Stream.iterate(s)(current => current.map(_.moveLeft))
val duplicateLefts: LazyList[Zipper[Zipper[A]]] = {
// Zipper.unfold(s)(z => z.maybeLeft.flatMap(y => y.maybeLeft.map(x => (x,x))))
LazyList.iterate(s)(current => current.map(_.moveLeft))
.tail
.zip(s.left)
.map(_._1)
}

val duplicateRights: Stream[Zipper[Zipper[A]]] =
// Zipper.unfold(s)(z => z.maybeRight.flatMap(y => y.maybeRight.map(x => (x,x))))
Stream.iterate(s)(current => current.map(_.moveRight))
val duplicateRights: LazyList[Zipper[Zipper[A]]] =
// Zipper.unfold(s)(z => z.maybeRight.flatMap(y => y.maybeRight.map(x => (x,x))))
LazyList.iterate(s)(current => current.map(_.moveRight))
.tail
.zip(s.right)
.map(_._1)

Zipper(duplicateLefts, s, duplicateRights)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package typeclasses.data
package conway.data

import typeclasses.Comonad
import typeclasses.data.Zipper.unfold
import cats.{Comonad, Eq}
import cats.instances.lazyList._
import conway.data.Zipper.unfold

case class Zipper[A](left: Stream[A], focus: A, right: Stream[A]) {
case class Zipper[A](left: LazyList[A], focus: A, right: LazyList[A]) {

def maybeRight: Option[Zipper[A]] = right match {
case nextRight #:: rights => Some(Zipper(focus #:: left, nextRight, rights))
Expand All @@ -21,7 +22,7 @@ case class Zipper[A](left: Stream[A], focus: A, right: Stream[A]) {

def moveRight: Zipper[A] = {
if (right.isEmpty) this
else Zipper(focus #:: left , right.head, right.tail)
else Zipper(focus #:: left, right.head, right.tail)
}

def moveLeft: Zipper[A] = {
Expand All @@ -36,42 +37,45 @@ case class Zipper[A](left: Stream[A], focus: A, right: Stream[A]) {
leftValues ++ focus ++ rightValues
}

def toList: List[A] = {
def toList: List[A] =
left.toList.reverse ++ (focus +: right.toList)
}

def toStream: Stream[A] = {
def toStream: LazyList[A] =
left.reverse #::: (focus #:: right)
}

def duplicateRight[B](f:Zipper[A] => B): Stream[B] =
def duplicateRight[B](f: Zipper[A] => B): LazyList[B] =
unfold(this)(z => z.maybeRight.map(x => (f(x), x)))

def duplicateLeft[B](f:Zipper[A] => B): Stream[B] =
def duplicateLeft[B](f: Zipper[A] => B): LazyList[B] =
unfold(this)(z => z.maybeLeft.map(x => (f(x), x)))

}

object Zipper {
def fromList[A](items: List[A]): Zipper[A] = {
// Will throw if items is empty, so beware!
Zipper(items.tail.toStream, items.head, Stream.empty)
}
def fromList[A](items: List[A]): Zipper[A] =
Zipper(LazyList.from(items.tail), items.head, LazyList.empty)

def unfold[A, B](a: A)(f: A => Option[(B, A)]): Stream[B] = f(a) match {
case Some((b, a)) => b #:: unfold(a)(f)
case None => Stream.empty

def unfold[A, B](a: A)(f: A => Option[(B, A)]): LazyList[B] =
f(a) match {
case Some((b, a)) => b #:: unfold(a)(f)
case None => LazyList.empty
}


implicit def zipperEq[A: Eq]: Eq[Zipper[A]] = {
import Eq._
and(and(by(_.left),by(_.focus)), by(_.right))
}

implicit def zipperComonad: Comonad[Zipper] = new Comonad[Zipper] {
override def extract[A](w: Zipper[A]): A = w.focus
override def extract[A](w: Zipper[A]): A =
w.focus

override def duplicate[A](w: Zipper[A]): Zipper[Zipper[A]] = {
Zipper(w.duplicateLeft(identity), w, w.duplicateRight(identity))
}
override def map[A, B](fa: Zipper[A])(f: A => B): Zipper[B] =
Zipper(fa.left.map(f), f(fa.focus), fa.right.map(f))

override def map[A, B](fa: Zipper[A])(f: A => B): Zipper[B] = {
Zipper(fa.left.map(f) ,f(fa.focus), fa.right.map(f))
}
override def coflatMap[A, B](fa: Zipper[A])(f: Zipper[A] => B): Zipper[B] =
Zipper(fa.duplicateLeft(f), f(fa), fa.duplicateRight(f))
}
}
12 changes: 8 additions & 4 deletions src/main/scala/conway/package.scala
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import conway.Main.Coordinates

package object conway {

type Coordinates = (Int, Int)

implicit class InitOps(presetShapes: Map[Coordinates, Int]) {
def at(coordinates: Coordinates): Map[Coordinates, Int] = presetShapes.map {
case ((x, y), v) => ((x + coordinates._2, y + coordinates._1), v)
}
def at(coordinates: Coordinates): Map[Coordinates, Int] =
presetShapes.map {
case ((x, y), v) => ((x + coordinates._2, y + coordinates._1), v)
}
}

}
25 changes: 0 additions & 25 deletions src/main/scala/typeclasses/Comonad.scala

This file was deleted.

5 changes: 0 additions & 5 deletions src/main/scala/typeclasses/Functor.scala

This file was deleted.

7 changes: 0 additions & 7 deletions src/main/scala/typeclasses/Monad.scala

This file was deleted.

16 changes: 0 additions & 16 deletions src/main/scala/typeclasses/syntax/gridZipper.scala

This file was deleted.

Loading