diff --git a/build.sbt b/build.sbt index 03a88d4160a1e08c6c22af9af6ff50a7951f6700..e0078963c4fbed682e0a56579191e4580115fd1c 100644 --- a/build.sbt +++ b/build.sbt @@ -21,7 +21,8 @@ scalacOptions ++= Seq( "-Ywarn-unused:params", "-Ywarn-unused:patvars", "-Ywarn-unused:privates", - "-Ypatmat-exhaust-depth", "40" + "-Ypatmat-exhaust-depth", "40", + "-language:higherKinds", ) resolvers += Resolver.sonatypeRepo("releases") diff --git a/src/main/scala/traverse/Fuse.scala b/src/main/scala/traverse/Fuse.scala new file mode 100644 index 0000000000000000000000000000000000000000..3f92ceea633403883cc7d831e2a3a3f57b5d9c5c --- /dev/null +++ b/src/main/scala/traverse/Fuse.scala @@ -0,0 +1,42 @@ +object Fuse { + /* reduced to relevant parts */ + trait Traverse[F[_]] { + def traverse[G[_]:Applicative,A,B](fa: F[A])(f: A => G[B]): G[F[B]] = + sequence(map(fa)(f)) + def sequence[G[_]:Applicative,A](fma: F[G[A]]): G[F[A]] = + traverse(fma)(ma => ma) + + def map[A,B](fa: F[A])(f: A => B): F[B] = ??? // exercise sheet + + /* Exercise: implement fusing two traversal functions in one + traversal using applicative products */ + + def fuse[G[_],H[_],A,B](fa: F[A])(f: A => G[B], g: A => H[B]) + (implicit G: Applicative[G],H: Applicative[H]) + : (G[F[B]], H[F[B]]) = ??? + } + + + /* reduced to relevant parts */ + trait Applicative[F[_]] { + def map2[A,B,C](fa: F[A], fb: F[B])(f: (A, B) => C): F[C] = + apply(map(fa)(f.curried))(fb) + + def apply[A,B](fab: F[A => B])(fa: F[A]): F[B] = + map2(fab, fa)(_(_)) + + def unit[A](a: => A): F[A] + + def map[A,B](fa: F[A])(f: A => B): F[B] = + apply(unit(f))(fa) + + def product[G[_]](G: Applicative[G]): Applicative[Lambda[x => (F[x], G[x])]] = { + val self = this + new Applicative[Lambda[x => (F[x], G[x])]]{ + def unit[A](a: => A) = (self.unit(a), G.unit(a)) + override def apply[A,B](fs: (F[A => B], G[A => B]))(p: (F[A], G[A])) = + (self.apply(fs._1)(p._1), G.apply(fs._2)(p._2)) + } + } + } +} diff --git a/src/main/scala/traverse/SequenceMap.scala b/src/main/scala/traverse/SequenceMap.scala new file mode 100644 index 0000000000000000000000000000000000000000..56577f7526e834dca485a66e7aa37b9184df4cb3 --- /dev/null +++ b/src/main/scala/traverse/SequenceMap.scala @@ -0,0 +1,28 @@ +object SequenceMap { + trait Applicative[F[_]] { + // Exercise: implement sequence for maps instead of lists + def sequenceMap[K,V](m: Map[K, F[V]]): F[Map[K,V]] = ??? + + //you can use any of these methods + def unit[A](a: => A): F[A] + + def apply[A,B](fab: F[A => B])(fa: F[A]): F[B] = map2(fab, fa)((ab, a) => ab(a)) + + def map[A,B](fa: F[A])(f: A => B): F[B] = apply(unit(f))(fa) + + def map2[A,B,C](fa: F[A], fb: F[B])(f: (A, B) => C): F[C] = + apply(apply(unit(f.curried))(fa))(fb) + + def map3[A,B,C,D](fa: F[A], fb: F[B], fc: F[C])(f: (A, B, C) => D): F[D] = + apply(apply(apply(unit(f.curried))(fa))(fb))(fc) + + def factor[A,B](fa: F[A], fb: F[B]): F[(A,B)] = + map2(fa, fb)((_,_)) + + def sequence[A](fas: List[F[A]]): F[List[A]] = + fas.foldRight[F[List[A]]](unit(Nil))((a, b) => map2(a, b)(_::_)) + + def traverse[A,B](fas: List[A])(f: A => F[B]): F[List[B]] = + fas.foldRight[F[List[B]]](unit(Nil))((a, b) => map2(f(a), b)(_::_)) + } +}