Skip to content

Instantly share code, notes, and snippets.

@rbobillot
Created June 14, 2022 00:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rbobillot/90e5a7ce4ed578bfffe2f7871105b4f7 to your computer and use it in GitHub Desktop.
Save rbobillot/90e5a7ce4ed578bfffe2f7871105b4f7 to your computer and use it in GitHub Desktop.
object Main {
import scala.language.higherKinds
/**
* Functor contains a function
* that maps from a category to another
*/
trait Functor[F[_]] {
def map[A, B](fa: F[A])(f: A => B): F[B]
}
/**
* Comonad, like a Monad, is a Functor
* Comonad, is actually kind of the opposite of a Monad
* unit becomes counit : A => M[A] becomes C[A] => A
* join becomes cojoin : M[M[A]] => M[A] becomes C[A] => C[C[A]]
* >>= becomes =>> : M[A] => (A => M[B]) => M[B] becomes C[A] => (C[A] => B) => C[A]
*/
trait Comonad[C[_]] extends Functor[C] {
def coUnit[A](ca: C[A]): A
def coJoin[A](ca: C[A]): C[C[A]]
def map[A, B](ca: C[A])(f: A => B): C[B]
def =>>[A, B](ca: C[A])(g: C[A] => B): C[B]
}
/**
* Instance of Comonad for List collection type
* coJoin returns a list of tails from a list:
* [1,2,3,4] : [[1,2,3,4],[2,3,4],[3,4],[4],[]]
*/
val listComonad = new Comonad[List] {
def coUnit[A](ca: List[A]): A = ca.head
def coJoin[A](ca: List[A]): List[List[A]] = ca.tails.toList
def map[A, B](ca: List[A])(f: A => B): List[B] = for (a <- ca) yield f(a)
def =>>[A, B](ca: List[A])(g: List[A] => B): List[B] = map(coJoin(ca))(g)
}
/**
* slices uses the cobind function (=>>) from the Comonad pattern
* to simulate a `digits.sliding(n)`
* We could have used coJoin instead:
* listComonad coJoin (digits) map (_ take n) filter (_.size == n)
*/
def slices(n: Int, digits: List[Int]): List[List[Int]] =
listComonad.=>>(digits)(_ take n).filter(_.size == n)
def main(av: Array[String]): Unit =
av.toList match {
case str :: n :: Nil if (str+n).forall(_.isDigit) =>
println(slices(n.toInt, str.toList.map(_.asDigit)).map(_.mkString("[",",","]")).mkString("[",",","]"))
case _ =>
println("run with: scala comonad.scala <digits:string> <windowing:int>")
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment