-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
160 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
package sierikov.codewars.kyu1 | ||
|
||
object ScottEncoding { | ||
trait STuple[+A, +B] { | ||
def apply[C]: ((A, B) => C) => C | ||
def _1: A = apply((a, _) => a) | ||
def _2: B = apply((_, b) => b) | ||
def swap: STuple[B, A] = apply((a, b) => STupleImpl(b, a)) | ||
} | ||
|
||
trait SOption[+A] { | ||
def apply[B]: (=> B, A => B) => B | ||
} | ||
|
||
trait SEither[+A, +B] { | ||
def apply[C]: (A => C, B => C) => C | ||
} | ||
|
||
trait SList[+A] { | ||
def apply[B]: (=> B, (A, SList[A]) => B) => B | ||
} | ||
|
||
case class STupleImpl[A, B](a: A, b: B) extends STuple[A, B] { | ||
override def apply[C]: ((A, B) => C) => C = f => f(a, b) | ||
} | ||
|
||
def toTuple[A, B](tuple: STuple[A, B]): (A, B) = (tuple._1, tuple._2) | ||
|
||
def fromTuple[A, B](tuple: (A, B)): STuple[A, B] = STupleImpl(tuple._1, tuple._2) | ||
|
||
def fst[A, B](tuple: STuple[A, B]): A = tuple._1 | ||
|
||
def snd[B](tuple: STuple[_, B]): B = tuple._2 | ||
|
||
def swap[A, B](tuple: STuple[A, B]): STuple[B, A] = tuple.swap | ||
|
||
def curry[A, B, C](f: STuple[A, B] => C): A => B => C = x => y => f(fromTuple(x, y)) | ||
|
||
def uncurry[A, B, C](f: A => B => C): STuple[A, B] => C = tuple => f(fst(tuple))(snd(tuple)) | ||
|
||
def toOption[A](option: SOption[A]): Option[A] = option.apply(None, Some(_)) | ||
|
||
def fromOption[A](option: Option[A]): SOption[A] = new SOption[A] { | ||
override def apply[B]: (=> B, A => B) => B = (b, a) => option.fold(b)(a) | ||
} | ||
|
||
def isSome(option: SOption[_]): Boolean = option.apply(true, _ => false) | ||
|
||
def isNone(option: SOption[_]): Boolean = option.apply(false, _ => true) | ||
|
||
def catOptions[A](list: SList[SOption[A]]): SList[A] = ??? | ||
|
||
def toEither[A, B](either: SEither[A, B]): Either[A, B] = ??? | ||
|
||
def fromEither[A, B](either: Either[A, B]): SEither[A, B] = ??? | ||
|
||
def isLeft[A](either: SEither[A, _]): Boolean = ??? | ||
|
||
def isRight[A](either: SEither[A, _]): Boolean = ??? | ||
|
||
def nil[A]: SList[A] = ??? | ||
|
||
def toList[A](list: SList[A]): List[A] = ??? | ||
|
||
def fromList[A](list: List[A]): SList[A] = ??? | ||
|
||
def cons[A](head: A, list: SList[A]): SList[A] = ??? | ||
|
||
def concat[A](left: SList[A], right: SList[A]): SList[A] = ??? | ||
|
||
def empty(list: SList[_]): Boolean = ??? | ||
|
||
def length(list: SList[_]): Int = ??? | ||
|
||
def map[A, B](f: (A => B), list: SList[A]): SList[B] = ??? | ||
|
||
def zip[A, B](listA: SList[A], listB: SList[B]): SList[STuple[A, B]] = ??? | ||
|
||
def foldLeft[A, B](f: ((B, A) => B), z: B, list: SList[A]): B = ??? | ||
|
||
def foldRight[A, B](f: ((A, B) => B), z: B, list: SList[A]): B = ??? | ||
|
||
def take[A](n: Int, list: SList[A]): SList[A] = ??? | ||
|
||
def partition[A, B](list: SList[SEither[A, B]]): STuple[SList[A], SList[B]] = ??? | ||
} |
74 changes: 74 additions & 0 deletions
74
src/test/scala/sierikov/codewars/kyu1/ScottEncodingSpec.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
package sierikov.codewars.kyu1 | ||
|
||
import org.scalatest.flatspec.AnyFlatSpec | ||
import org.scalatest.matchers.should.Matchers | ||
|
||
class ScottEncodingSpec extends AnyFlatSpec with Matchers { | ||
|
||
import ScottEncoding._ | ||
|
||
"The Option type".can("be cast to scala Option") in { | ||
toOption(new SOption[Int] { | ||
def apply[B] = (z, _) => z | ||
}) should be(None) | ||
toOption(new SOption[Int] { | ||
def apply[B] = (_, f) => f(4) | ||
}) should be(Some(4)) | ||
} | ||
it.can("be cast from scala Option") in { | ||
fromOption[Int](None)[Int](0, _ + 1) should be(0) | ||
fromOption(Some(4))[Int](0, _ + 1) should be(5) | ||
} | ||
|
||
it.can("be predicated on its content") in { | ||
isSome(new SOption[Int] { | ||
def apply[B] = (_, f) => f(4) | ||
}) should be(true) | ||
isSome(new SOption[Int] { | ||
def apply[B] = (z, _) => z | ||
}) should be(false) | ||
} | ||
|
||
"The List type".can("be cast to scala List") in { | ||
toList(nil[Int]) should be(List()) | ||
toList(new SList[Int] { | ||
override def apply[B] = (_, f) => | ||
f(1, | ||
new SList[Int] { | ||
override def apply[B] = (_, g) => g(2, nil[Int]) | ||
} | ||
) | ||
}) should be(List(1, 2)) | ||
} | ||
it.can("be cast from scala List") in { | ||
fromList[Int](List())[Int](0, reduce) should be(0) | ||
fromList[Int](List(1, 2, 3))[Int](0, reduce) should be(321) | ||
} | ||
|
||
"The Either type".can("be cast to scala Either") in { | ||
toEither(new SEither[Int, String] { | ||
override def apply[C] = (left, _) => left(3) | ||
}) should be(Left(3)) | ||
|
||
toEither(new SEither[Int, String] { | ||
override def apply[C] = (_, right) => right("hello") | ||
}) should be(Right("hello")) | ||
} | ||
it.can("be cast from scala Either") in { | ||
fromEither[Int, String](Left(3))[String](_.toString, identity) should be("3") | ||
fromEither[Int, String](Right("hello"))[String](_.toString, identity) should be("hello") | ||
} | ||
|
||
"The tuple type".can("be cast to (,)") in { | ||
toTuple(new STuple[Int, String] { | ||
override def apply[C] = f => f(2, "hi") | ||
}) should be((2, "hi")) | ||
} | ||
it.can("be cast from (,)") in { | ||
fromTuple((2, "hi"))[List[String]](List.fill(_)(_)) should be(List("hi", "hi")) | ||
fromTuple((3, 6))[Int](_ * _) should be(18) | ||
} | ||
|
||
def reduce(i: Int, is: SList[Int]): Int = | ||
i + 10 * is[Int](0, reduce) | ||
} |