package com.zibaldone.cats
package ch_04
trait Crypto[A]:
self =>
def encrypt(value: A): String
def decrypt(value: String): A
def imap[B](back: B => A)(forth: A => B): Crypto[B] = new Crypto[B]:
override def encrypt(value: B): String = self.encrypt(back(value))
override def decrypt(value: String): B = forth(self.decrypt(value))
object Crypto:
given caesarCypher: Crypto[String] = new Crypto[String]:
override def encrypt(value: String): String = value.map { c => (c + 2).toChar }
override def decrypt(value: String): String = value.map { c => (c - 2).toChar }
given doubleCypher: Crypto[Double] = caesarCypher.imap[Double](_.toString)(_.toDouble)
// ex. Option[String]
given optCaesarCypher: Crypto[Option[String]] = caesarCypher.imap[Option[String]](_.getOrElse(""))(Option(_))
extension [A: Crypto as crypto](value: A)
def encrypt: String = crypto.encrypt(value)
extension (value: String)
def decrypt[A: Crypto as crypto]: A = crypto.decrypt(value)
trait `invariant`[F[_]]:
def imap[A, B](fa: F[A])(forth: A => B)(back: B => A): F[B]