Skip to content

Instantly share code, notes, and snippets.

@imeredith
Created July 11, 2012 11:38
Show Gist options
  • Save imeredith/3089818 to your computer and use it in GitHub Desktop.
Save imeredith/3089818 to your computer and use it in GitHub Desktop.
trait PartialType[T[_, _], A] {
type Apply[B] = T[A, B]
type Flip[B] = T[B, A]
}
trait Fluffy[F[_]] {
def furry[A, B](f: A => B, fa: F[A]): F[B]
}
object Fluffy {
// Exercise 1
// Relative Difficulty: 1
def ListFluffy: Fluffy[List] = new Fluffy[List] {
def furry[A, B](f: (A) => B, fa: List[A]): List[B] = fa.map(f)
}
// Exercise 2
// Relative Difficulty: 1
def OptionFluffy: Fluffy[Option] = new Fluffy[Option] {
def furry[A, B](f: (A) => B, fa: Option[A]): Option[B] = fa.map(f)
}
// Exercise 3
// Relative Difficulty: 1
def StreamFluffy: Fluffy[Stream] = new Fluffy[Stream] {
def furry[A, B](f: (A) => B, fa: Stream[A]): Stream[B] = fa.map(f)
}
// Exercise 5
// Relative Difficulty: 5
def Function1Fluffy[X]: Fluffy[PartialType[Function1, X]#Apply] = new Fluffy[PartialType[Function1, X]#Apply] {
def furry[A, B](f: Function1[A, B], fa: Function1[X, A]): Function1[X, B] = f.compose(fa)
}
// Exercise 6
// Relative Difficulty: 6
def EitherLeftFluffy[X]: Fluffy[PartialType[Either.LeftProjection, X]#Flip] = new Fluffy[PartialType[LeftProjection, X]#Flip] {
def furry[A, B](f: (A) => B, fa: LeftProjection[A, X]): LeftProjection[B, X] = LeftProjection(fa.map(f))
}
// Exercise 7
// Relative Difficulty: 4
def EitherRightFluffy[X]: Fluffy[PartialType[Either.RightProjection, X]#Apply] = new Fluffy[PartialType[RightProjection, X]#Apply] {
def furry[A, B](f: (A) => B, fa: RightProjection[X, A]): RightProjection[X, B] = RightProjection(fa.map(f))
}
}
trait Misty[M[_]] extends Fluffy[M] {
def banana[A, B](f: A => M[B], ma: M[A]): M[B]
def unicorn[A](a: A): M[A]
// Exercise 8
// Relative Difficulty: 3
// (use banana and/or unicorn)
def furry[A, B](f: A => B, ma: M[A]): M[B] = banana((a: A) => unicorn(f(a)), ma)
}
object Misty {
// Exercise 9
// Relative Difficulty: 2
def ListMisty: Misty[List] = new Misty[List] {
def banana[A, B](f: (A) => List[B], ma: List[A]): List[B] = ma flatMap f
def unicorn[A](a: A): List[A] = List(a)
}
// Exercise 10
// Relative Difficulty: 2
def OptionMisty: Misty[Option] = new Misty[Option] {
def banana[A, B](f: (A) => Option[B], ma: Option[A]): Option[B] = ma flatMap f
def unicorn[A](a: A): Option[A] = Option(a)
}
// Exercise 11
// Relative Difficulty: 2
def StreamMisty: Misty[Stream] = new Misty[Stream] {
def banana[A, B](f: (A) => Stream[B], ma: Stream[A]): Stream[B] = ma flatMap f
def unicorn[A](a: A): Stream[A] = Stream(a)
}
// Exercise 13
// Relative Difficulty: 6
def Function1Misty[X]: Misty[PartialType[Function1, X]#Apply] = new Misty[PartialType[Function1, X]#Apply] {
def banana[A, B](f: (A) => (X) => B, ma: (X) => A): (X) => B = (x: X) => f(ma(x))(x)
def unicorn[A](a: A): (X) => A = (_) => a
}
// Exercise 14
// Relative Difficulty: 7
def EitherLeftMisty[X]: Misty[PartialType[Either.LeftProjection, X]#Flip] = new Misty[PartialType[LeftProjection, X]#Flip] {
def banana[A, B](f: (A) => LeftProjection[B, X], ma: LeftProjection[A, X]): LeftProjection[B,X]= LeftProjection(ma.flatMap{ a => f(a).e})
def unicorn[A](a: A): PartialType[LeftProjection, X]#Flip[A] = Left[A,X](a).left
}
// Exercise 15
// Relative Difficulty: 5
def EitherRightMisty[X]: Misty[PartialType[Either.RightProjection, X]#Apply] = new Misty[PartialType[RightProjection, X]#Apply] {
def banana[A, B](f: (A) => PartialType[RightProjection, X]#Apply[B], ma: PartialType[RightProjection, X]#Apply[A]): PartialType[RightProjection, X]#Apply[B] =
RightProjection(ma.flatMap{ a => f(a).e})
def unicorn[A](a: A): PartialType[RightProjection, X]#Apply[A] = Right[X, A](a).right
}
// Exercise 16
// Relative Difficulty: 3
def jellybean[M[_], A](ma: M[M[A]], m: Misty[M]): M[A] = m.banana((a: M[A]) => a, ma)
// Exercise 17
// Relative Difficulty: 6
def apple[M[_], A, B](ma: M[A], mf: M[A => B], m: Misty[M]): M[B] = m.banana((a: A) => m.banana((b: A=>B) => m.unicorn(b(a)), mf), ma)
// Exercise 18
// Relative Difficulty: 6
def moppy[M[_], A, B](as: List[A], f: A => M[B], m: Misty[M]): M[List[B]] = as.foldLeft(m.unicorn(List[B]())) {
(mb,a) => m.banana((c:B) => m.banana((d: List[B]) => m.unicorn(d ++ List(c)), mb),f(a))
}
}
object AdvancedFun {
case class State[S, A](f: S => (S, A))
// Exercise 19
// Relative Difficulty: 9
def StateFluffy[S]: Fluffy[PartialType[State, S]#Apply] = new Fluffy[PartialType[State, S]#Apply] {
def furry[A, B](f: (A) => B, fa: PartialType[State, S]#Apply[A]): PartialType[State, S]#Apply[B] = State((s:S) => fa.f(s) match {case (a,b) => (a, f(b))})
}
// Exercise 20
// Relative Difficulty: 10
def StateMisty[S]: Misty[PartialType[State, S]#Apply] = new Misty[PartialType[State, S]#Apply] {
def banana[A, B](f: (A) => PartialType[State, S]#Apply[B], ma: PartialType[State, S]#Apply[A]): PartialType[State, S]#Apply[B] =
State((st: S) => ma.f(st) match {case (s,a) => f(a).f(s)})
def unicorn[A](a: A): PartialType[State, S]#Apply[A] = State((s: S) => (s,a))
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment