ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Cats2 Exercise
    scala/cats2 2023. 1. 22. 20:35

    https://www.geekabyte.io/2018/09/easing-into-cats-and-case-for-category.html 에 나오는 문제의 답안이 scalafiddle 사이트로 연결되지 않아 볼 수가 없다.  cats 로 내가 생각한 대로 구현해 본다. 

     

    import cats._
    import cats.data._
    import cats.syntax.all._
    
    import scala.concurrent.ExecutionContext.Implicits.global
    import scala.concurrent.duration.Duration
    import scala.concurrent.{Await, ExecutionContext, Future}
    import scala.util.{Failure, Success, Try}
    
    object ScalaApp {
      // Task 1: Merging two maps
      def task1(): Unit = {
        val m1 = Map("k1" -> List("One"), "k2" -> List("Zero"))
        val m2 = Map("k1" -> List("Two"))
    
        val m = m1 |+| m2
        println(m) // Map(k1 -> List(One, Two), k2 -> List(Zero))
      }
    
      // Task 2: Generalise merging of maps
      def task2(): Unit = {
        def mergeMaps(maps: Map[String, List[String]]*): Map[String, List[String]] = maps.combineAll
    
        val m1 = Map("k1" -> List("One"), "k2" -> List("Zero"))
        val m2 = Map("k1" -> List("Two"))
    
        val m = mergeMaps(m1, m2)
        println(m) // Map(k1 -> List(One, Two), k2 -> List(Zero))
      }
    
      // Task 3: Mapping over nested structures
      def task3(): Unit = {
        val nested: List[Try[Int]] = List(
          Success(1),
          Success(2),
          Failure(new Throwable("Not valid")),
          Success(3)
        )
    
        def mapNested(nested: List[Try[Int]]): Seq[Try[Int]] = Nested(nested).map(_ + 1).value
        val m: Seq[Try[Int]]                                 = mapNested(nested)
        println(m) // List(Success(2), Success(3), Failure(java.lang.Throwable: Not valid), Success(4))
      }
    
      // Task 4: Validate list of values (fail fast scenario)
      def task4(): Unit = {
        val listOfInts: List[Int]    = (1 to 10).toList
        val listOfAllEven: List[Int] = List(2, 4, 6, 8)
    
        // validation function
        def isEven(value: Int): Either[String, Int] =
          if (value % 2 == 0) {
            Right(value)
          } else {
            Left(s"$value is not even")
          }
    
        def validateEven(input: List[Int])(f: Int => Either[String, Int]): Either[String, List[Int]] = input.traverse(f)
    
        val r1 = validateEven(listOfInts)(isEven)
        println(r1) // Left(1 is not even)
    
        val r2 = validateEven(listOfAllEven)(isEven)
        println(r2) // Right(List(2, 4, 6, 8))
      }
    
      // Task 5: Validation of domain properties (fail slow scenario)
      def task5(): Unit = {
        case class Person(name: String, age: Int)
    
        def validateAndCreatePerson(name: String, age: Int): Either[Vector[String], Person] = {
          val nameCheck: Validated[Vector[String], String] =
            if (name.exists(_.isDigit)) Vector("Name cannot contain numbers").invalid[String]
            else name.valid[Vector[String]]
    
          val ageCheck: Validated[Vector[String], Int] =
            if (age <= 0) Vector("Age cannot be zero or less than zero").invalid[Int]
            else age.valid[Vector[String]]
    
          (nameCheck, ageCheck).mapN(Person).toEither
        }
    
        validateAndCreatePerson("John", 20)  // Right(Person(John,20))
        validateAndCreatePerson("John1", 20) // Left(Vector(Name cannot contain numbers))
        validateAndCreatePerson("John", -1)  // Left(Vector(Age cannot be zero or less than zero))
        validateAndCreatePerson(
          "John1",
          -1
        ) // Left(Vector(Name cannot contain numbers, Age cannot be zero or less than zero))
      }
    
      // Task 6: File processing
      def task6(): Unit = {
        val lines: List[String] = List(
          "A bird in the hand is worth two in the bush",
          "Left hand doesn't know what the right hand is doing",
          "Like a moth to a flame"
        )
    
        def process(lines: List[String]): (Int, Map[String, Int]) = {
          val stats: Seq[(Int, Map[String, Int])] = lines.map { line =>
            val cols = line.split(" ")
            (cols.size, cols.map(key => key -> 1).toMap)
          }
    
          stats.combineAll
        }
    
        process(
          lines
        ) // (27,HashMap(Like -> 1, in -> 1, is -> 2, what -> 1, hand -> 2, bird -> 1, doing -> 1, worth -> 1, Left -> 1, flame -> 1, doesn't -> 1, the -> 2, two -> 1, A -> 1, a -> 1, moth -> 1, to -> 1, know -> 1, bush -> 1, right -> 1))
      }
    
      // Task 7: Chaining asynchronous calls that can return or not return values
      def task7(): Unit = {
        // domain objects representing users and membership information
        case class User(id: Int)
        case class MembershipInfo(mtype: String)
    
        // stub implementation for getUser that only returns a user when called with id of 1
        def getUser(id: Int): Option[User] =
          if (id == 1) {
            Some(User(id))
          } else {
            None
          }
    
        // stub implementation of getMembershipIfo that only returns membership info when called with a user
        // with id of 1
        def getMembershipInfo(user: User): Future[Option[MembershipInfo]] =
          if (user.id == 1) {
            Future.successful(Some(MembershipInfo("Standard")))
          } else {
            Future.successful(None)
          }
    
        // makes use of both getUser and getMembershipInfo to get the membership info given a user id
        def fetchMembershipInfo(id: Int): Future[Option[MembershipInfo]] = getUser(id).flatTraverse(getMembershipInfo)
    
        // def fetchMembershipInfo(id: Int): Future[Option[MembershipInfo]] =
        //  (for {
        //    user       <- OptionT.fromOption[Future](getUser(id))
        //    membership <- OptionT(getMembershipInfo(user))
        //  } yield membership).value
    
        Await.result(fetchMembershipInfo(1), Duration.Inf) // Some(MembershipInfo(Standard))
        Await.result(fetchMembershipInfo(2), Duration.Inf) // None
      }
    
    
      // Extra task: Generalise map
      def extraTask(): Unit = {
        def genericMap[F[_]: Monad, A](fa: F[A])(f: A => A): F[A] = fa.map(f)
      }
    
      def main(args: Array[String]): Unit = {
        //    task1()
        //    task2()
        //    task3()
        //    task4()
        //    task5()
        //    task6()
        //    task7()
        extraTask()
      }
    }

    'scala > cats2' 카테고리의 다른 글

    Future Traverse  (0) 2023.02.13
    Ior  (1) 2023.01.29
    Validated  (0) 2023.01.19
    Writer  (0) 2023.01.19
    OptionT  (0) 2023.01.16

    댓글

Designed by Tistory.