Skip to content

Instantly share code, notes, and snippets.

@JohnNilsson
Created September 19, 2011 21:46
Show Gist options
  • Save JohnNilsson/1227708 to your computer and use it in GitHub Desktop.
Save JohnNilsson/1227708 to your computer and use it in GitHub Desktop.
20 Intermediate Scala Exercises by Tony Morris
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 4
// Relative Difficulty: 1
//def ArrayFluffy: Fluffy[Array] = new Fluffy[Array] {
// def furry[A,B](f: A => B, fa: Array[A]): Array[B] = (fa map f).toArray[B]
//}
// Exercise 5
// Relative Difficulty: 5
def Function1Fluffy[X]: Fluffy[PartialType[Function1, X]#Apply] =
new Fluffy[PartialType[Function1, X]#Apply] {
def furry[A,B](f: A => B, fa: X => A): X => B = fa andThen f
}
// Exercise 6
// Relative Difficulty: 6
def EitherLeftFluffy[X]: Fluffy[PartialType[Either.LeftProjection, X]#Flip] =
new Fluffy[PartialType[Either.LeftProjection, X]#Flip] {
def furry[A,B](f: A => B, fa: Either.LeftProjection[A,X]):Either.LeftProjection[B,X] =
Either.LeftProjection(fa map f)
}
// Exercise 7
// Relative Difficulty: 4
def EitherRightFluffy[X]: Fluffy[PartialType[Either.RightProjection, X]#Apply] =
new Fluffy[PartialType[Either.RightProjection, X]#Apply] {
def furry[A, B](f: A => B, fa: Either.RightProjection[X,A]): Either.RightProjection[X,B] =
Either.RightProjection[X,B](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(f andThen unicorn, 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] = Some(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 12
// Relative Difficulty: 2
def ArrayMisty: Misty[Array] = error("todo")
// 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) => (ma andThen f)(x)(x)
def unicorn[A](a: A): X => A = Function.const(a)
}
// Exercise 14
// Relative Difficulty: 7
def EitherLeftMisty[X]: Misty[PartialType[Either.LeftProjection, X]#Flip] =
new Misty[PartialType[Either.LeftProjection, X]#Flip] {
def banana[A, B](f: A => Either.LeftProjection[B,X], ma: Either.LeftProjection[A,X]): Either.LeftProjection[B,X] =
Either.LeftProjection(ma flatMap (f andThen (_.e)))
def unicorn[A](a: A): Either.LeftProjection[A,X] = Either.LeftProjection(Left(a))
}
// Exercise 15
// Relative Difficulty: 5
def EitherRightMisty[X]: Misty[PartialType[Either.RightProjection, X]#Apply] =
new Misty[PartialType[Either.RightProjection, X]#Apply] {
def banana[A, B](f: A => Either.RightProjection[X,B], ma: Either.RightProjection[X,A]): Either.RightProjection[X,B] =
Either.RightProjection(ma flatMap (f andThen (_.e)))
def unicorn[A](a: A): Either.RightProjection[X,A] = Either.RightProjection(Right(a))
}
// Exercise 16
// Relative Difficulty: 3
def jellybean[M[_], A](ma: M[M[A]], m: Misty[M]): M[A] = m.banana[M[A],A](x => x, 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 => B, B](m.furry(_,ma), mf)
// Exercise 18
// Relative Difficulty: 6
def moppy[M[_], A, B](as: List[A], f: A => M[B], m: Misty[M]): M[List[B]] = {
as.foldRight(m.unicorn[List[B]](List())) { (a: A, ml: M[List[B]]) =>
m.banana[List[B],List[B]](lb => m.furry[B,List[B]](_ :: lb,f(a)), ml)
}
}
}
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, s: State[S,A]): State[S,B] =
State(s.f andThen { case (s,a) => (s,f(a)) } )
}
// Exercise 20
// Relative Difficulty: 10
def StateMisty[S]: Misty[PartialType[State, S]#Apply] =
new Misty[PartialType[State, S]#Apply] {
def unicorn[A](a:A): State[S,A] = State(s => (s,a))
def banana[A,B](f: A => State[S,B], sa: State[S,A]): State[S,B] =
State(sa.f andThen { case (s,a) => f(a).f(s) })
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment