├── project └── build.properties ├── README.md ├── src ├── main │ ├── resources │ │ ├── chat.conf │ │ ├── brief │ │ │ ├── RSS.docx │ │ │ ├── Анаграммы.docx │ │ │ ├── Телеграм бот.docx │ │ │ ├── Поиск по логам.docx │ │ │ ├── Курьерская карта.docx │ │ │ ├── Онлайн лабораторные.docx │ │ │ └── Парсер отзывов о банке.docx │ │ ├── Лекции Scala для FinTech.odp │ │ ├── Лекции Scala для FinTech.pdf │ │ ├── Лекции Scala для FinTech.pptx │ │ ├── Подготовка рабочего места.pdf │ │ ├── shop │ │ │ ├── users.json │ │ │ └── products.json │ │ ├── game.conf │ │ ├── logback.xml │ │ ├── application.conf │ │ └── программа обучения.txt │ └── scala │ │ ├── java2scala │ │ ├── Lecture5.scala │ │ ├── NotALecture.scala │ │ ├── tagless │ │ │ ├── package.scala │ │ │ ├── Filter.scala │ │ │ ├── FilterTF.scala │ │ │ └── FromProduct.scala │ │ ├── shop │ │ │ ├── package.scala │ │ │ ├── Key.scala │ │ │ ├── Greeting.scala │ │ │ ├── actors │ │ │ │ └── Greeter.scala │ │ │ ├── http │ │ │ │ ├── resourceHttp.scala │ │ │ │ └── package.scala │ │ │ ├── SimpleStore.scala │ │ │ ├── Shop.scala │ │ │ ├── ProductStore.scala │ │ │ ├── CartStore.scala │ │ │ └── domain.scala │ │ ├── homeworks │ │ │ ├── funcs │ │ │ │ ├── Three.scala │ │ │ │ ├── ChurchTuple.scala │ │ │ │ ├── ChurchBool.scala │ │ │ │ ├── Equivalent.scala │ │ │ │ ├── FiniteEquivalences.scala │ │ │ │ └── ChurchList.scala │ │ │ ├── DesugarFor.scala │ │ │ ├── StreamThings.scala │ │ │ ├── MapOperations.scala │ │ │ ├── LinkedMap.scala │ │ │ └── CharAutomata.scala │ │ ├── Lecture10.scala │ │ ├── Lecture1.scala │ │ ├── Lecture7.scala │ │ ├── Lecture2.scala │ │ ├── Lecture3.scala │ │ ├── lecture5.sc │ │ ├── Lecture8.scala │ │ ├── Lecture11.scala │ │ ├── Lecture9.scala │ │ ├── Lecture6.scala │ │ └── Lecture4.scala │ │ └── lectures │ │ ├── collections │ │ ├── MergeSortImpl.scala │ │ ├── MyListImpl.scala │ │ ├── OptionVsNPE.scala │ │ ├── comprehension │ │ │ └── Couriers.scala │ │ └── CherryTree.scala │ │ ├── types │ │ ├── TypeInference.scala │ │ └── FixCompile.scala │ │ ├── oop │ │ ├── Scopes.scala │ │ ├── Inheritence.scala │ │ ├── types │ │ │ ├── GeneralBST.scala │ │ │ └── Binder.scala │ │ ├── lineization.scala │ │ ├── Application.scala │ │ ├── Fisherman.scala │ │ └── BST.scala │ │ ├── concurrent │ │ ├── akka │ │ │ ├── domain.scala │ │ │ ├── AkkaExample.scala │ │ │ ├── AkkaPinPongExample.scala │ │ │ ├── SupervisorActor.scala │ │ │ └── Worker.scala │ │ ├── PromiseExample.scala │ │ └── Smooth.scala │ │ ├── akka │ │ └── chat │ │ │ ├── In.scala │ │ │ ├── Out.scala │ │ │ ├── Chat.scala │ │ │ ├── Hub.scala │ │ │ ├── Session.scala │ │ │ └── ChatServer.scala │ │ ├── functions │ │ ├── recursion.scala │ │ ├── Fibonacci.scala │ │ ├── Authentication.scala │ │ ├── SQLAPI.scala │ │ ├── Computations.scala │ │ └── AuthenticationDomain.scala │ │ ├── eval │ │ └── LazyScheduler.scala │ │ ├── operators │ │ ├── Competition.scala │ │ └── EvaluateOptimization.scala │ │ ├── features │ │ └── ApplyAndUnapplyExample.scala │ │ └── matching │ │ └── SortingStuff.scala └── test │ └── scala │ ├── lectures │ ├── Utils.scala │ ├── functions │ │ ├── LazyVals.scala │ │ └── AuthenticationTest.scala │ ├── types │ │ └── FixCompile.scala │ ├── oop │ │ ├── ApplicationTest.scala │ │ └── BSTTestWithMocks.scala │ ├── concurrent │ │ └── akka │ │ │ ├── TestActorSystem.scala │ │ │ ├── PingPongIntegrationTest.scala │ │ │ ├── SupervisorUnitTest.scala │ │ │ └── WorkerUnitTest.scala │ ├── collections │ │ ├── MergeSortImplFlatSpecTest.scala │ │ ├── MergeSortImpFunSuiteTest.scala │ │ ├── CherryTreeSuite.scala │ │ └── MergeSortImplWordSpecTest.scala │ ├── eval │ │ └── LazySchedulerTest.scala │ ├── check │ │ └── TableStyleScalaCheckTest.scala │ └── matching │ │ └── SortingStuffGeneratorBasedTest.scala │ ├── inclasss │ ├── Circe.scala │ ├── Futures.scala │ ├── Streams.scala │ └── AkkaTypedHello.scala │ └── java2scala │ └── homeworks │ ├── funcs │ ├── package.scala │ ├── FiniteEquivalencesSuite.scala │ └── ChurchSuite.scala │ ├── LinkedMapSpec.scala │ ├── MapOperationsSuite.scala │ └── CharAutomataSuite.scala ├── .scalafmt.conf └── .gitignore /project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=1.2.3 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # scala-school 2 | scala courses for Fintech 3 | -------------------------------------------------------------------------------- /src/main/resources/chat.conf: -------------------------------------------------------------------------------- 1 | akka.http { 2 | server { 3 | idle-timeout = infinite 4 | } 5 | } -------------------------------------------------------------------------------- /.scalafmt.conf: -------------------------------------------------------------------------------- 1 | binPack.parentConstructors = true 2 | maxColumn = 128 3 | includeCurlyBraceInSelectChains = false 4 | align = most -------------------------------------------------------------------------------- /src/main/resources/brief/RSS.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Odomontois/scala-school/HEAD/src/main/resources/brief/RSS.docx -------------------------------------------------------------------------------- /src/main/scala/java2scala/Lecture5.scala: -------------------------------------------------------------------------------- 1 | package java2scala 2 | 3 | object Lecture5 { 4 | List(1, 2, 3, 4, 5, 6) 5 | } 6 | -------------------------------------------------------------------------------- /src/main/resources/brief/Анаграммы.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Odomontois/scala-school/HEAD/src/main/resources/brief/Анаграммы.docx -------------------------------------------------------------------------------- /src/main/resources/brief/Телеграм бот.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Odomontois/scala-school/HEAD/src/main/resources/brief/Телеграм бот.docx -------------------------------------------------------------------------------- /src/main/resources/brief/Поиск по логам.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Odomontois/scala-school/HEAD/src/main/resources/brief/Поиск по логам.docx -------------------------------------------------------------------------------- /src/main/resources/brief/Курьерская карта.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Odomontois/scala-school/HEAD/src/main/resources/brief/Курьерская карта.docx -------------------------------------------------------------------------------- /src/main/resources/Лекции Scala для FinTech.odp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Odomontois/scala-school/HEAD/src/main/resources/Лекции Scala для FinTech.odp -------------------------------------------------------------------------------- /src/main/resources/Лекции Scala для FinTech.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Odomontois/scala-school/HEAD/src/main/resources/Лекции Scala для FinTech.pdf -------------------------------------------------------------------------------- /src/main/resources/brief/Онлайн лабораторные.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Odomontois/scala-school/HEAD/src/main/resources/brief/Онлайн лабораторные.docx -------------------------------------------------------------------------------- /src/main/resources/Лекции Scala для FinTech.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Odomontois/scala-school/HEAD/src/main/resources/Лекции Scala для FinTech.pptx -------------------------------------------------------------------------------- /src/main/resources/Подготовка рабочего места.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Odomontois/scala-school/HEAD/src/main/resources/Подготовка рабочего места.pdf -------------------------------------------------------------------------------- /src/main/resources/brief/Парсер отзывов о банке.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Odomontois/scala-school/HEAD/src/main/resources/brief/Парсер отзывов о банке.docx -------------------------------------------------------------------------------- /src/main/scala/java2scala/NotALecture.scala: -------------------------------------------------------------------------------- 1 | package java2scala 2 | 3 | object NotALecture { 4 | import Lecture3.Color 5 | 6 | // case object Black extends Color 7 | } 8 | -------------------------------------------------------------------------------- /src/main/scala/java2scala/tagless/package.scala: -------------------------------------------------------------------------------- 1 | package java2scala 2 | 3 | package object tagless { 4 | type ProdF[A] = Product => A 5 | type ShowF[A] = String 6 | } 7 | -------------------------------------------------------------------------------- /src/test/scala/lectures/Utils.scala: -------------------------------------------------------------------------------- 1 | package lectures 2 | 3 | object Utils { 4 | def shuffle(seq: Seq[Int]): Seq[Int] = 5 | scala.util.Random.shuffle(seq) 6 | } 7 | 8 | -------------------------------------------------------------------------------- /src/main/scala/java2scala/shop/package.scala: -------------------------------------------------------------------------------- 1 | package java2scala 2 | 3 | package object shop { 4 | type CancelAction = () => Unit 5 | type CancelCont[A] = (A => Unit) => CancelAction 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/shop/users.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "db62f60e-5adb-11e9-8063-bbb5544e54e2", 4 | "name": "odo" 5 | }, 6 | { 7 | "id": "a11f59d6-6064-11e9-aaa0-0bf5385b841d", 8 | "name": "kate" 9 | } 10 | ] -------------------------------------------------------------------------------- /src/main/scala/java2scala/homeworks/funcs/Three.scala: -------------------------------------------------------------------------------- 1 | package java2scala.homeworks.funcs 2 | 3 | /** simple type with three elements */ 4 | sealed trait Three 5 | 6 | object Three{ 7 | case object First extends Three 8 | case object Second extends Three 9 | case object Third extends Three 10 | } 11 | -------------------------------------------------------------------------------- /src/test/scala/inclasss/Circe.scala: -------------------------------------------------------------------------------- 1 | package inclasss 2 | 3 | import lectures.akka.chat._ 4 | import io.circe.syntax._ 5 | 6 | object Circe extends App { 7 | println(Map[String, In]( 8 | "a" -> In.Create("foooasdasd asd"), 9 | "b" -> In.Send("1231 sdfds !!!"), 10 | "c" -> In.Enter("lolo", "uuu") 11 | ).asJson) 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/resources/game.conf: -------------------------------------------------------------------------------- 1 | game_conf { 2 | ping_delay: 10 //– задержка между пингами 3 | break_delay: 30//– задержка между поломками 4 | ping_for_pong: 10 //– количество “пингов”, необходимых для “понга” 5 | pong_switch: 10//– количесво “pong” после которого акторы меняются местами 6 | set_count: 10 //- количество “сетов” после которого игра заканчивается 7 | } -------------------------------------------------------------------------------- /src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | %-4relative /%d/ [%thread] %-5level %logger{35} - %msg %n 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/main/scala/lectures/collections/MergeSortImpl.scala: -------------------------------------------------------------------------------- 1 | package lectures.collections 2 | 3 | /** 4 | * Постарайтесь не использовать мутабильные коллекции и var 5 | * Подробнее о сортировке можно подсмотреть здесь - https://en.wikipedia.org/wiki/Merge_sort 6 | * 7 | * 8 | */ 9 | object MergeSortImpl extends App { 10 | 11 | def mergeSort(data: Seq[Int]): Seq[Int] = data 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/test/scala/lectures/functions/LazyVals.scala: -------------------------------------------------------------------------------- 1 | package lectures.functions 2 | 3 | class ServiceA(c: =>ServiceC) { 4 | def getC = c 5 | } 6 | 7 | class ServiceC(val a: ServiceA) 8 | 9 | object LazyVals extends App { 10 | 11 | val a: ServiceA = new ServiceA(c) 12 | val c: ServiceC = new ServiceC(a) 13 | 14 | println(a.getC) 15 | 16 | assert(a.getC == c) 17 | a.getC == c 18 | } 19 | -------------------------------------------------------------------------------- /src/main/scala/java2scala/homeworks/DesugarFor.scala: -------------------------------------------------------------------------------- 1 | package java2scala.homeworks 2 | import scala.reflect.runtime._ 3 | import scala.tools.reflect._ 4 | 5 | object DesugarFor extends App{ 6 | val toolbox = currentMirror.mkToolBox() 7 | 8 | val tree = toolbox.parse( 9 | """ 10 | |for((x, i) <- xs.zipWithIndex) yield x + i 11 | """.stripMargin 12 | ) 13 | 14 | println(tree) 15 | } 16 | -------------------------------------------------------------------------------- /src/main/scala/lectures/types/TypeInference.scala: -------------------------------------------------------------------------------- 1 | package lectures.types 2 | 3 | /** 4 | * Не запуская приложения, предположите, чему будет равен 'result'. 5 | * Почему? 6 | * 7 | */ 8 | object TypeInference extends App { 9 | 10 | def printSomething() = "2 плюс 3 - это " 11 | 12 | def calculateSomething() = 1 + 1 13 | 14 | def result = printSomething + 3 + calculateSomething 15 | 16 | print(result) 17 | 18 | } 19 | 20 | -------------------------------------------------------------------------------- /src/main/scala/java2scala/homeworks/funcs/ChurchTuple.scala: -------------------------------------------------------------------------------- 1 | package java2scala.homeworks.funcs 2 | 3 | trait ChurchTuple[A, B] { 4 | def unpack[C](f: A => B => C): C 5 | 6 | def first: A = ??? 7 | def second: B = ??? 8 | 9 | def mapFirst[C](f: A => C): ChurchTuple[C, B] = ??? 10 | def mapSecond[C](f: B => C): ChurchTuple[A, C] = ??? 11 | } 12 | 13 | object ChurchTuple { 14 | def apply[A, B](x: A, y: B): ChurchTuple[A, B] = ??? 15 | } 16 | -------------------------------------------------------------------------------- /src/main/scala/java2scala/shop/Key.scala: -------------------------------------------------------------------------------- 1 | package java2scala.shop 2 | import java.util.UUID 3 | 4 | trait Key[A] { 5 | def key(a: A): UUID 6 | def notFound(uuid: UUID): Throwable 7 | def multiple(uuid: UUID): Throwable 8 | } 9 | 10 | object Key { 11 | def notFound[A](uuid: UUID)(implicit key: Key[A]): Throwable = key.notFound(uuid) 12 | def multiple[A](uuid: UUID)(implicit key: Key[A]): Throwable = key.multiple(uuid) 13 | def key[A](a: A)(implicit key: Key[A]): UUID = key.key(a) 14 | } 15 | -------------------------------------------------------------------------------- /src/main/scala/java2scala/homeworks/funcs/ChurchBool.scala: -------------------------------------------------------------------------------- 1 | package java2scala.homeworks.funcs 2 | 3 | trait ChurchBool { 4 | def cif[A](ifTrue: => A)(ifFalse: => A): A 5 | 6 | def toBool: Boolean = ??? 7 | 8 | def unary_! : ChurchBool = ??? 9 | def &&(that: ChurchBool): ChurchBool = ??? 10 | def ||(that: ChurchBool): ChurchBool = ??? 11 | } 12 | 13 | object ChurchBool { 14 | def apply(x: Boolean): ChurchBool = ??? 15 | 16 | val True: ChurchBool = ??? 17 | val False: ChurchBool = ??? 18 | } 19 | -------------------------------------------------------------------------------- /src/main/scala/java2scala/homeworks/funcs/Equivalent.scala: -------------------------------------------------------------------------------- 1 | package java2scala.homeworks.funcs 2 | 3 | /** известен также как "изоморфизм" 4 | * должен удовлетворять законам 5 | * from(to(a : A)) == a 6 | * to(from(b : B)) == b 7 | */ 8 | trait Equivalent[A, B] { 9 | def to(a: A): B 10 | def from(b: B): A 11 | } 12 | 13 | object Equivalent { 14 | def apply[A, B](fto: A => B)(ffrom: B => A): Equivalent[A, B] = new Equivalent[A, B] { 15 | def to(a: A): B = fto(a) 16 | def from(b: B): A = ffrom(b) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/scala/java2scala/homeworks/funcs/FiniteEquivalences.scala: -------------------------------------------------------------------------------- 1 | package java2scala.homeworks.funcs 2 | 3 | object FiniteEquivalences { 4 | val boolToThree: Equivalent[Boolean => Three, (Three, Three)] = ??? 5 | val threeToBool: Equivalent[Three => Boolean, (Boolean, Boolean, Boolean)] = ??? 6 | 7 | val boolToBoolToBool: Equivalent[Boolean => Boolean => Boolean, (Boolean => Boolean) => Boolean] = ??? 8 | 9 | val threeToUnit: Equivalent[Three => Unit, Unit] = ??? 10 | val unitToThree: Equivalent[Unit => Three, Three] = ??? 11 | } 12 | -------------------------------------------------------------------------------- /src/main/scala/lectures/oop/Scopes.scala: -------------------------------------------------------------------------------- 1 | package lectures.oop 2 | 3 | object Hobbit { 4 | def destroyStuff(hobbit:Hobbit) = hobbit.otherStuff 5 | // def destroyTheRing(hobbit:Hobbit) = hobbit.precious 6 | } 7 | class Hobbit { 8 | private val otherStuff: String = "" 9 | private[this] val precious: String = "the Ring" 10 | 11 | private def showSomeStuff() = otherStuff 12 | 13 | private[this] def lookAtPrecious() = { 14 | } 15 | 16 | def visit(bilbo: Hobbit) = { 17 | bilbo.showSomeStuff() 18 | // bilbo.lookAtPrecious() 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/test/scala/lectures/types/FixCompile.scala: -------------------------------------------------------------------------------- 1 | object DecomposeCountOnes extends App{ 2 | def fixByName(step: (=> (BigInt, Long) => Long) => ((BigInt, Long) => Long)): (BigInt, Long) => Long = 3 | step(fixByName(step)) 4 | /* 5 | def countOnes(num: BigInt, count: Long): Long = 6 | if (num == 0) count 7 | else countOnes(num / 2, if (num % 2 == 0) count else count + 1) 8 | */ 9 | println(fixByName( recur => (num, count) => 10 | if (num == 1) count 11 | else recur(num/2, if (num % 2 == 0) count else count + 1))(27, 0)) 12 | } 13 | -------------------------------------------------------------------------------- /src/main/scala/lectures/oop/Inheritence.scala: -------------------------------------------------------------------------------- 1 | package lectures.oop 2 | 3 | object SuperObject {} 4 | trait SuperTrait {} 5 | class SuperClass { 6 | val name = "SuperClass" 7 | protected val secretName = "secret" 8 | } 9 | class SubClass extends SuperClass { 10 | def printMySecretName = secretName 11 | } 12 | class SubClassWithTrait extends SuperTrait {} 13 | //you can't extends object 14 | //class SubClassByObject extends SuperObject{} 15 | // 16 | class TestApp extends App { 17 | val sc = new SubClass() 18 | sc.name 19 | // sc.secretName 20 | sc.printMySecretName 21 | } 22 | 23 | -------------------------------------------------------------------------------- /src/test/scala/lectures/oop/ApplicationTest.scala: -------------------------------------------------------------------------------- 1 | package lectures.oop 2 | 3 | import org.scalatest.WordSpec 4 | 5 | /** 6 | * Раскомментируйте и допишите тесты на 7 | * класс lectures.oop.Application 8 | */ 9 | class ApplicationTest extends WordSpec { 10 | 11 | private val started = new AfterWord("started") 12 | 13 | "Application" should { 14 | "return correct answer" when started{ 15 | "in a test environment" in { 16 | //??? shouldBe 5 17 | } 18 | "in a production environment" in { 19 | // ??? shouldBe 2 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/resources/application.conf: -------------------------------------------------------------------------------- 1 | akka { 2 | 3 | name = "fintech" 4 | 5 | loggers = ["akka.event.slf4j.Slf4jLogger"] 6 | loglevel = "INFO" 7 | logging-filter = "akka.event.slf4j.Slf4jLoggingFilter" 8 | log-config-on-start = "on" 9 | 10 | actor { 11 | provider = "akka.remote.RemoteActorRefProvider" 12 | debug { 13 | receive = on 14 | lifecycle = on 15 | event-stream = on 16 | } 17 | } 18 | 19 | remote { 20 | enabled-transports = ["akka.remote.netty.tcp"] 21 | netty.tcp { 22 | hostname = "127.0.0.1" 23 | port = 2552 24 | } 25 | } 26 | } 27 | 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | /test-output 3 | /out 4 | /http/target 5 | /sms/target 6 | 7 | # jira plugin 8 | /atlassian-ide-plugin.xml 9 | 10 | # Intellij Idea 11 | *.iml 12 | .idea/** 13 | .idea 14 | !/.idea/copyright/ 15 | !/.idea/inspectionProfiles/ 16 | !/.idea/runConfigurations/ 17 | !/.idea/scopes/ 18 | !/.idea/codeStyleSettings.xml 19 | !/.idea/dataSources.ids 20 | !/.idea/dataSources.xml 21 | !/.idea/encodings.xml 22 | !/.idea/highlighting.xml 23 | !/.idea/vcs.xml 24 | /.idea_modules 25 | **/project/target 26 | **/project/project/target 27 | 28 | # WorkSheet files 29 | 30 | # test logs 31 | /catalina.home_IS_UNDEFINED 32 | -------------------------------------------------------------------------------- /src/main/scala/lectures/types/FixCompile.scala: -------------------------------------------------------------------------------- 1 | package lectures.types 2 | 3 | /** 4 | * Программа должна удвоить все нечетные члены List и потом просуммировать, 5 | * сохранив результат в 'result' 6 | * 7 | * Ваша задача: 8 | * * Раскоментируйте код 9 | * * Исправьте тело метода mapper так, чтобы программа скомпилировалась 10 | */ 11 | object FixCompile extends App { 12 | 13 | // val mapper = (i: String) => if (i % 2 != 0) i * 2 14 | // 15 | // val result = List(1, 2, 3, 4, 5, 6, 7, 8, 9).map { 16 | // mapper 17 | // }.foldLeft(0) { (acc, v) => acc + v } 18 | // 19 | // print(result) 20 | } 21 | 22 | -------------------------------------------------------------------------------- /src/test/scala/lectures/functions/AuthenticationTest.scala: -------------------------------------------------------------------------------- 1 | package lectures.functions 2 | 3 | import org.scalatest.WordSpec 4 | 5 | /** 6 | * Авторизация - это очень важно, поэтому нам необходимо покрыть тестами ответсвенный за нее код 7 | * (lectures.functions.Authentication) 8 | * 9 | * Для этого 10 | * * * * уберите extends App у Authentication 11 | * * * * замените AuthenticationData.testUsers соответствующими генераторами 12 | * * * * напишите 13 | * * * * * 2 теста на authByCard 14 | * * * * * 2 теста на authByLP 15 | * * * * * 1 тест на их композицию 16 | * 17 | */ 18 | class AuthenticationTest extends WordSpec { 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/scala/lectures/concurrent/akka/domain.scala: -------------------------------------------------------------------------------- 1 | package lectures.concurrent.akka 2 | 3 | import akka.actor.ActorRef 4 | 5 | /** 6 | * Domain for Ping Pong game 7 | */ 8 | case object Ping 9 | 10 | case object Pong 11 | 12 | case object WorkerStatusTest 13 | 14 | case object StartTheGame 15 | 16 | case object GameFinished 17 | 18 | case class BecomePing(ponger: ActorRef) 19 | 20 | case class WorkerStatus(isPinger: Boolean) 21 | 22 | case class BecomePong() 23 | 24 | case class SetFinished(ponger: ActorRef, self: ActorRef) 25 | 26 | case class PongerFailure(msg: String) 27 | 28 | class PongerFailureException(message: String) extends Exception(message) -------------------------------------------------------------------------------- /src/test/scala/lectures/concurrent/akka/TestActorSystem.scala: -------------------------------------------------------------------------------- 1 | package lectures.concurrent.akka 2 | 3 | import akka.actor.{Actor, ActorSystem, Terminated} 4 | import akka.testkit.{TestKit, TestKitBase} 5 | import org.scalatest.{BeforeAndAfterAll, Suite} 6 | 7 | object TerminationWatcher { 8 | } 9 | 10 | class TerminationWatcher extends Actor { 11 | 12 | override def receive: Receive = { 13 | case t: Terminated => context.parent ! t 14 | } 15 | } 16 | 17 | trait TestActorSystem extends TestKitBase with BeforeAndAfterAll { this: Suite => 18 | 19 | implicit lazy val system = ActorSystem(getClass.getSimpleName) 20 | 21 | override def afterAll() { 22 | super.afterAll() 23 | TestKit.shutdownActorSystem(system) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/scala/lectures/concurrent/PromiseExample.scala: -------------------------------------------------------------------------------- 1 | package lectures.concurrent 2 | 3 | import scala.concurrent.duration.Duration 4 | import scala.concurrent.{Await, Promise} 5 | import scala.util.Success 6 | 7 | object PromiseExample extends App { 8 | 9 | val p = Promise[Int]() 10 | val f = p.future 11 | 12 | var doJob = true 13 | // Imitation of endless async process 14 | val runnable = new Runnable { 15 | override def run(): Unit = { 16 | var i = 0 17 | while (doJob) { 18 | i = i + 1 19 | Thread.sleep(100) 20 | if (i > 100) p.tryComplete(Success(i)) //p.complete(Success(i)) 21 | } 22 | } 23 | } 24 | 25 | val tr = new Thread(runnable) 26 | tr.start() 27 | val r = Await.ready(f, Duration.Inf) 28 | println("RESULT IS" + r) 29 | doJob = false 30 | } 31 | -------------------------------------------------------------------------------- /src/main/scala/lectures/akka/chat/In.scala: -------------------------------------------------------------------------------- 1 | package lectures.akka.chat 2 | 3 | import io.circe.{Decoder, Encoder} 4 | import io.circe.generic.JsonCodec 5 | import io.circe.generic.extras.semiauto._ 6 | 7 | 8 | sealed trait In 9 | 10 | object In { 11 | @JsonCodec 12 | final case class Channels() extends In 13 | 14 | @JsonCodec 15 | final case class Enter(login: String, chat: String) extends In 16 | 17 | @JsonCodec 18 | final case class Create(chat: String) extends In 19 | 20 | @JsonCodec 21 | final case class Send(text: String) extends In 22 | 23 | implicit val circeConfig = io.circe.generic.extras.Configuration.default 24 | .withDiscriminator("type") 25 | .withSnakeCaseConstructorNames 26 | 27 | implicit val decoder: Decoder[In] = deriveDecoder 28 | implicit val encoder: Encoder[In] = deriveEncoder 29 | } 30 | -------------------------------------------------------------------------------- /src/main/scala/java2scala/Lecture10.scala: -------------------------------------------------------------------------------- 1 | package java2scala 2 | 3 | import Numeric.Implicits._ 4 | object Lecture10 extends App { 5 | def one[N](implicit N: Numeric[N]): N = N.one 6 | 7 | def fibonacci[N: Numeric]: Stream[N] = { 8 | lazy val res: Stream[N] = one #:: one #:: res.zip(res.tail).map { case (x, y) => x + y } 9 | res 10 | } 11 | 12 | println(fibonacci[Int].take(1000).force) 13 | println(fibonacci[BigInt].take(1000).force) 14 | 15 | final class Wrapped(val int: Int) { 16 | def bar = int - 1 17 | } 18 | 19 | implicit def wrap1[A](a: A)(implicit conv: A => Int): Wrapped = new Wrapped(conv(a)) 20 | 21 | final class Wrapped2(w: Wrapped) { 22 | def foo = w.int + 1 23 | } 24 | 25 | implicit def wrap2[A](a: A)(implicit conv: A => Wrapped): Wrapped2 = new Wrapped2(conv(a)) 26 | 27 | 28 | 1.bar 29 | 30 | 2.foo 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/scala/lectures/akka/chat/Out.scala: -------------------------------------------------------------------------------- 1 | package lectures.akka.chat 2 | 3 | import io.circe.{Decoder, Encoder} 4 | import io.circe.generic.JsonCodec 5 | import io.circe.generic.extras.semiauto.deriveEncoder 6 | 7 | sealed trait Out 8 | 9 | object Out { 10 | @JsonCodec 11 | final case class ChatRoomList(names: List[String]) extends Out 12 | 13 | @JsonCodec 14 | final case class NewPersonEntered(name: String) extends Out 15 | 16 | @JsonCodec 17 | final case class MessageSent(login: String, message: String) extends Out 18 | 19 | @JsonCodec 20 | final case class Connected(chat: String) extends Out 21 | 22 | implicit val circeConfig = io.circe.generic.extras.Configuration.default 23 | .withDiscriminator("type") 24 | .withSnakeCaseConstructorNames 25 | 26 | implicit val encoder: Encoder[Out] = deriveEncoder 27 | } 28 | -------------------------------------------------------------------------------- /src/main/scala/lectures/concurrent/Smooth.scala: -------------------------------------------------------------------------------- 1 | package lectures.concurrent 2 | 3 | import scala.concurrent.Future 4 | 5 | /** 6 | * Smooth - это своебразный функциональный кэш, предназначенный для исключения повторных вызовов кода 7 | * до того, как получен результат первого вызова. 8 | * Он работает следующим образом: 9 | * * * * в объект Smooth в метод apply передается код, который может выполняться какое-то время, и возвращает какое-то значение 10 | * * * * apply создаст инстанс Smooth 11 | * * * * созданный инстанс при вызове apply возвращает Future 12 | * * * * * и запускает код, если код еще не запущен 13 | * * * * * и не запускает код, если код еще не завершился с момента предыдущего запуска 14 | * 15 | * Подсказка: можно использовать AtomicReference 16 | * 17 | */ 18 | object Smooth{ 19 | //def apply(thunk: =>): Smooth = ??? 20 | } 21 | 22 | class Smooth { 23 | def apply(): Future[_] = ??? 24 | } 25 | -------------------------------------------------------------------------------- /src/test/scala/java2scala/homeworks/funcs/package.scala: -------------------------------------------------------------------------------- 1 | package java2scala.homeworks 2 | import java2scala.homeworks.funcs.Three.{First, Second, Third} 3 | import org.scalacheck.{Arbitrary, Cogen, Gen} 4 | import org.scalactic.Equality 5 | 6 | package object funcs { 7 | private val threeCogenF: Three => Long = { 8 | case First => 1L 9 | case Second => 2L 10 | case Third => 3L 11 | } 12 | 13 | implicit val arbitraryThree: Arbitrary[Three] = Arbitrary(Gen.oneOf(First, Second, Third)) 14 | implicit val cogenThree: Cogen[Three] = Cogen(threeCogenF) 15 | 16 | implicit def arbitraryChurchList[A: Arbitrary]: Arbitrary[ChurchList[A]] = 17 | Arbitrary(Arbitrary.arbitrary[List[A]].map(ChurchList(_: _*))) 18 | 19 | implicit def equalityChurchList[A]: Equality[ChurchList[A]] = { 20 | case (a, b: ChurchList[A @unchecked]) => a.toList == b.toList 21 | case _ => false 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/scala/java2scala/homeworks/StreamThings.scala: -------------------------------------------------------------------------------- 1 | package java2scala.homeworks 2 | 3 | object StreamThings { 4 | 5 | /** простые числа - имеющие ровно два делителя, себя и 1. Числа 2,3,5,7,11... 6 | * необходимо реализовать с помощью `isPrime`*/ 7 | val primes: Stream[Long] = ??? 8 | 9 | /** проверка на простоту числа - нужно сделать с помощью `primes` */ 10 | def isPrime(n: Long): Boolean = ??? 11 | 12 | /** последовательность Коллатца для выбранного числа 13 | * C(0) = n, 14 | * C(i + 1) = С(i) / 2 если С(i_ - чётное 15 | * С(i + 1) = 3 * С(i) + 1 если С(i) - нечётное*/ 16 | def collatz(n: Long): Stream[Long] = ??? 17 | 18 | /** числа фибоначчи F(0) = F(1) = 1, F(n + 2) = F(n + 1) + F(n) */ 19 | val fibonacci: Stream[Long] = 1L #:: 1L #:: (??? : Stream[Long]) 20 | 21 | /** построить бесконечный цикл из конечного числа элементов, используя O(`as.length`) памяти */ 22 | def cycle[A](as: A*): Stream[A] = ??? 23 | } 24 | -------------------------------------------------------------------------------- /src/main/scala/lectures/functions/recursion.scala: -------------------------------------------------------------------------------- 1 | package lectures.functions 2 | 3 | object recursion extends App { 4 | def collatzSteps(x: BigInt, steps: Long = 0): Long = 5 | if (x == 1) steps 6 | else collatzSteps(if (x % 2 == 0) x / 2 else 3 * x + 1, steps + 1) 7 | 8 | def collatzSeq(x: BigInt, seq: Seq[BigInt] = Vector.empty): Seq[BigInt] = 9 | if (x == 1) seq 10 | else collatzSeq(if (x % 2 == 0) x / 2 else 3 * x + 1, seq :+ x) 11 | 12 | 13 | def fixByVal(step: ((BigInt, Long) => Long) => ((BigInt, Long) => Long)): (BigInt, Long) => Long = 14 | step(fixByVal(step)) 15 | 16 | def fixByName(step: (=> (BigInt, Long) => Long) => ((BigInt, Long) => Long)): (BigInt, Long) => Long = 17 | step(fixByName(step)) 18 | 19 | 20 | def countOnesFixed = fixByName(recursive => (num, count) => 21 | if (num == 0) count 22 | else recursive(num / 2, if (num % 2 == 0) count else count + 1) 23 | ) 24 | 25 | println(countOnesFixed(41424, 12)) 26 | } 27 | -------------------------------------------------------------------------------- /src/main/scala/java2scala/shop/Greeting.scala: -------------------------------------------------------------------------------- 1 | package java2scala.shop 2 | 3 | import akka.actor.{ActorRef, ActorSystem} 4 | import cats.effect.{ContextShift, IO} 5 | import java2scala.shop.actors.Greeter 6 | 7 | import scala.concurrent.duration.FiniteDuration 8 | 9 | final class Greeting(actor: ActorRef) { 10 | def greet(name: String, duration: FiniteDuration)(implicit cs: ContextShift[IO]): IO[String] = 11 | for { 12 | cont <- IO.async[CancelCont[String]] { k => 13 | actor ! Greeter.Message( 14 | name, 15 | cont => k(Right(cont)), 16 | duration, 17 | ) 18 | } 19 | res <- IO.cancelable[String] { k => 20 | val f = cont(s => k(Right(s))) 21 | IO(f()) 22 | } 23 | } yield res 24 | 25 | } 26 | 27 | object Greeting { 28 | def greeting(system: ActorSystem): IO[Greeting] = 29 | for (ref <- IO(system.actorOf(Greeter.props))) yield new Greeting(ref) 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/scala/java2scala/shop/actors/Greeter.scala: -------------------------------------------------------------------------------- 1 | package java2scala.shop 2 | package actors 3 | 4 | import akka.actor.{Actor, Props} 5 | import java2scala.shop.actors.Greeter.{Message, Respond} 6 | 7 | import scala.concurrent.duration.FiniteDuration 8 | 9 | class Greeter extends Actor { 10 | def receive: Receive = { 11 | case Message(name, continue, dur) => 12 | implicit val ec = context.system.dispatcher 13 | 14 | continue { ack => 15 | val task = context.system.scheduler.scheduleOnce(dur, self, Respond(name, ack)) 16 | () => { 17 | println(s"canceling $name") 18 | task.cancel() 19 | } 20 | } 21 | case Respond(name, ack) => 22 | println(s"responding $name") 23 | ack(s"Hello, $name!") 24 | } 25 | } 26 | 27 | object Greeter{ 28 | 29 | case class Message(name: String, continue: CancelCont[String] => Unit, dur: FiniteDuration) 30 | case class Respond(name: String, ack: String => Unit) 31 | 32 | def props: Props = Props[Greeter] 33 | } 34 | -------------------------------------------------------------------------------- /src/main/scala/java2scala/Lecture1.scala: -------------------------------------------------------------------------------- 1 | package java2scala 2 | import scala.annotation.tailrec 3 | 4 | object Greeting { 5 | println("Hello from other world") 6 | val greeting = "Aloha" 7 | } 8 | 9 | object Lecture1 { 10 | 11 | def emptyString = { 12 | println("here your empty string, dude") 13 | "" 14 | } 15 | 16 | // java.util.Collections.nCopies() 17 | 18 | @tailrec def repeat(word: String = "lol", rep: Int, acc: String = emptyString): String = { 19 | print(rep) 20 | if (rep == 0) acc 21 | else 22 | repeat( 23 | word, 24 | acc = word + acc, 25 | rep = rep - 1, 26 | ) 27 | } 28 | 29 | def greeting(name: String, rep: Int) = 30 | s"Aloha, ${repeat(rep = rep)} " 31 | 32 | def name = { 33 | println("calculating name") 34 | "Oleg" 35 | } 36 | 37 | def main(args: Array[String]): Unit = { 38 | def name1 = { 39 | println("ohhhh") 40 | "ololo" + name 41 | } 42 | 43 | println(s"${greeting("Vitaly", 4)}!") 44 | println(s"${greeting("Vitaly", 4)}!") 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/scala/lectures/concurrent/akka/AkkaExample.scala: -------------------------------------------------------------------------------- 1 | package lectures.concurrent.akka 2 | 3 | import akka.actor.Actor 4 | import akka.actor.ActorSystem 5 | import akka.actor.Props 6 | import akka.event.Logging 7 | import akka.pattern.ask 8 | 9 | import scala.concurrent.Await 10 | import scala.concurrent.duration._ 11 | 12 | 13 | class MyActor extends Actor { 14 | val log = Logging(context.system, this) 15 | 16 | def receive = { 17 | case "test" => 18 | log.info("received test") 19 | sender() ! "Done!" 20 | 21 | case _ => 22 | log.info("received unknown message") 23 | context.become(newReceive) 24 | } 25 | 26 | def newReceive: Receive = { 27 | case _ => 28 | log.info("OH SHI...") 29 | } 30 | 31 | } 32 | 33 | 34 | object AkkaExample extends App { 35 | val system = ActorSystem("mySystem") 36 | 37 | val myActor = system.actorOf(Props[MyActor], "myactor2") 38 | 39 | val f = myActor.ask("test")(1.minute) 40 | 41 | myActor ! "another test" 42 | myActor ! "another test" 43 | 44 | Await.ready(system.terminate(), Duration.Inf) 45 | } 46 | -------------------------------------------------------------------------------- /src/main/scala/lectures/oop/types/GeneralBST.scala: -------------------------------------------------------------------------------- 1 | package lectures.oop.types 2 | 3 | /** 4 | * Модифицируйте реализацию BSTImpl из предыдущего задания. 5 | * Используя тайп параметры и паттерн Type Class, реализуйте GeneralBSTImpl таким образом, 6 | * чтобы дерево могло работать с произвольным типом данных. 7 | * 8 | * Наследников GeneralBSTImpl определять нельзя. 9 | * 10 | * Создайте генератор для деревьев 3-х типов данных: 11 | * * * * float 12 | * * * * String 13 | * * * * Watches из задачи SortStuff. Большими считаются часы с большей стоимостью 14 | */ 15 | 16 | trait GeneralBST { 17 | //val value: T 18 | val left: Option[GeneralBST] 19 | val right: Option[GeneralBST] 20 | 21 | def add(newValue: Int): GeneralBST 22 | 23 | def find(value: Int): Option[GeneralBST] 24 | } 25 | 26 | class GeneralBSTImpl extends GeneralBST { 27 | //override val value = _ 28 | 29 | override def find(value: Int): Option[GeneralBST] = ??? 30 | 31 | override def add(newValue: Int): GeneralBST = ??? 32 | 33 | override val left: Option[GeneralBST] = ??? 34 | override val right: Option[GeneralBST] = ??? 35 | } -------------------------------------------------------------------------------- /src/test/scala/lectures/concurrent/akka/PingPongIntegrationTest.scala: -------------------------------------------------------------------------------- 1 | package lectures.concurrent.akka 2 | 3 | import akka.actor.{Terminated, Props} 4 | import akka.testkit.{ImplicitSender, TestActorRef} 5 | import org.scalatest.{Matchers, WordSpec} 6 | import scala.concurrent.duration._ 7 | 8 | /** 9 | * Do the async stuff with actors created in the implicit system 10 | */ 11 | class PingPongIntegrationTest extends WordSpec with Matchers with TestActorSystem with ImplicitSender { 12 | 13 | private val pingDelay = 10l 14 | private val breakDelay = 1000l 15 | private val pingsForPong = 2 16 | private val pongsToSwitch = 2 17 | private val setsToPLay = 2 18 | 19 | "Game" should { 20 | "finish" when { 21 | "set count exceeded" in { 22 | val testActorRef = system.actorOf(Props(classOf[SupervisorActor], pingDelay, breakDelay, pingsForPong, pongsToSwitch, setsToPLay)) 23 | testActorRef ! StartTheGame 24 | val res = receiveWhile(1000 millis) { 25 | case msg: Any => msg 26 | } 27 | res should have size 1 28 | res.head == GameFinished 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/scala/java2scala/shop/http/resourceHttp.scala: -------------------------------------------------------------------------------- 1 | package java2scala.shop.http 2 | 3 | import akka.http.scaladsl.model.StatusCodes 4 | import akka.http.scaladsl.server.Directives._ 5 | import akka.http.scaladsl.server.Route 6 | import cats.effect.{ContextShift, IO, Timer} 7 | import io.circe.Encoder 8 | import java2scala.shop.{Greeting, ProductStore, SimpleStore} 9 | 10 | import scala.concurrent.duration.{Duration, FiniteDuration} 11 | 12 | object resourceHttp { 13 | def route[A: Encoder](prefix: String, store: SimpleStore[A])(implicit timer: Timer[IO], cs: ContextShift[IO]): Route = 14 | pathPrefix(prefix)( 15 | (get & path("all"))(complete(store.all)) 16 | ) 17 | } 18 | 19 | object greeterHttp { 20 | def route(greeting: Greeting)(implicit timer: Timer[IO], cs: ContextShift[IO]): Route = 21 | pathPrefix("greet") { 22 | (get & parameter("name") & parameter("duration")) { (name, durStr) => 23 | Duration.apply(durStr) match { 24 | case _: Duration.Infinite => complete(StatusCodes.BadRequest) 25 | case dur: FiniteDuration => complete(greeting.greet(name, dur)) 26 | } 27 | 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/scala/lectures/akka/chat/Chat.scala: -------------------------------------------------------------------------------- 1 | package lectures.akka.chat 2 | 3 | import akka.actor.typed.scaladsl.Behaviors 4 | import akka.actor.typed.scaladsl.AbstractBehavior 5 | import akka.actor.typed.{ActorRef, Behavior} 6 | 7 | object Chat { 8 | sealed trait Message 9 | 10 | final case class SendText(login: String, text: String) extends Message 11 | final case class Connect(login: String, session: ActorRef[Session.Message]) extends Message 12 | final case class Disconnect(session: ActorRef[Session.Message]) extends Message 13 | 14 | def behavior(name: String): Behavior[Message] = new Behave(name) 15 | 16 | private class Behave(name: String) extends AbstractBehavior[Message] { 17 | var sessions = Set.empty[ActorRef[Session.Message]] 18 | 19 | def onMessage(msg: Message): Behavior[Message] = { 20 | msg match { 21 | case SendText(login, text) => 22 | sessions.foreach(_ ! Session.NewMessage(login, text)) 23 | case Connect(login, session) => 24 | (sessions - session).foreach(_ ! Session.UserEnter(login)) 25 | sessions += session 26 | case Disconnect(session) => 27 | sessions -= session 28 | } 29 | Behaviors.same 30 | } 31 | 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/test/scala/inclasss/Futures.scala: -------------------------------------------------------------------------------- 1 | package inclasss 2 | 3 | import java.util.concurrent.atomic.{AtomicInteger, AtomicReference} 4 | import java.util.function.UnaryOperator 5 | 6 | import scala.concurrent.Future 7 | import scala.concurrent.ExecutionContext.Implicits.global 8 | import scala.concurrent.Await 9 | import scala.concurrent.duration._ 10 | 11 | object Futures { 12 | 13 | val sum = new AtomicInteger(0) 14 | val count = new AtomicInteger(0) 15 | val list = new AtomicReference[List[Int]](Nil) 16 | 17 | 18 | def add(x: Int) = { 19 | count.addAndGet(1) 20 | sum.addAndGet(x) 21 | list.updateAndGet(new UnaryOperator[List[Int]] { 22 | override def apply(t: List[Int]): List[Int] = x :: t 23 | }) 24 | } 25 | 26 | val futList = 1 to 100 map { i => 27 | Future(add(i)) 28 | } 29 | 30 | def main(args: Array[String]): Unit = { 31 | val start = System.nanoTime() 32 | val x: Future[String] = { 33 | Future(1).flatMap(_ => throw new Exception("no string today")) 34 | } 35 | val y = x.recoverWith{ 36 | case ex: Exception => Future(ex.getMessage) 37 | } 38 | Await.ready(x, Duration.Inf) 39 | println(x) 40 | println(y) 41 | println(s"elapsed ${(System.nanoTime() - start) / 1e6} millis") 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/scala/java2scala/homeworks/MapOperations.scala: -------------------------------------------------------------------------------- 1 | package java2scala.homeworks 2 | 3 | import cats.data.Ior 4 | 5 | object MapOperations { 6 | implicit class MapSyntaxExtensions[K, V](val me: Map[K, V]) extends AnyVal { 7 | 8 | /** find items contained in the either maps*/ 9 | def union[X](other: Map[K, X]): Map[K, Ior[V, X]] = ??? 10 | 11 | /** find items contained in the either maps, merge elements with custom function*/ 12 | def unionWith(other: Map[K, V])(f: (K, V, V) => V): Map[K, V] = ??? 13 | 14 | /** find items contained in the either maps, merge elements with custom function*/ 15 | def unionWithGen[X, Y](other: Map[K, X])(f: (K, V, X) => Y)(g: (K, V) => Y)(h: (K, X) => Y): Map[K, Y] = ??? 16 | 17 | /** find elements contained in both maps*/ 18 | def intersect[X](other: Map[K, X]): Map[K, (V, X)] = ??? 19 | 20 | /** find elements contained in both maps*/ 21 | def intersectWith[X, Y](other: Map[K, X])(f: (K, V, X) => Y): Map[K, Y] = ??? 22 | 23 | /** find elements contained in either map*/ 24 | def difference[X](other: Map[K, X]): Map[K, Either[V, X]] = ??? 25 | 26 | /** find elements contained in either map, use custom functions to unify types*/ 27 | def differenceWith[X, Y](other: Map[K, X])(f: V => Y)(g: X => Y): Map[K, Y] = ??? 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/scala/java2scala/Lecture7.scala: -------------------------------------------------------------------------------- 1 | package java2scala 2 | 3 | import cats.effect.{ExitCode, IO, IOApp, Timer} 4 | 5 | import scala.concurrent.duration._ 6 | import scala.io.StdIn 7 | import scala.language.postfixOps 8 | import cats.implicits._ 9 | 10 | object Lecture7 extends IOApp { 11 | val helloWorld = IO(println("Hello world")) 12 | 13 | def printlnIO(str: String): IO[Unit] = IO(println(str)) 14 | val readLn: IO[String] = IO(StdIn.readLine()) //TODO : make async !!! 15 | 16 | def elapsed(seconds: Long = 0): IO[Nothing] = 17 | for { 18 | _ <- printlnIO(s"$seconds seconds elapsed") 19 | _ <- Timer[IO].sleep(1 second) 20 | res <- elapsed(seconds + 1) 21 | } yield res 22 | 23 | def elapsed2(seconds: Long = 0): IO[Nothing] = 24 | printlnIO(s"$seconds seconds elapsed") *> 25 | Timer[IO].sleep(1 second) *> 26 | elapsed(seconds + 1) 27 | 28 | val waitForEnter = printlnIO("press Enter to exit") <* readLn 29 | 30 | val app = for { 31 | _ <- printlnIO("write your name: ") 32 | name <- readLn 33 | _ <- printlnIO(s"Hello, $name") 34 | } yield ExitCode.Success 35 | 36 | def run(args: List[String]): IO[ExitCode] = 37 | for { 38 | res <- (Timer[IO].sleep(1 millisecond) *> elapsed()).start 39 | _ <- waitForEnter 40 | } yield ExitCode.Success 41 | } 42 | -------------------------------------------------------------------------------- /src/test/scala/lectures/collections/MergeSortImplFlatSpecTest.scala: -------------------------------------------------------------------------------- 1 | package lectures.collections 2 | 3 | import org.scalatest.{FlatSpec, Matchers} 4 | 5 | class MergeSortImplFlatSpecTest extends FlatSpec with Matchers { 6 | 7 | val defaultSeq = Seq(1, 2, 3, 4, 5, 6, 7, 8, 9) 8 | 9 | "shuffled seq " should "not equal sorted seq" in { 10 | val shuffled = scala.util.Random.shuffle(defaultSeq) 11 | shuffled should not equal defaultSeq 12 | } 13 | 14 | "sorted seq " should "equal to already sorted seq" in { 15 | val shuffled = scala.util.Random.shuffle(defaultSeq) 16 | shuffled should not equal defaultSeq 17 | 18 | val sorted = MergeSortImpl.mergeSort(shuffled) 19 | sorted shouldBe defaultSeq 20 | } 21 | 22 | it should "have the the same size as origignal seq" in { 23 | val shuffled = scala.util.Random.shuffle(defaultSeq) 24 | shuffled should not equal defaultSeq 25 | 26 | val sorted = MergeSortImpl.mergeSort(shuffled) 27 | sorted should have size shuffled.size 28 | } 29 | 30 | "an error" should "occur if index exceed seq size" in { 31 | val shuffled = scala.util.Random.shuffle(defaultSeq) 32 | shuffled should not equal defaultSeq 33 | intercept[IndexOutOfBoundsException] { 34 | val sorted = MergeSortImpl.mergeSort(shuffled) 35 | sorted(shuffled.length) 36 | } 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/scala/lectures/concurrent/akka/AkkaPinPongExample.scala: -------------------------------------------------------------------------------- 1 | package lectures.concurrent.akka 2 | 3 | import com.typesafe.config.ConfigFactory 4 | 5 | /** 6 | * Реализовать на Акке игру в пин-понг. Игра должна представлять собой 2 актора. 7 | * В начале игры первый актор посылает “пинг” каждые N ms. 8 | * Второй актор отвечает сообщением “понг” на каждые M посланных “пингов”. 9 | * Известно, что актор, который принимает пинги, часто падает с ошибкой. 10 | * Необходимо имитировать поломку каждые B ms > N и поднимать сломавшийся актор заново с тем значением пингов, с которым он упал. 11 | * После K принятых “pong” акторы меняются местами. 12 | * Игра в пин-понг заканчивается, после G перемен игроков. 13 | * Входные параметры: 14 | * • N – задержка между пингами 15 | * • B – задержка между поломками 16 | * • M – количество “пингов”, необходимых для “понга” 17 | * • K – количесво “pong”, после которого акторы меняются местами 18 | * • G - количество “сетов”, после которого игра заканчивается 19 | * 20 | */ 21 | object AkkaPinPongExample extends App { 22 | 23 | val actorSystemConfig = ConfigFactory.load() 24 | 25 | val actorSystem = akka.actor.ActorSystem("Fintech", actorSystemConfig) 26 | 27 | val supervisorActor = actorSystem.actorOf(SupervisorActor.props(), "game_supervisor") 28 | 29 | supervisorActor ! StartTheGame 30 | } 31 | -------------------------------------------------------------------------------- /src/test/scala/lectures/collections/MergeSortImpFunSuiteTest.scala: -------------------------------------------------------------------------------- 1 | package lectures.collections 2 | 3 | import org.scalatest.{FunSuite, Matchers} 4 | 5 | /** 6 | * 7 | * 8 | * 9 | * 10 | */ 11 | class MergeSortImpFunSuiteTest extends FunSuite with Matchers { 12 | 13 | val defaultSeq = Seq(1,2,3,4,5,6,7,8,9) 14 | 15 | test("shuffled seq should not equal sorted seq") { 16 | val shuffled = scala.util.Random.shuffle(defaultSeq) 17 | shuffled should not equal defaultSeq 18 | } 19 | 20 | test("a seq sorted with an Impl should equal to already sorted seq") { 21 | val shuffled = scala.util.Random.shuffle(defaultSeq) 22 | shuffled should not equal defaultSeq 23 | 24 | val sorted = MergeSortImpl.mergeSort(shuffled) 25 | sorted shouldBe defaultSeq 26 | } 27 | 28 | test("a size of a sorted seq should be the same") { 29 | val shuffled = scala.util.Random.shuffle(defaultSeq) 30 | shuffled should not equal defaultSeq 31 | 32 | val sorted = MergeSortImpl.mergeSort(shuffled) 33 | sorted should have size shuffled.size 34 | } 35 | 36 | test("an error should occur if index exceed seq size") { 37 | val shuffled = scala.util.Random.shuffle(defaultSeq) 38 | shuffled should not equal defaultSeq 39 | intercept[IndexOutOfBoundsException] { 40 | val sorted = MergeSortImpl.mergeSort(shuffled) 41 | sorted(shuffled.length) 42 | } 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/main/scala/lectures/eval/LazyScheduler.scala: -------------------------------------------------------------------------------- 1 | package lectures.eval 2 | 3 | import java.time.Clock 4 | 5 | import scala.collection.SeqView 6 | 7 | /** 8 | * В этом задании ваша задча реализовать своеобразный View с таймером. 9 | * 10 | * Он должен представлять из себя стандартный SeqView c ограничением по времени. 11 | * Т.е. этот view ведет себя как обычно, пока не истечет таймаут, предеданный при создании. 12 | * Как только таймаут истекает, view должен начать вести себя так, как будто коллекция пуста. 13 | * 14 | * Для решения задачи подставьте на место вопросительных знаков реализацию view. 15 | * Раскомментируйте и выполните тесты в lectures.eval.LazySchedulerTest 16 | */ 17 | 18 | object LazySchedulerView { 19 | 20 | implicit class SeqViewConverter[A](f: Seq[A]) { 21 | val c = Clock.systemDefaultZone() 22 | 23 | /** 24 | * 25 | * @param expirationTimeout - таймаут, после которого view становится пустым, в миллисекундах 26 | * @return - view 27 | */ 28 | def lazySchedule(expirationTimeout: Long): SeqView[A, Seq[_]] = { 29 | val i = c.instant().plusMillis(expirationTimeout) 30 | ??? 31 | } 32 | } 33 | } 34 | 35 | object LazySchedulerViewExample extends App { 36 | 37 | import LazySchedulerView._ 38 | 39 | val v = List(1, 2, 3, 56) 40 | val d = v.lazySchedule(1300) 41 | 42 | print(d.length) 43 | Thread.sleep(1500) 44 | print(d.length) 45 | } 46 | 47 | 48 | -------------------------------------------------------------------------------- /src/test/scala/lectures/concurrent/akka/SupervisorUnitTest.scala: -------------------------------------------------------------------------------- 1 | package lectures.concurrent.akka 2 | 3 | import akka.testkit.TestActorRef 4 | import akka.util.Timeout 5 | import org.scalatest.{Matchers, WordSpec} 6 | import scala.concurrent.Await 7 | import akka.pattern.ask 8 | import scala.concurrent.duration._ 9 | 10 | /** 11 | * 12 | */ 13 | class SupervisorUnitTest extends WordSpec with Matchers with TestActorSystem { 14 | 15 | private val pingDelay = 1000l 16 | private val breakDelay = 1000l 17 | private val pingsForPong = 2 18 | private val pongsToSwitch = 2 19 | private val setCount = 2 20 | implicit val timeout: Timeout = Timeout(10 second) 21 | 22 | "supervisor actor" should { 23 | "create two children" when { 24 | "proper message accepted" in { 25 | val testActorRef = TestActorRef(new SupervisorActor(pingDelay, breakDelay, pingsForPong, pongsToSwitch, setCount)) 26 | testActorRef ! StartTheGame 27 | testActorRef.children should have size 2 28 | } 29 | } 30 | "stop it self" when { 31 | "set count limit reached" in { 32 | val testActorRef = TestActorRef(new SupervisorActor(pingDelay, breakDelay, pingsForPong, pongsToSwitch, 1)) 33 | testActorRef ! StartTheGame 34 | Await.ready(testActorRef ? SetFinished(testActorRef.children.head, testActorRef.children.tail.head), 10 seconds) 35 | testActorRef.children should have size 0 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/scala/java2scala/homeworks/funcs/ChurchList.scala: -------------------------------------------------------------------------------- 1 | package java2scala.homeworks.funcs 2 | 3 | trait ChurchList[A] { self => 4 | def fold[R](z: R)(ag: A => R => R): R 5 | 6 | def ::(x: A): ChurchList[A] = new ChurchList[A] { 7 | def fold[R](z: R)(ag: A => R => R): R = ag(x)(self.fold(z)(ag)) 8 | } 9 | 10 | def map[B](f: A => B): ChurchList[B] = 11 | new ChurchList[B] { 12 | def fold[R](z: R)(ag: B => R => R): R = self.fold(z)(a => ag(f(a))) 13 | } 14 | 15 | def filter(p: A => Boolean): ChurchList[A] = 16 | new ChurchList[A] { 17 | def fold[R](z: R)(ag: A => R => R): R = self.fold(z)(a => if (p(a)) ag(a) else identity) 18 | } 19 | 20 | def flatMap[B](f: A => ChurchList[B]): ChurchList[B] = new ChurchList[B] { 21 | def fold[R](z: R)(ag: B => R => R): R = 22 | self.fold(z)(a => r => f(a).fold(r)(ag)) 23 | } 24 | 25 | def ++(that: ChurchList[A]): ChurchList[A] = new ChurchList[A] { 26 | def fold[R](z: R)(ag: A => R => R): R = self.fold(that.fold(z)(ag))(ag) 27 | } 28 | 29 | def headOption: Option[A] = fold[Option[A]](None)(a => _.orElse(Some(a))) 30 | 31 | def toList: List[A] = fold[List[A]](Nil)(e => e :: _) 32 | } 33 | 34 | object ChurchList { 35 | def apply[A](xs: A*): ChurchList[A] = new ChurchList[A] { 36 | def fold[R](z: R)(ag: A => R => R): R = xs.foldRight(z)(Function.uncurried(ag)) 37 | } 38 | 39 | def empty[A]: ChurchList[A] = new ChurchList[A] { 40 | def fold[R](z: R)(ag: A => R => R): R = z 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/scala/lectures/collections/MyListImpl.scala: -------------------------------------------------------------------------------- 1 | package lectures.collections 2 | 3 | /** 4 | * Представим, что по какой-то причине Вам понадобилась своя обертка над списком целых чисел List[Int] 5 | * 6 | * Вы приняли решение, что будет достаточно реализовать 4 метода: 7 | * * * * * def flatMap(f: (Int => MyList)) - реализуете на основе соответствующего метода из List 8 | * * * * * метод map(f: (Int) => Int) - с помощью только что полученного метода flatMap класса MyList 9 | * * * * * filter(???) - через метод flatMap класса MyList 10 | * * * * * foldLeft(acc: Int)(???) - через декомпозицию на head и tail 11 | * 12 | * Для того, чтобы выполнить задание: 13 | * * * * * раскомментируйте код 14 | * * * * * замените знаки вопроса на сигнатуры и тела методов 15 | * * * * * не используйте var и мутабильные коллекции 16 | * 17 | */ 18 | object MyListImpl extends App { 19 | 20 | case class MyList(data: List[Int]) { 21 | 22 | // def flatMap(f: (Int => MyList)) = 23 | // MyList(data.flatMap(inp => f(inp).data)) 24 | // 25 | // def map(f: ???) = ??? 26 | // 27 | // def foldLeft(acc: Int)(???): Int = ??? 28 | // 29 | // def filter(???) = ??? 30 | } 31 | 32 | // require(MyList(List(1, 2, 3, 4, 5, 6)).map(_ * 2).data == List(2, 4, 6, 8, 10, 12)) 33 | // require(MyList(List(1, 2, 3, 4, 5, 6)).filter(_ % 2 == 0).data == List(2, 4, 6)) 34 | // require(MyList(List(1, 2, 3, 4, 5, 6)).foldLeft(0)((tpl) => tpl._1 + tpl._2) == 21) 35 | // require(MyList(Nil).foldLeft(0)((tpl) => tpl._1 + tpl._2) == 0) 36 | 37 | } -------------------------------------------------------------------------------- /src/main/scala/lectures/functions/Fibonacci.scala: -------------------------------------------------------------------------------- 1 | package lectures.functions 2 | 3 | /** 4 | * Цель упражнения: вычислить 9 - е число Фибоначчи 5 | * Для этого раскомментируйте строчку в методе fibs и исправьте ошибку компиляции. 6 | * 7 | * Данная реализация вычисления чисел фибоначчи крайне не оптимальна (имеет показатеьную сложность O(a.pow(n)) ) 8 | * Для того, что бы в этом убедиться, Вы можете раскомментировать 9 | * строчку с вычислением 1000-ого числа фибоначчи 10 | * 11 | */ 12 | object Fibonacci extends App { 13 | 14 | // Task 2 15 | def fibs(num: Int) = { 16 | if (num == 1) 1 17 | if (num == 2) 1 18 | //fibs(num - 1) + fibs(num - 2) 19 | } 20 | 21 | println(fibs(9)) 22 | //println(fibs(1000)) 23 | } 24 | 25 | /** 26 | * Цель упражнения: используя приемы динамического программирования, 27 | * реализовать более оптимальный алгоритм подсчета чисел фибоначчи 28 | * Для этого нужно реализовать функцию fibsImpl. 29 | * Сигнатуру функции Вы можете расширять по своему усмотрению, 30 | * но реализация должна удовлетворять следующим требованиям 31 | * * * * метод fibsImpl - должен быть tail recursive 32 | * * * * параметр acc - аккумулятор посчитанных значений 33 | * 34 | */ 35 | object Fibonacci2 extends App { 36 | 37 | def fibs2(num: Int) = 38 | if (num <= 3) Array(1, 1, 2)(num - 1) 39 | else fibsImpl(num, Array(1, 1, 2))(num - 1) 40 | 41 | private def fibsImpl(num: Int, acc: Array[Int]): Array[Int] = ??? 42 | 43 | println(fibs2(16)) 44 | //println(fibs(1000)) 45 | } 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /src/main/scala/java2scala/Lecture2.scala: -------------------------------------------------------------------------------- 1 | package java2scala 2 | 3 | object Lecture2 { 4 | 5 | trait Food 6 | 7 | abstract class Animal[Self, Eats](name: String, full: Double = 0) { 8 | animal: Self => 9 | def eat(food: Eats): Self 10 | 11 | def eatLegacy(food: Food): Animal[Self, Eats] 12 | } 13 | 14 | case class Grass() extends Food 15 | 16 | object Animal 17 | 18 | case class Cow(name: String, full: Double = 0) extends Animal[Cow, Grass](name, full) with Food { 19 | 20 | override def eatLegacy(food: Food): Cow = 21 | if (food.isInstanceOf[Grass]) eat(food.asInstanceOf[Grass]) 22 | else { 23 | println("I dont eat it") 24 | this 25 | } 26 | 27 | override def eat(food: Grass): Cow = { 28 | println("yummi") 29 | Cow(name, full + 0.1) 30 | } 31 | 32 | } 33 | 34 | case class Lion(name: String, full: Double = 0) extends Animal[Lion, Cow](name, full) { 35 | def eat(cow: Cow): Lion = { 36 | println(s"that ${cow.name} was delicious, thank you") 37 | Lion(name, full) 38 | } 39 | 40 | def eatLegacy(food: Food): Lion = food match { 41 | case cow: Cow => eat(cow) 42 | 43 | case _ => 44 | println("I dont eat it") 45 | this 46 | } 47 | 48 | } 49 | 50 | def main(args: Array[String]): Unit = { 51 | val cow = Cow("maggy") 52 | val lion = Lion("john") 53 | val grass = Grass() 54 | val cow2 = cow.eat(grass) 55 | lion.eat(cow2) 56 | 57 | // cow: cow2.type 58 | 59 | println(cow) 60 | println(cow2) 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/scala/lectures/functions/Authentication.scala: -------------------------------------------------------------------------------- 1 | package lectures.functions 2 | 3 | import scala.util.Random 4 | 5 | /** 6 | * Эта задача имитирует авторизацию в интернет банке. 7 | * Авторизоваться можно 2-я способами. Предоставив карту или логин/пароль 8 | * Вам дан список зарегистрированных банковских карт и 9 | * AuthenticationData.registeredCards 10 | * и список зарегистрированных логинов/паролей 11 | * AuthenticationData.registeredLoginAndPassword 12 | * 13 | * Ваша задача, получая на вход приложения список тестовых юзеров 14 | * AuthenticationData.testUsers 15 | * Оставить в этом списке только тех пользователей, чьи учетные данные 16 | * совпадают с одними из зарегистрированных в системе 17 | * 18 | * Пользователи бывают 3-х видов 19 | * AnonymousUser - пользователь, который не указал своих учетных данных 20 | * CardUser - пользователь, который предоствил данные карты 21 | * LPUser - пользователь, предоставивший логин и пароль 22 | * 23 | * Для решения задачи раскомметируйте код в теле объекта Authentication 24 | * Реализуйте методы authByCard и authByLP, заменив 25 | * знаки ??? на подходящие выражения. 26 | * 27 | * Что-либо еще, кроме знаков ???, заменять нельзя 28 | */ 29 | object Authentication extends App { 30 | 31 | import AuthenticationData._ 32 | 33 | // val authByCard: PartialFunction[???, ???] = ??? 34 | 35 | // val authByLP: PartialFunction[???, ???] = ??? 36 | 37 | val authenticated: List[Option[User]] = for (user <- testUsers) yield { 38 | ??? 39 | } 40 | 41 | authenticated.flatten foreach println 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/main/scala/java2scala/shop/http/package.scala: -------------------------------------------------------------------------------- 1 | package java2scala.shop 2 | import akka.http.scaladsl.marshalling.{Marshaller, ToEntityMarshaller, ToResponseMarshaller} 3 | import akka.http.scaladsl.model.{ContentTypes, HttpEntity} 4 | import cats.effect.{ContextShift, IO, Timer} 5 | import io.circe.Encoder 6 | import akka.http.scaladsl.model.MediaTypes.{`application/json` => JSON} 7 | import akka.http.scaladsl.server.{Directives, Route} 8 | import akka.stream.scaladsl.Source 9 | import akka.util.ByteString 10 | import cats.Monoid 11 | import io.circe.syntax._ 12 | import cats.implicits._ 13 | import Directives._ 14 | import scala.concurrent.duration._ 15 | 16 | package object http { 17 | implicit def toResponseMarshaller[A: Encoder](implicit cs: ContextShift[IO], timer: Timer[IO]): ToEntityMarshaller[IO[A]] = 18 | Marshaller.withFixedContentType(JSON) { ia: IO[A] => 19 | val iaWithTimeout = 20 | IO.race( 21 | timer.sleep(1.seconds), 22 | ia.map(a => ByteString(a.asJson.noSpaces)), 23 | ) 24 | .flatMap { 25 | case Right(s) => s.pure[IO] 26 | case Left(()) => IO.raiseError(TimeoutError()) 27 | } 28 | 29 | HttpEntity( 30 | JSON, 31 | Source.fromFuture(iaWithTimeout.unsafeToFuture()) 32 | ) 33 | } 34 | 35 | implicit val ioRouteMonoid: Monoid[IO[Route]] = new Monoid[IO[Route]] { 36 | def empty: IO[Route] = IO.pure(reject) 37 | def combine(x: IO[Route], y: IO[Route]): IO[Route] = (x, y).mapN(_ ~ _) 38 | } 39 | 40 | final case class TimeoutError() extends Throwable 41 | } 42 | -------------------------------------------------------------------------------- /src/test/scala/lectures/oop/BSTTestWithMocks.scala: -------------------------------------------------------------------------------- 1 | package lectures.oop 2 | 3 | import org.mockito.Mockito.{when => w, _} 4 | 5 | import org.scalatest.mock.MockitoSugar 6 | import org.scalatest.{Matchers, GivenWhenThen, BeforeAndAfterAll, WordSpec} 7 | import org.mockito.Matchers.{eq => exact, _} 8 | /** 9 | * This test tests nothing and is intended only to show the power of Mockito mocks 10 | * 11 | * 12 | */ 13 | class BSTTestWithMocks extends WordSpec with Matchers with MockitoSugar with BeforeAndAfterAll with GivenWhenThen{ 14 | 15 | val bstSUT = mock[BST] 16 | "BST" when { 17 | "empty" should { 18 | "not have left child" in { 19 | w(bstSUT.left).thenReturn(None) 20 | bstSUT.left shouldBe None 21 | } 22 | "and right child" in{ 23 | w(bstSUT.right).thenReturn(None) 24 | bstSUT.right shouldBe None 25 | } 26 | } 27 | } 28 | 29 | it should { 30 | "return values" which { 31 | "were added" in { 32 | info("emulate that there is a node with the value == 10") 33 | w(bstSUT.find(any[Int]())).thenReturn(None) 34 | info("set exact value with matcher") 35 | w(bstSUT.find(exact[Int](10))).thenReturn(Some(bstSUT)) 36 | info("set exact value") 37 | w(bstSUT.find(10)).thenReturn(Some(bstSUT)) 38 | 39 | bstSUT.find(1) shouldBe None 40 | bstSUT.find(10) should be === Some(bstSUT) 41 | info("verify that we have executed find method for at least once") 42 | verify(bstSUT, atLeastOnce()).find(any[Int]()) // never, atLeast, calls.. are also available 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/scala/lectures/oop/lineization.scala: -------------------------------------------------------------------------------- 1 | package lectures.oop 2 | 3 | abstract class AbstractTest { 4 | val name: String = "" 5 | println("Deepest level of inheritance: AbstractTest") 6 | 7 | def whoAmI() 8 | } 9 | 10 | class NameProvider extends AbstractTest { 11 | 12 | override val name: String = "name provided by trait" 13 | println("One level up: NameProvider") 14 | 15 | override def whoAmI() = { 16 | println(s"name is `$name` in NameProvider") 17 | } 18 | } 19 | 20 | trait AnotherNameProvider extends AbstractTest { 21 | 22 | override val name: String = "name provided by another trait" 23 | println("Almost on the surface: AnotherNameProvider") 24 | 25 | abstract override def whoAmI() = { 26 | println(s"name is `$name` in AnotherNameProvider") 27 | super.whoAmI() 28 | } 29 | } 30 | 31 | class ConcreteClass extends NameProvider with AnotherNameProvider { 32 | 33 | override val name: String = "Concrete class" 34 | println("The uppermost level: ConcreteClass") 35 | 36 | override def whoAmI() = { 37 | println(s"name is `$name` in Concrete class") 38 | super.whoAmI() 39 | } 40 | } 41 | 42 | object InheritanceTest extends App { 43 | val k = new ConcreteClass() 44 | k.whoAmI() 45 | val n = k.name 46 | } 47 | 48 | /* 49 | Deepest level of inheritance: AbstractTest 50 | One level up: NameProvider 51 | Almost on the surface: AnotherNameProvider 52 | The uppermost level: ConcreteClass 53 | name is `Concrete class` in Concrete class 54 | name is `Concrete class` in AnotherNameProvider 55 | name is `Concrete class` in NameProvider 56 | */ 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /src/test/scala/lectures/eval/LazySchedulerTest.scala: -------------------------------------------------------------------------------- 1 | package lectures.eval 2 | 3 | import org.scalacheck.Gen 4 | import org.scalatest.{Matchers, WordSpec} 5 | import org.scalatest.prop.PropertyChecks 6 | import LazySchedulerView._ 7 | 8 | /** 9 | * 10 | * 11 | */ 12 | class LazySchedulerTest extends WordSpec with PropertyChecks with Matchers { 13 | 14 | val nott = afterWord("not") 15 | 16 | "Lazy scheduler view " should { 17 | // "iterate over all elements" when { 18 | // "it has not expired yet" in { 19 | // val g = Gen.listOfN(100, Gen.alphaStr) 20 | // forAll(g) { l => 21 | // val r = l.lazySchedule(Long.MaxValue).map { 22 | // identity 23 | // } 24 | // r should have size 100 25 | // } 26 | // } 27 | // } 28 | // 29 | // "return lazy views " which { 30 | // "conform timeout contract" in { 31 | // val ls = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).lazySchedule(500) 32 | // val filteredView = ls.takeWhile(_ > 0) 33 | // filteredView should have size 10 34 | // Thread.sleep(500) 35 | // filteredView should have size 10 36 | // val filteredView2 = ls.takeWhile(_ > 0) 37 | // filteredView2 should have size 0 38 | // } 39 | // } 40 | } 41 | 42 | "Lazy scheduler view " should nott { 43 | // "iterate" when { 44 | // "it already has expired" in { 45 | // val g = Gen.listOfN(100, Gen.alphaStr) 46 | // forAll(g) { l => 47 | // val r = l.lazySchedule(-1).map { 48 | // identity 49 | // } 50 | // r should have size 0 51 | // } 52 | // } 53 | // } 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/main/scala/lectures/operators/Competition.scala: -------------------------------------------------------------------------------- 1 | package lectures.operators 2 | 3 | /** 4 | * Проходит чемпионат по спортивному киданю костей) 5 | * Сражаются "Наши" и "Приезжие" 6 | * 7 | * Каждый член команды бросил кубик и должен сравнить свой результат с каждым результатом из команды соперника 8 | * 9 | * Итог сравнений должн быть записан в ассоциативный массив в таком виде 10 | * val results: Array[(String, Int)] = (("Artem vs John" -> 3), ("Artem vs James" -> 5), ... ) 11 | * При этом числовое значение должно быть получено как разность между результатами первого и второго игроков 12 | * 13 | * Когда составлен массив results, надо подсчитать, чья взяла. 14 | * Если результат встречи >0, то finalResult увеличивается на единицу 15 | * Если <0, уменьшается 16 | * 17 | * В итоге надо напечатать: 18 | * "Наша взяла", если наших побед больше, т.е. finalResult > 0 19 | * "Продули", если победили приезжие 20 | * "Победила дружба" в случае ничьи 21 | * 22 | * Для решения задачи раскомментируйте тело объекта Competition 23 | */ 24 | 25 | object Competition extends App { 26 | 27 | val locals = Map("Artem" -> 6, "Sergey" -> 5, "Anton" -> 2, "Vladimir" -> "2", "Alexander" -> 4l) 28 | val foreigners = Map[String, Int]("John" -> 3, "James" -> 1, "Tom" -> 2, "Dick" -> 5, "Eric" -> 6) 29 | 30 | // val results = for (l <- locals; 31 | // ???) { 32 | // val localName = l._1 33 | // val localValue = l._2 34 | // ??? 35 | // } 36 | 37 | // var finalResult = 0 38 | // for (r <- results) { 39 | // if (???) finalResult = finalResult + 1 40 | // else ??? 41 | // } 42 | 43 | print("Победила дружба") 44 | } 45 | -------------------------------------------------------------------------------- /src/test/scala/lectures/concurrent/akka/WorkerUnitTest.scala: -------------------------------------------------------------------------------- 1 | package lectures.concurrent.akka 2 | 3 | import akka.testkit._ 4 | import org.scalatest.{Matchers, WordSpec} 5 | 6 | /** 7 | * 8 | * Do the sync tests 9 | * All test are sync because TestActorRef uses CallingThreadDispatcher 10 | * 11 | */ 12 | class WorkerUnitTest extends WordSpec with Matchers with TestActorSystem with ImplicitSender { 13 | 14 | private val pingDelay = 1000l 15 | private val breakDelay = 100000l 16 | private val pingsForPong = 2 17 | private val pongsToSwitch = 2 18 | 19 | "worker" should { 20 | "become Ponger" when { 21 | "BecomePong message arrive" in { 22 | val testActorRef = TestActorRef(new Worker(pingDelay, breakDelay, pingsForPong, pongsToSwitch)) 23 | testActorRef ! BecomePong() 24 | testActorRef ! WorkerStatusTest 25 | expectMsg(WorkerStatus(false)) 26 | } 27 | } 28 | "become Pinger" when { 29 | "BecomePing message arrive " in { 30 | val testPongerActorRef = TestActorRef(new Worker(pingDelay, breakDelay, pingsForPong, pongsToSwitch)) 31 | val testActorRef = TestActorRef(new Worker(pingDelay, breakDelay, pingsForPong, pongsToSwitch)) 32 | testActorRef ! BecomePing(testPongerActorRef) 33 | testActorRef ! WorkerStatusTest 34 | expectMsg(WorkerStatus(true)) 35 | } 36 | } 37 | "pong" when { 38 | "in Ponger state and it's time to Pong" in { 39 | val testActorRef = TestActorRef(new Worker(pingDelay, breakDelay, pingsForPong, pongsToSwitch)) 40 | testActorRef ! BecomePong() 41 | for (i <- 1 to pingsForPong) { 42 | testActorRef ! Ping 43 | } 44 | expectMsg(Pong) 45 | } 46 | } 47 | } 48 | } 49 | 50 | -------------------------------------------------------------------------------- /src/main/scala/lectures/oop/Application.scala: -------------------------------------------------------------------------------- 1 | package lectures.oop 2 | 3 | import lectures.functions.SQLAPI 4 | 5 | /** 6 | * У вас есть приложение, которое можно запустить в тестовом или продуктовом окружении. 7 | * В зависимости от окружения ваше приложение создает БД с тестовым или бовым адресом 8 | * и использует подходящую реализацию сервиса. 9 | * 10 | * Ваша задача: реализовать методы doSomeService в тестовом и боевом сервисах. Для этого: 11 | * * * * добавьте SQLAPI как self type annotation 12 | * * * * уберите знаки вопроса и раскомментируйте execute(sql) 13 | * * * * допишите тело функций в соответсвии с комментарием в каждом методе 14 | * После этого допишите инициализацию usefulService в Application так, чтобы: 15 | * в тестовой среде использовался TestServiceImpl 16 | * в боевой - ProductionServiceImpl 17 | * 18 | * Допишите тесты в ApplicationTest 19 | * 20 | */ 21 | trait UsefulService { 22 | def doSomeService(): Int 23 | } 24 | 25 | trait TestServiceImpl extends UsefulService { 26 | private val sql = "do the SQL query and then count words" 27 | def doSomeService() = ??? //execute(sql) //подсчитайте количество слов в результате execute 28 | } 29 | 30 | trait ProductionServiceImpl extends UsefulService { 31 | private val sql = "do the SQL query and than count 'a' sympols" 32 | def doSomeService() = ??? //execute(sql) // подсчитайте сколько символов 'a' в полученной строке 33 | } 34 | 35 | class Application(isTestEnv: Boolean) { 36 | 37 | val usefulService: UsefulService = if (isTestEnv) 38 | ??? //передайте "test db Resource" в качестве ресурсв в конструктор SQLAPI 39 | else 40 | ??? //передайте "production Resource" в качестве ресурсв в конструктор SQLAPI 41 | 42 | def doTheJob() = usefulService.doSomeService() 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/main/scala/lectures/oop/Fisherman.scala: -------------------------------------------------------------------------------- 1 | package lectures.oop 2 | 3 | /** 4 | * Программист Иван собрался на рыбалку. 5 | * Он хочет поймать огромную рыбину и для этого решил собрать свою любимую удочку. 6 | * Иван раздобыл составные части, ему осталось правильно их соединить. 7 | * 8 | * Каждая составная часть - это класс (или трейт, или объект), маркированный определенным образом. 9 | * Например, PartD - это часть удочки, маркированная символом D 10 | * 11 | * Раскомментируйте код, начиная с ??? PartD 12 | * 13 | * Ваша задача: с помощью extends и with добиться того, чтобы вызов println(o.str) вывел в консоль слово YDOCHKA 14 | * 15 | * * * * В самом низу иерархии должен быть класс PartO, т.е. ни один член приложения не должен быть сабклассом PartO 16 | * * * * Остальные часть могут иметь друг с другом любое отношение наследования 17 | * * * * Новые члены приложения (т.е. новые классы, трейты или объекты) вводить нельзя 18 | * * * * str может быть любым членом класса (методом, переменной, константой) 19 | * * * * Нельзя использовать явно символ-маркер одной части в str другой части 20 | * * * * т.е. сделать так: PartO { override val str = "YDOCHKA" } нельзя, зато 21 | * * * * так можно: PartD { def str = { val newStr = doSomethingWithD("D"); newStr }} 22 | * * * * содержимое FishermansApp менять нельзя 23 | **/ 24 | //??? PartD { 25 | // ??? str = "D" 26 | //} 27 | // 28 | //??? PartY { 29 | // ??? str = "Y" 30 | //} 31 | // 32 | //??? PartCH { 33 | // ??? str = "CH" 34 | //} 35 | // 36 | //??? PartK { 37 | // ??? str = "K" 38 | //} 39 | // 40 | //??? PartA { 41 | // ??? str = "A" 42 | //} 43 | // 44 | //??? PartO extends PartA { 45 | // ??? str = "O" 46 | //} 47 | // 48 | //object FishermansApp extends App { 49 | // val o = new PartO 50 | // println(o.str) 51 | //} 52 | 53 | 54 | -------------------------------------------------------------------------------- /src/main/scala/java2scala/shop/SimpleStore.scala: -------------------------------------------------------------------------------- 1 | package java2scala.shop 2 | import java.io.{BufferedReader, InputStreamReader} 3 | import java.util.UUID 4 | 5 | import cats.effect.{ContextShift, IO} 6 | import io.circe.Decoder 7 | import cats.implicits._ 8 | 9 | import scala.collection.JavaConverters._ 10 | import io.circe.parser._ 11 | 12 | import scala.concurrent.ExecutionContext 13 | 14 | trait SimpleStore[A] { 15 | def all: IO[List[A]] 16 | 17 | def getById(id: UUID): IO[Option[A]] 18 | 19 | def byId(id: UUID): IO[A] 20 | } 21 | 22 | object SimpleStore { 23 | 24 | private class ListStore[A: Key](items: List[A], byIdMap: Map[UUID, A]) extends SimpleStore[A] { 25 | def all: IO[List[A]] = IO.pure(items) 26 | def getById(id: UUID): IO[Option[A]] = IO.pure(byIdMap.get(id)) 27 | def byId(id: UUID): IO[A] = getById(id).flatMap(_.liftTo[IO](Key.notFound[A](id))) 28 | } 29 | 30 | private def makeListStore[A: Key](items: List[A]): IO[ListStore[A]] = 31 | items 32 | .groupBy(Key.key[A]) 33 | .toList 34 | .traverse { 35 | case (id, List(a)) => IO.pure(id -> a) 36 | case (id, _) => IO.raiseError(Key.multiple[A](id)) 37 | } 38 | .map(byId => new ListStore(items, byId.toMap)) 39 | 40 | def fromResource[A: Key: Decoder](name: String, blocking: ExecutionContext)( 41 | implicit basic: ContextShift[IO]): IO[SimpleStore[A]] = { 42 | val read: IO[List[A]] = IO { 43 | val stream = getClass.getResourceAsStream(name) 44 | val reader = new BufferedReader(new InputStreamReader(stream)) 45 | val total = reader.lines().iterator.asScala.mkString 46 | decode[List[A]](total): Either[Throwable, List[A]] 47 | }.rethrow 48 | 49 | for { 50 | _ <- IO.shift(blocking) 51 | products <- read 52 | store <- makeListStore(products) 53 | _ <- IO.shift(basic) 54 | } yield store 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/main/scala/lectures/functions/SQLAPI.scala: -------------------------------------------------------------------------------- 1 | package lectures.functions 2 | 3 | /** 4 | * Представим себе, как бы мог выглядеть API для работы, например, с БД 5 | * Строить методы этого API будем через композицию уже определенных методов. 6 | * 7 | * Ваша задача реализовать метод execute, композируя методы из объекта SQLAPI 8 | * Метод execute из объекта SQLAPI должен выполнить следующие действия 9 | * * * * * залогировать ресурс 10 | * * * * * получить соединение с помощью метода connection 11 | * * * * * залогировать запрос 12 | * * * * * открыть соединение 13 | * * * * * выполнить SQL 14 | * * * * * залогировать результат 15 | * 16 | * В результате в консоль должно быть выведено сообщение 17 | * some DB 18 | * some SQL 19 | * SQL has been executed. Congrats! 20 | * 21 | * 22 | * Обратите внимание на то, что композиция функций учит писать код в декларативном виде 23 | * Благодаря этому мы можем отделить реализацию методов от их применения и, в конечном итоге, иметь переиспользуемую 24 | * декларацию, которую можно применить, например, для настоящей БД 25 | * 26 | * 27 | */ 28 | class SQLAPI(resource: String) { 29 | 30 | case class Connection(resource: String, opened: Boolean = false) { 31 | 32 | private val result = "SQL has been executed. Congrats!" 33 | 34 | def open(): Connection = this.copy(opened = true) 35 | 36 | def execute(sql: String): String = if (opened) result else throw new Exception("You have to open connection before execute") 37 | 38 | } 39 | 40 | private def logParameter[T](prm: T): T = ??? 41 | 42 | val connection = (resource: String) => Connection(resource) 43 | 44 | def execute(sql: String): String = ??? // use resource from constructor 45 | 46 | 47 | def openConnection(connection: Connection): (String) => String = 48 | (sql: String) => { 49 | connection.open execute sql 50 | } 51 | 52 | } 53 | 54 | object SQLCheck extends App { 55 | 56 | new SQLAPI("some DB").execute("some SQL") 57 | 58 | } 59 | -------------------------------------------------------------------------------- /src/main/scala/lectures/concurrent/akka/SupervisorActor.scala: -------------------------------------------------------------------------------- 1 | package lectures.concurrent.akka 2 | 3 | import akka.actor.SupervisorStrategy.{Resume, Stop} 4 | import akka.actor._ 5 | import com.typesafe.config.ConfigFactory 6 | 7 | object SupervisorActor { 8 | 9 | def props(): Props = { 10 | val actorGameCfg = ConfigFactory.load("game").getConfig("game_conf") 11 | Props(classOf[SupervisorActor], actorGameCfg.getLong("ping_delay"), 12 | actorGameCfg.getLong("break_delay"), 13 | actorGameCfg.getInt("ping_for_pong"), 14 | actorGameCfg.getInt("pong_switch"), 15 | actorGameCfg.getInt("set_count") 16 | ) 17 | } 18 | } 19 | 20 | class SupervisorActor(pingDelay: Long, 21 | breakDelay: Long, 22 | pingsForPong: Int, 23 | pongsToSwitch: Int, 24 | setCountPrm: Int) extends Actor with ActorLogging { 25 | 26 | override val supervisorStrategy = OneForOneStrategy() { 27 | case p: PongerFailureException => Resume 28 | case _ => Stop 29 | } 30 | 31 | override def receive: Receive = { 32 | case StartTheGame => 33 | context.become(manageGame(setCountPrm, sender)) 34 | val ponger = context.actorOf(Worker.props(pingDelay, breakDelay, pingsForPong, pongsToSwitch), "Worker1") 35 | val pinger = context.actorOf(Worker.props(pingDelay, breakDelay, pingsForPong, pongsToSwitch), "Worker2") 36 | ponger ! BecomePong() 37 | pinger ! BecomePing(ponger) 38 | } 39 | 40 | def manageGame(setCount: Int, starterRef: ActorRef): Receive = { 41 | case SetFinished(ponger, pinger) if setCount <= 1 => 42 | starterRef ! GameFinished 43 | context stop self 44 | case SetFinished(ponger, pinger) => 45 | context.become(manageGame(setCount - 1, starterRef)) 46 | ponger ! BecomePing(pinger) 47 | pinger ! BecomePong() 48 | } 49 | 50 | override def postStop() = { 51 | log.info("The game is over!") 52 | //context.system.shutdown() 53 | } 54 | } 55 | 56 | -------------------------------------------------------------------------------- /src/test/scala/lectures/check/TableStyleScalaCheckTest.scala: -------------------------------------------------------------------------------- 1 | package lectures.check 2 | 3 | import org.scalatest.{OutcomeOf, Matchers, WordSpec} 4 | import org.scalatest.prop.PropertyChecks 5 | 6 | class Fraction(n: Int, d: Int) { 7 | 8 | require(d != 0) 9 | require(d != Integer.MIN_VALUE) 10 | require(n != Integer.MIN_VALUE) 11 | 12 | val numer = if (d < 0) -1 * n else n 13 | val denom = d.abs 14 | 15 | override def toString = numer + " / " + denom 16 | } 17 | 18 | class TableStyleScalaCheckTest extends WordSpec with PropertyChecks with Matchers with OutcomeOf { 19 | 20 | "Fraction" should { 21 | "work correctly" when { 22 | "numerator and denominator are correct" in { 23 | 24 | forAll { (n: Int, d: Int) => 25 | println(s"n == $n and d == $d ") 26 | whenever(d != 0 && d != Integer.MIN_VALUE 27 | && n != Integer.MIN_VALUE) { 28 | 29 | val f = new Fraction(n, d) 30 | println(s"do a fraction $f") 31 | 32 | if (n < 0 && d < 0 || n > 0 && d > 0) 33 | f.numer should be > 0 34 | else if (n != 0) 35 | f.numer should be < 0 36 | else 37 | f.numer should be === 0 38 | 39 | f.denom should be > 0 40 | } 41 | } 42 | } 43 | } 44 | "produce IllegalArgumentException" when { 45 | "illegal input has been presented" in { 46 | val invalidCombos = 47 | Table( 48 | ("n", "d"), 49 | (Integer.MIN_VALUE, Integer.MIN_VALUE), 50 | (1, Integer.MIN_VALUE), 51 | (Integer.MIN_VALUE, 1), 52 | (Integer.MIN_VALUE, 0), 53 | (1, 0) 54 | ) 55 | 56 | // val o = outcomeOf{"blaa" shouldNot be ("blaa")} 57 | 58 | forAll(invalidCombos) { (n: Int, d: Int) => 59 | an[IllegalArgumentException] should be thrownBy { 60 | new Fraction(n, d) 61 | } 62 | } 63 | } 64 | } 65 | } 66 | } 67 | 68 | -------------------------------------------------------------------------------- /src/main/scala/lectures/akka/chat/Hub.scala: -------------------------------------------------------------------------------- 1 | package lectures.akka.chat 2 | 3 | import akka.actor.typed.scaladsl.AbstractBehavior 4 | import akka.actor.typed.{ActorRef, ActorSystem, Behavior, scaladsl} 5 | import akka.{actor => untyped} 6 | import com.typesafe.config.Config 7 | import com.typesafe.scalalogging.LazyLogging 8 | import untyped.BootstrapSetup 9 | import untyped.typed.scaladsl.ActorContext 10 | import untyped.typed.scaladsl.Behaviors 11 | 12 | object Hub extends LazyLogging { 13 | sealed trait Message 14 | 15 | final case class GetChats(session: ActorRef[Session.Message]) extends Message 16 | final case class Connect(name: String, login: String, session: ActorRef[Session.Message]) extends Message 17 | final case class NewSession(respond: ActorRef[ActorRef[Session.Message]]) extends Message 18 | final case class NewChat(name: String) extends Message 19 | 20 | 21 | def apply(name: String = "chat-hub", config: Option[Config] = None) = 22 | config.fold(ActorSystem(behaviour, name))(ActorSystem(behaviour, name, _)) 23 | 24 | def behaviour: Behavior[Message] = Behaviors.setup(new Behave(_)) 25 | 26 | 27 | class Behave(ctx: ActorContext[Message]) extends AbstractBehavior[Message] { 28 | var chats = Map.empty[String, ActorRef[Chat.Message]] 29 | def onMessage(msg: Message): Behavior[Message] = { 30 | msg match { 31 | case GetChats(session) => session ! Session.ChatList(chats.keys.toList) 32 | case Connect(name, login, session) => 33 | chats.get(name).foreach { chat => 34 | chat ! Chat.Connect(login, session) 35 | session ! Session.Connected(name, login, chat) 36 | } 37 | case NewSession(respond) => 38 | logger.info("new client connected") 39 | respond ! ctx.spawnAnonymous(Session.initial) 40 | case NewChat(name) => 41 | chats += name -> ctx.spawn(Chat.behavior(name), s"chat-$name") 42 | } 43 | Behaviors.same 44 | } 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/main/scala/java2scala/shop/Shop.scala: -------------------------------------------------------------------------------- 1 | package java2scala.shop 2 | import java.util.concurrent.Executors 3 | 4 | import akka.actor.ActorSystem 5 | import akka.http.scaladsl.Http 6 | import akka.http.scaladsl.server.Route 7 | import akka.stream.ActorMaterializer 8 | import cats.effect.{ExitCode, IO, IOApp, Resource} 9 | import java2scala.shop.http.{greeterHttp, resourceHttp} 10 | 11 | import scala.concurrent.ExecutionContext 12 | import cats.implicits._ 13 | import akka.http.scaladsl.server.Directives._ 14 | 15 | object Shop extends IOApp { 16 | 17 | def system: IO[ActorSystem] = IO(ActorSystem()) 18 | 19 | def runServerAndSystem(route: Route)(implicit system: ActorSystem): IO[Unit] = 20 | for { 21 | binding <- IO.fromFuture(IO { 22 | implicit val mat = ActorMaterializer() 23 | Http().bindAndHandle(route, "0.0.0.0", 8080) 24 | }) 25 | res <- IO(println(binding)) 26 | } yield res 27 | 28 | val blocking: Resource[IO, ExecutionContext] = 29 | Resource 30 | .make(IO(Executors.newCachedThreadPool()))(exec => IO(exec.shutdown())) 31 | .map(ExecutionContext.fromExecutor) 32 | 33 | def run(args: List[String]): IO[ExitCode] = 34 | blocking.use { blockingCS => 35 | for { 36 | cartStore <- IOCartStore.create 37 | productStore <- SimpleStore.fromResource[Product]("/shop/products.json", blockingCS) 38 | userStore <- SimpleStore.fromResource[User]("/shop/users.json", blockingCS) 39 | productRoute = resourceHttp.route("product", productStore) 40 | userRoute = resourceHttp.route("user", userStore) 41 | implicit0(sys: ActorSystem) <- system 42 | greeting <- Greeting.greeting(sys) 43 | helloRoute = greeterHttp.route(greeting) 44 | _ <- runServerAndSystem(productRoute ~ userRoute ~ helloRoute) 45 | _ <- IO.never 46 | } yield ExitCode.Success 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/scala/java2scala/shop/ProductStore.scala: -------------------------------------------------------------------------------- 1 | package java2scala.shop 2 | import java.io.{BufferedReader, InputStreamReader} 3 | import java.util.UUID 4 | 5 | import akka.stream.scaladsl.Source 6 | import cats.effect.{ContextShift, IO} 7 | import io.circe.parser._ 8 | 9 | import scala.collection.JavaConverters._ 10 | import cats.implicits._ 11 | 12 | import scala.concurrent.ExecutionContext 13 | 14 | trait ProductStore { 15 | def all: IO[List[Product]] 16 | 17 | def getById(id: UUID): IO[Option[Product]] 18 | 19 | def byId(id: UUID): IO[Product] = getById(id).flatMap(_.liftTo[IO](ProductNotFound(id))) 20 | // def byId(id: UUID): IO[Product] = getById(id).flatMap{ 21 | // case Some(product) => IO.pure(product) 22 | // case None => IO.raiseError(ProductNotFound(id)) 23 | // } 24 | } 25 | 26 | object ProductStore { 27 | private class ListStore(products: List[Product], byIdMap: Map[UUID, Product]) extends ProductStore { 28 | def all: IO[List[Product]] = IO.pure(products) 29 | def getById(id: UUID): IO[Option[Product]] = IO.pure(byIdMap.get(id)) 30 | } 31 | 32 | private def makeListStore(products: List[Product]): IO[ListStore] = 33 | products 34 | .groupBy(_.id) 35 | .toList 36 | .traverse { 37 | case (id, List(product)) => IO.pure(id -> product) 38 | case (id, _) => IO.raiseError(MultipleProducts(id)) 39 | } 40 | .map(byId => new ListStore(products, byId.toMap)) 41 | 42 | def fromResource(name: String, blocking: ExecutionContext)(implicit basic: ContextShift[IO]): IO[ProductStore] = { 43 | val read: IO[List[Product]] = IO { 44 | val stream = getClass.getResourceAsStream(name) 45 | val reader = new BufferedReader(new InputStreamReader(stream)) 46 | val total = reader.lines().iterator.asScala.mkString 47 | decode[List[Product]](total): Either[Throwable, List[Product]] 48 | }.rethrow 49 | 50 | for { 51 | _ <- IO.shift(blocking) 52 | products <- read 53 | store <- makeListStore(products) 54 | _ <- IO.shift(basic) 55 | } yield store 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/scala/lectures/operators/EvaluateOptimization.scala: -------------------------------------------------------------------------------- 1 | package lectures.operators 2 | 3 | import lectures.functions.Data 4 | 5 | /** 6 | * В задачке из lectures.functions.Computations мы реализовали 7 | * один и тот же метод 3-мя разными способами 8 | * 9 | * Пришло время оценить, насколько разные имплементации 10 | * отличаются друг от друга по производительности 11 | * 12 | * Для этого 13 | * * в классах CurriedComputation и FunctionalComputation уберите extends App, оставьте extends Data 14 | * * раскомментируйте код, выполните в циклах вызов 3-х имплементаций, 15 | * * оцените разницу во времени выполнения и объясните ее происхожение 16 | * 17 | */ 18 | object EvaluateOptimization extends App with Data { 19 | 20 | val computationStartTimestamp = System.currentTimeMillis() 21 | 22 | // // ВЫПОЛНИТЬ В ЦИКЛЕ ОТ 1 ДО 100 Computation.computation 23 | // for (??? <- ???) { 24 | // ??? 25 | // } 26 | // 27 | // println("Elapsed time in computation(): " + (System.currentTimeMillis() - computationStartTimestamp)) 28 | // 29 | // 30 | // 31 | // val partiallyAppliedStartTimestamp = System.currentTimeMillis() 32 | // 33 | // // ВЫПОЛНИТЬ В ЦИКЛЕ ОТ 1 ДО 100 CurriedComputation.partiallyAppliedCurriedFunction 34 | // for (??? <- ???) { 35 | // ??? 36 | // } 37 | // 38 | // val partiallyAppliedDuration = System.currentTimeMillis() - partiallyAppliedStartTimestamp 39 | // println("Elapsed time in partiallyAppliedCurriedFunction(): " + partiallyAppliedDuration) 40 | // 41 | // 42 | // 43 | // val filterAppliedStartTimestamp = System.currentTimeMillis() 44 | // 45 | // // ВЫПОЛНИТЬ В ЦИКЛЕ ОТ 1 ДО 100 FunctionalComputation.filterApplied 46 | // for (??? <- ???) { 47 | // ??? 48 | // } 49 | // 50 | // val filterAppliedDuration = System.currentTimeMillis() - filterAppliedStartTimestamp 51 | // println("Elapsed time in filterApplied():" + filterAppliedDuration) 52 | // 53 | // // ВЫВЕСТИ РАЗНИЦУ В ПРОДОЛЖИТЕЛЬНОСТИ ВЫПОЛНЕНИЯ МЕЖДУ КАРРИРОВАННОЙ ВЕРСИЕЙ 54 | // // И ФУНКЦИОНАЛЬНОЙ 55 | // 56 | // val diff = ??? 57 | // 58 | // println(s"Difference is about $diff milliseconds") 59 | } 60 | 61 | -------------------------------------------------------------------------------- /src/test/scala/java2scala/homeworks/LinkedMapSpec.scala: -------------------------------------------------------------------------------- 1 | package java2scala.homeworks 2 | 3 | import org.scalatest.{Matchers, PropSpec} 4 | import org.scalatest.prop._ 5 | 6 | class LinkedMapSpec extends PropSpec with Matchers with PropertyChecks { 7 | property("empty map contains nothing") { 8 | forAll { key: Int => 9 | val empty = LinkedMap[Int, String]() 10 | empty.contains(key) shouldBe false 11 | empty(key) shouldBe None 12 | } 13 | } 14 | 15 | property("singleton map contains it's key") { 16 | forAll { (key1: Int, value: String, key2: Int) => 17 | val singleton = LinkedMap[Int, String](key1 -> value) 18 | singleton.contains(key1) shouldBe true 19 | singleton(key1) shouldBe Some(value) 20 | singleton.contains(key2) shouldBe (key1 == key2) 21 | } 22 | } 23 | 24 | property("deleted data should not be found") { 25 | forAll { (elems: List[(String, Int)], key: String) => 26 | val removed = LinkedMap(elems: _*).delete(key) 27 | removed.contains(key) shouldBe false 28 | removed(key) shouldBe None 29 | } 30 | } 31 | 32 | property("updated element should always be in map") { 33 | forAll { (elems: List[(Int, String)], key: Int, value: String) => 34 | val updated = LinkedMap(elems: _*)(key) = value 35 | updated.contains(key) shouldBe true 36 | updated(key) shouldBe Some(value) 37 | } 38 | } 39 | 40 | property("maps are equivalent when non repeating lists are quivalent") { 41 | forAll { (m1: Map[String, String], m2: Map[String, String]) => 42 | val l1 = m1.toList 43 | val l2 = m2.toList 44 | (LinkedMap(l1: _*) == LinkedMap(l2: _*)) shouldBe (l1 == l2) 45 | } 46 | } 47 | 48 | property("mapped map should be correct") { 49 | forAll { (l: List[(String, Int)], f: Int => String) => 50 | LinkedMap(l: _*).mapValues(f) shouldBe LinkedMap(l.map { case (k, v) => k -> f(v) }: _*) 51 | } 52 | } 53 | 54 | property("key-value mapped map should be correct") { 55 | forAll { (l: List[(Int, String)], f: (Int, String) => Double) => 56 | LinkedMap(l: _*).mapWithKey(f) shouldBe LinkedMap(l.map { case (k, v) => k -> f(k, v) }: _*) 57 | } 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/main/scala/java2scala/Lecture3.scala: -------------------------------------------------------------------------------- 1 | package java2scala 2 | 3 | object Lecture3 extends App { 4 | import Color._ 5 | sealed trait Color { 6 | def name: String = this match { 7 | case Red => "red" 8 | case Blue => "blue" 9 | case Green => "green" 10 | } 11 | } 12 | 13 | object Color { 14 | case object Red extends Color 15 | case object Blue extends Color 16 | case object Green extends Color 17 | } 18 | 19 | // def main(args: Array[String]): Unit = { 20 | // println(Red.name) 21 | // println(Green.name) 22 | // } 23 | // val VeryRed = Mix(Red, Red) 24 | val veryRed = Mix(Red, Red) 25 | 26 | sealed trait GenColor { 27 | def show: String = this match { 28 | case White => "white" 29 | case Black => "black" 30 | case Base(gen) => s"base color ${gen.name}" 31 | case Mix(Green, Green) => s"the greenest" 32 | case `veryRed` => s"the redest" 33 | case Mix(col1, col2) if col1 == col2 => s"very very $col1" 34 | case Mix(Blue, col @ (Red | Green)) => s"little bit sad ${col.name}" 35 | case Mix(first, second) => s"mix of ${first.name} and ${second.name}" 36 | } 37 | } 38 | 39 | case object White extends GenColor 40 | case object Black extends GenColor 41 | case class Base(color: Color) extends GenColor 42 | case class Mix(first: Color, second: Color) extends GenColor 43 | 44 | // case class Lol(override val color: Color) extends Base(color) 45 | 46 | println(White.show) 47 | println(Base(Green).show) 48 | println(Mix(Red, Blue).show) 49 | println(Mix(Red, Red).show) 50 | println(Red == 2) 51 | println(Mix(Red, Red).show) 52 | println(Red == 2) 53 | 54 | println(Mix(Blue, Red).show) 55 | println(Mix(Green, Green).show) 56 | 57 | println(null == Red) 58 | println(Red == null) 59 | println(Mix(Red, Red).show) 60 | println(Red == 2) 61 | println(Mix(Red, Red).show) 62 | println(Red == 2) 63 | 64 | println(100000 == (100000: Integer)) 65 | println(100000 eq (100000: Integer)) 66 | println(127 eq (127: Integer)) 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/main/scala/lectures/features/ApplyAndUnapplyExample.scala: -------------------------------------------------------------------------------- 1 | package lectures.features 2 | 3 | trait Figure { 4 | val color: String 5 | } 6 | 7 | case class Cube(color: String = "Red") extends Figure 8 | 9 | case class Pyramid(color: String = "Yellow") extends Figure 10 | 11 | case class Sphere(color: String = "Green") extends Figure 12 | 13 | case class ToyPuzzle(figure1: Figure, figure2: Figure, figure3: Figure) 14 | 15 | object ToyPuzzle { 16 | def apply(): ToyPuzzle = new ToyPuzzle(Cube(), Pyramid(), Sphere()) 17 | 18 | // def unapply(puzzle: ToyPuzzle): Option[(String, String, String)] = 19 | // Some((puzzle.figure1.color, puzzle.figure2.color, puzzle.figure2.color)) 20 | } 21 | 22 | object DefaultPuzzle { 23 | 24 | def apply(): ToyPuzzle = new ToyPuzzle(Cube(), Pyramid(), Sphere()) 25 | 26 | def unapply(puzzle: ToyPuzzle): Option[(Figure, Figure, Figure)] = { 27 | val ToyPuzzle(f1, f2, f3) = puzzle 28 | if (f1.isInstanceOf[Cube] && f2.isInstanceOf[Pyramid] && f3.isInstanceOf[Sphere]) 29 | Some(f1, f2, f3) 30 | else None 31 | } 32 | } 33 | 34 | object OR { 35 | def unapply(puzzle: ToyPuzzle): Option[(Figure, Figure)] = { 36 | val ToyPuzzle(f1, f2, f3) = puzzle 37 | if (f1.isInstanceOf[Cube] && f2.isInstanceOf[Pyramid]) 38 | Some(f1, f2) 39 | else None 40 | } 41 | } 42 | 43 | object Main extends App { 44 | 45 | val p1 = ToyPuzzle(Sphere(), Sphere(), Sphere()) 46 | val p2 = ToyPuzzle(Pyramid(), Sphere(), Cube()) 47 | val p3 = ToyPuzzle() 48 | val badPuzzle = ToyPuzzle(Cube(), Pyramid(), Pyramid()) 49 | 50 | def matchPuzzle(puzzle: ToyPuzzle) = puzzle match { 51 | case ToyPuzzle(f1, f2, f3) if (f1 == f2) && (f1 == f3) => println("Toy puzzle") 52 | case OR(cube, pyramid) => print(cube) 53 | case DefaultPuzzle(cube1, pyramid1, sphere1) => print(cube1) 54 | case ToyPuzzle(Pyramid(_), _, _) => print("Puzzle with pyramid in front ") 55 | //case puzzle => //DOn't forget to put all possible cases 56 | } 57 | 58 | // Assignment 59 | val ToyPuzzle(cube, pyramid, sphere) = ToyPuzzle() 60 | println(cube) 61 | println(pyramid) 62 | println(sphere) 63 | 64 | // Pattern Match 65 | matchPuzzle(p1) 66 | matchPuzzle(p2) 67 | matchPuzzle(p3) 68 | //matchPuzzle(badPuzzle) 69 | } 70 | 71 | -------------------------------------------------------------------------------- /src/test/scala/lectures/collections/CherryTreeSuite.scala: -------------------------------------------------------------------------------- 1 | package lectures.collections 2 | 3 | import org.scalactic.anyvals.PosZInt 4 | import org.scalatest.prop.PropertyChecks 5 | import org.scalatest.{FlatSpec, Matchers, PropSpec} 6 | 7 | class CherryTreeSuite extends FlatSpec with PropertyChecks with Matchers { 8 | 9 | override implicit val generatorDrivenConfig = PropertyCheckConfiguration(sizeRange = 1000) 10 | 11 | "Cherry tree" should "append element" in forAll { (x: Int, xs: Vector[Int]) => 12 | val tree = CherryTree(xs: _*) 13 | tree.append(x) shouldBe CherryTree(xs :+ x: _*) 14 | } 15 | 16 | it should "prepend element" in forAll { (x: Int, xs: Vector[Int]) => 17 | val tree = CherryTree(xs: _*) 18 | tree.prepend(x) shouldBe CherryTree(x +: xs: _*) 19 | } 20 | 21 | it should "get tail" in forAll { xs: Vector[Int] => 22 | val tree = CherryTree(xs: _*) 23 | if (xs.isEmpty) an[UnsupportedOperationException] should be thrownBy tree.tail 24 | else xs.tail shouldBe CherryTree(xs.tail: _*) 25 | } 26 | 27 | it should "get head" in forAll { xs: Vector[Int] => 28 | val tree = CherryTree(xs: _*) 29 | if (xs.isEmpty) an[NoSuchElementException] should be thrownBy tree.head 30 | else xs.head shouldBe xs.head 31 | } 32 | 33 | it should "get init" in forAll { xs: Vector[Int] => 34 | val tree = CherryTree(xs: _*) 35 | if (xs.isEmpty) an[UnsupportedOperationException] should be thrownBy tree.init 36 | else xs.tail shouldBe CherryTree(xs.tail: _*) 37 | } 38 | 39 | it should "get last" in forAll { xs: Vector[Int] => 40 | val tree = CherryTree(xs: _*) 41 | if (xs.isEmpty) an[NoSuchElementException] should be thrownBy tree.last 42 | else xs.head shouldBe xs.head 43 | } 44 | 45 | it should "get element by index" in forAll { (xs: Vector[Int], i: Int) => 46 | whenever(i < xs.size && i >= 0) { 47 | val tree = CherryTree(xs: _*) 48 | tree(i) shouldBe xs(i) 49 | } 50 | } 51 | 52 | it should "concat elements" in forAll { (xs: List[Int], ys: List[Int]) => 53 | CherryTree(xs: _*) concat CherryTree(ys: _*) shouldBe CherryTree(xs ++ ys: _*) 54 | } 55 | 56 | it should "get correct size" in forAll { (xs: Vector[Int]) => 57 | CherryTree(xs: _*).size shouldBe xs.size 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/test/scala/lectures/collections/MergeSortImplWordSpecTest.scala: -------------------------------------------------------------------------------- 1 | package lectures.collections 2 | 3 | import org.scalatest.{BeforeAndAfter, GivenWhenThen, Matchers, WordSpec} 4 | 5 | /** 6 | * 7 | * 8 | * 9 | */ 10 | class MergeSortImplWordSpecTest extends WordSpec with Matchers with GivenWhenThen with BeforeAndAfter{ //BeforeAndAfterAll 11 | 12 | before { 13 | // here we can put initialization of some static resources 14 | // or resources that are accessible by tests 15 | } 16 | 17 | after{ 18 | // some finalization 19 | } 20 | def seqTest(f: (Seq[Int]) => Unit) = f(Seq(1, 2, 3, 4, 5, 6, 7, 8, 9)) 21 | 22 | "A seq" when { 23 | "shuffled" should { 24 | "not be equal to sorted seq" in seqTest { defaultSeq => 25 | val shuffled = scala.util.Random.shuffle(defaultSeq) 26 | shuffled should not equal defaultSeq 27 | } 28 | } 29 | "sorted with an Impl" should { 30 | 31 | "be equal to already sorted seq" in pendingUntilFixed { 32 | seqTest { defaultSeq => { 33 | val shuffled = scala.util.Random.shuffle(defaultSeq) 34 | shuffled should not equal defaultSeq 35 | 36 | val sorted = MergeSortImpl.mergeSort(shuffled) 37 | sorted shouldBe defaultSeq 38 | } 39 | } 40 | } 41 | 42 | "have the same size as original seq" in pendingUntilFixed { 43 | seqTest { defaultSeq => { 44 | val shuffled = scala.util.Random.shuffle(defaultSeq) 45 | shuffled should not equal defaultSeq 46 | 47 | val sorted = MergeSortImpl.mergeSort(shuffled) 48 | sorted should not equal shuffled 49 | sorted should have size shuffled.size 50 | } 51 | } 52 | } 53 | 54 | "throw exception" in pendingUntilFixed { 55 | seqTest { defaultSeq => { 56 | When("index requested exceed it's size") 57 | val shuffled = scala.util.Random.shuffle(defaultSeq) 58 | shuffled should not equal defaultSeq 59 | 60 | intercept[IndexOutOfBoundsException] { 61 | val sorted = MergeSortImpl.mergeSort(shuffled) 62 | sorted should not equal shuffled 63 | sorted(shuffled.length) 64 | } 65 | } 66 | } 67 | } 68 | } 69 | } 70 | } 71 | 72 | -------------------------------------------------------------------------------- /src/main/scala/lectures/functions/Computations.scala: -------------------------------------------------------------------------------- 1 | package lectures.functions 2 | 3 | /** 4 | * 5 | * В объекте 'Computation' в методе computation сравниваются 2 массива. 6 | * Результатом сравнения будет массив, содержащий слова, принадлежащие обоим массивам 7 | * В данном случа результатом будет массив, содержащий 2 элемента Array("Клара", "Карла") 8 | * 9 | * С помощью Thread.sleep имитируется прододжительное вычисление 10 | */ 11 | trait Data { 12 | val filterData = "Клара у Карла украла корралы, Карл у Клары украл кларнет" 13 | val dataArray = "Клара Цеткин обожала Карла Маркса".split(" ") 14 | } 15 | 16 | object Computation extends App with Data { 17 | 18 | def computation(filterData: String, dataProducer: Array[String]): Array[String] = { 19 | //EMULATE HEAVY LOAD 20 | Thread.sleep(10) 21 | //PRODUCE WORDS ARRAY FROM A STRING 22 | val filterArray = filterData.split(" ") 23 | 24 | //EMULATE HEAVY LOAD 25 | Thread.sleep(100) 26 | // LEAVE ONLY EQUAL WORDS IN BOTH ARRAYS 27 | dataProducer.filter(dataItem => filterArray.contains(dataItem)) 28 | } 29 | 30 | val result = computation(filterData, dataArray) 31 | result.foreach(println) 32 | } 33 | 34 | /** 35 | * Допишите curriedComputation, так, что бы после вызова partiallyAppliedCurriedFunction 36 | * результат был бы тем же, что и в предыдущем случае 37 | * 38 | * Раскомментируйте последнюю строчку 39 | * 40 | * Какой тип имеет partiallyAppliedCurriedFunction - ? 41 | */ 42 | object CurriedComputation extends App with Data { 43 | 44 | def curriedComputation(filterData: String)(dataProducer: Array[String]): Array[String] = ??? 45 | 46 | val partiallyAppliedCurriedFunction = ??? 47 | 48 | //val result = partiallyAppliedCurriedFunction(dataArray) 49 | //result.foreach(println) 50 | } 51 | 52 | /** 53 | * Допишите реализации методов так, что бы результат совпадал с предыдущими. 54 | * 55 | * При этом постарайтесь минимизировать количество разбиений строки filterData на отдельные слова. 56 | */ 57 | object FunctionalComputation extends App with Data { 58 | 59 | def functionalComputation(filterData: String): (Array[String]) => Array[String] = ??? 60 | 61 | val filterApplied = functionalComputation(???) 62 | 63 | val result = filterApplied(???) 64 | result.foreach(println) 65 | } 66 | -------------------------------------------------------------------------------- /src/main/scala/java2scala/homeworks/LinkedMap.scala: -------------------------------------------------------------------------------- 1 | package java2scala.homeworks 2 | 3 | sealed trait LinkedMap[K, V] extends Traversable[(K, V)] { 4 | 5 | /** должен вернуть `false` если коллекция содержит хотя бы один элемент */ 6 | override def isEmpty: Boolean = ??? 7 | 8 | /** должен вернуть `true` если коллекция содержит ключ `key` */ 9 | def contains(key: K): Boolean = ??? 10 | 11 | /** возвращает Some со значением значения, если коллекция содержит ключ `key` 12 | * и None если не содержит */ 13 | def apply(key: K): Option[V] = ??? 14 | 15 | /** возвращает новый LinkedMap[K, V], 16 | * в котором добавлено или изменено значение для ключа `key` на `value` */ 17 | def update(key: K, value: V): LinkedMap[K, V] = ??? 18 | 19 | /** возвращает новый LinkedMap[K, V] 20 | * состоящий из тех же позиций, но в обратном порядке */ 21 | def reverse: LinkedMap[K, V] = ??? 22 | 23 | /** создаёт новый LinkedMap, состоящий из элементов `this` и `other` 24 | * если какой-то ключ встречается в обеих коллекциях, 25 | * может быть выбрано любое значение*/ 26 | def ++(other: LinkedMap[K, V]): LinkedMap[K, V] = ??? 27 | 28 | /** создаёт новый LinkedMap , где ко всем значениям применена заданная функция */ 29 | def mapValues[W](f: V => W): LinkedMap[K, W] = ??? 30 | 31 | /** создаёт новый LinkedMap , где ко всем значениям применена заданная функция, 32 | * учитывающая ключ*/ 33 | def mapWithKey[W](f: (K, V) => W): LinkedMap[K, W] = ??? 34 | 35 | /** конструирует новый LinkedMap, содеоржащий все записи текущего, кроме заданного ключа */ 36 | def delete(key: K): LinkedMap[K, V] = ??? 37 | 38 | /** применяет действие `action` с побочным эффектом ко всем элементам коллекции */ 39 | def foreach[U](action: ((K, V)) => U): Unit = ??? 40 | } 41 | 42 | object LinkedMap { 43 | 44 | /** конструирует новый `LinkedMap` на основании приведённых элементов 45 | * каждый ключ должен присутствовать в результате только один раз 46 | * если в исходных данныхх ключ встречается несколько раз, может быть 47 | * выбрано любое из значений 48 | */ 49 | def apply[K, V](kvs: (K, V)*): LinkedMap[K, V] = ??? 50 | 51 | final case class Cons[K, V](key: K, value: V, rest: LinkedMap[K, V]) extends LinkedMap[K, V] 52 | final case class Empty[K, V]() extends LinkedMap[K, V] 53 | } 54 | -------------------------------------------------------------------------------- /src/main/scala/lectures/oop/types/Binder.scala: -------------------------------------------------------------------------------- 1 | package lectures.oop.types 2 | 3 | import scala.reflect.runtime.{universe => ru} 4 | import ru._ 5 | 6 | 7 | /** 8 | * Идем дальше. 9 | * Определим трейт, который будет обозначать группу методов 10 | * для создания инстансов коллекций 11 | * При этом нам пока не важно, каких 12 | * 13 | */ 14 | 15 | trait Binder3[M[_]] { 16 | def bind[T](item: T): M[T] 17 | def fill[T](count: Int, item: T): M[T] 18 | } 19 | 20 | class SeqBinder extends Binder3[Seq] { 21 | override def bind[T](item: T): Seq[T] = Seq(item) 22 | override def fill[T](count: Int, item: T): Seq[T] = Seq.fill(count)(item) 23 | def badFill(count: Int, item: (T) forSome {type T}): Seq[_] = Seq.fill(count)(item) 24 | } 25 | 26 | class SetBinder extends Binder3[Set] { 27 | override def bind[T](item: T): Set[T] = Set(item) 28 | override def fill[T](count: Int, item: T): Set[T] = Set(Seq.fill(count)(item): _*) 29 | } 30 | 31 | class ConcreteSetBinder[C] extends Binder3[Set] { 32 | def bind[T](item: T): Set[T] = Set(item) 33 | def concreteBind(item: C): Set[C] = Set(item) 34 | override def fill[T](count: Int, item: T): Set[T] = Set(Seq.fill(count)(item): _*) 35 | } 36 | 37 | object Binder4 { 38 | trait Builder[M[_]] { 39 | def build[T](item: T): M[T] 40 | } 41 | 42 | implicit var seqBuilder = new Builder[Seq] { 43 | override def build[T](item: T): Seq[T] = Seq(item) 44 | } 45 | implicit val setBuilder = new Builder[Set] { 46 | override def build[T](item: T): Set[T] = Set(item) 47 | } 48 | 49 | def bind[T, B[_]](item: T)(implicit builder: Builder[B]): B[T] = { 50 | builder.build(item) 51 | } 52 | 53 | def fill[T, B[_]](count: Int, item: T)(implicit builder: Builder[B]) = ??? 54 | } 55 | 56 | object BinderExample extends App { 57 | import Binder4._ 58 | 59 | def withType[T:TypeTag, ClassTag](t: T): Unit = { 60 | val tt = typeOf[T] 61 | println(tt.typeParams) 62 | } 63 | 64 | val strBinder = new ConcreteSetBinder[String]() 65 | strBinder 66 | 67 | withType(new SeqBinder) 68 | (new SeqBinder).bind(100) 69 | (new SetBinder).bind(100) 70 | (new SeqBinder).fill(10, 100) 71 | (new SeqBinder).badFill(10, 100) 72 | (new SetBinder).fill(10, 100) 73 | //но вот так мы сделать не можем 74 | //val b = new Binder3[List]() 75 | 76 | val s = bind[Int, Set](10) 77 | 78 | print(s) 79 | } 80 | -------------------------------------------------------------------------------- /src/test/scala/java2scala/homeworks/MapOperationsSuite.scala: -------------------------------------------------------------------------------- 1 | package java2scala.homeworks 2 | 3 | import org.scalatest.prop.PropertyChecks 4 | import org.scalatest.{FlatSpec, Matchers} 5 | 6 | import MapOperations._ 7 | 8 | class MapOperationsSuite extends FlatSpec with Matchers with PropertyChecks { 9 | "map union" should "produce map containing all the keys" in 10 | forAll { (m1: Map[Int, Int], m2: Map[Int, String]) => 11 | (m1 union m2).keySet shouldBe (m1.keySet | m2.keySet) 12 | } 13 | 14 | it should "have elements of left parameter as left" in 15 | forAll { (m1: Map[Int, Int], m2: Map[Int, String]) => 16 | (m1 union m2).flatMap { case (k, v) => v.left.map(k -> _) } shouldBe m1 17 | } 18 | 19 | it should "have elements of right parameter as right" in 20 | forAll { (m1: Map[Int, Int], m2: Map[Int, String]) => 21 | (m1 union m2).flatMap { case (k, v) => v.right.map(k -> _) } shouldBe m2 22 | } 23 | 24 | "map intersect" should "produce map containing common keys" in 25 | forAll { (m1: Map[Int, Int], m2: Map[Int, String]) => 26 | (m1 intersect m2).keySet shouldBe (m1.keySet & m2.keySet) 27 | } 28 | 29 | it should "elements of first parameters as first" in 30 | forAll { (m1: Map[Int, Int], m2: Map[Int, String]) => 31 | (m1 intersect m2).mapValues(_._1) shouldBe m1.filterKeys(m2.contains) 32 | } 33 | 34 | it should "elements of second parameters as second" in 35 | forAll { (m1: Map[Int, Int], m2: Map[Int, String]) => 36 | (m1 intersect m2).mapValues(_._2) shouldBe m2.filterKeys(m1.contains) 37 | } 38 | 39 | "map difference" should "produce map containing exclusive keys" in 40 | forAll { (m1: Map[Int, Int], m2: Map[Int, String]) => 41 | (m1 difference m2).keySet shouldBe ((m1.keySet diff m2.keySet) ++ (m2.keySet diff m1.keySet)) 42 | } 43 | 44 | it should "contain elements of left parameter as left" in 45 | forAll { (m1: Map[Int, Int], m2: Map[Int, String]) => 46 | (m1 difference m2).flatMap { case (k, v) => v.left.toOption.map(k -> _) } shouldBe m1.filterKeys(!m2.contains(_)) 47 | } 48 | 49 | it should "contain elements of right parameter as left" in 50 | forAll { (m1: Map[Int, Int], m2: Map[Int, String]) => 51 | (m1 difference m2).flatMap { case (k, v) => v.right.toOption.map(k -> _) } shouldBe m2.filterKeys(!m1.contains(_)) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/scala/java2scala/lecture5.sc: -------------------------------------------------------------------------------- 1 | import scala.collection.mutable._ 2 | import scala.util.Random 3 | 4 | val lls = List(List(1, 2), List(3, 4, 5), List(2)) 5 | lls.flatten 6 | //lls.foldLeft(List[Int]())(_ ::: _) 7 | val rand = new Random(123) 8 | val x = List.fill(10, 10)(rand.nextInt) 9 | val y = List.tabulate(10, 10)((i, j) => i * j) 10 | List(1, 2, 3).flatMap(i => Iterator.fill(i)(i)) 11 | 12 | List(1, 2, 3) ::: List(2, 3) 13 | List(1, 2, 3) ++ List(2, 3) 14 | List(1, 2, 3) ++ Vector(2, 3) ++ Iterator(3, 4) 15 | 16 | 17 | val u = Vector(1, 2, 3) 18 | 19 | 2 +: u 20 | 21 | 22 | 23 | 24 | List(List(List(List(1)))).flatten.flatten 25 | 26 | // 27 | //val u = List(1, 2, 3, 4) 28 | //List("asdf", "asd") 29 | //List() 30 | //List(1, "dwfsdfsf") 31 | //List("sdfsdf", (1, 2)) 32 | // 33 | //class X 34 | //val List(x, y, _*) = u 35 | // 36 | //List("sadsdfd", new X) 37 | // 38 | //List((1, 2), (3, 4)) 39 | //val s = List((1, 2), (3, "sdf")) 40 | // 41 | //s.head 42 | // 43 | //s.tail 44 | // 45 | //val vec = Vector(1, 2, 3, 4) 46 | //vec.head 47 | //vec.tail 48 | //u.filter(_ % 2 == 0) 49 | // 50 | //u.foldLeft(0)( (acc, elem) => acc + elem) 51 | //u.sum 52 | // 53 | //u.foldLeft("")( (acc, elem) => acc + "," + elem.toString) 54 | //u.foldLeft(("", false)){ case ((acc, seen), elem) => ( 55 | // acc + (if(seen) "," + elem.toString else ""), true ) 56 | //}._1 57 | //u.mkString 58 | //u.mkString(",") 59 | //u.mkString("List(", ",", ")") 60 | //u.scanLeft("")( (acc, elem) => acc + "," + elem.toString) 61 | // 62 | //u.take(2) 63 | //u.drop(2) 64 | // 65 | //u.drop(1) 66 | // 67 | //val empty = List() 68 | //empty.headOption 69 | //u.headOption 70 | // 71 | //empty.drop(1) 72 | // 73 | //u.map(_ * 2) 74 | //u.map(_ * 2).map(_ + 1) 75 | // 76 | //LinearSeq 77 | //IndexedSeq 78 | // 79 | //u(2) 80 | ////u(5) 81 | //u.lift(1) 82 | //u.lift(5) 83 | //u.iterator.map(_ * 2).filter( _ > 5).map( _ / 2).toList 84 | // 85 | //u.map(_.toString) 86 | //u.map(x => (x, x.toString)) 87 | // 88 | //val pf : PartialFunction[Int, String] = { 89 | // case 1 => "one" 90 | // case 2 => "two" 91 | //} 92 | // 93 | //pf.isDefinedAt(1) 94 | //pf.isDefinedAt(5) 95 | //pf.lift(1) 96 | //pf.lift(5) 97 | // 98 | //u.collect(pf) 99 | //u.collect{ 100 | // case 3 => "three" 101 | //} 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /src/main/scala/lectures/oop/BST.scala: -------------------------------------------------------------------------------- 1 | package lectures.oop 2 | 3 | 4 | /** 5 | * BSTImpl - это бинарное дерево поиска, содержащее только значения типа Int 6 | * 7 | * * Оно обладает следующими свойствами: 8 | * * * * * левое поддерево содержит значения, меньшие значения родителя 9 | * * * * * правое поддерево содержит значения, большие значения родителя 10 | * * * * * значения, уже присутствующие в дереве, в него не добавляются 11 | * * * * * пустые значения (null) не допускаются 12 | * 13 | * * Завершите реализацию методов кейс класс BSTImpl: 14 | * * * * * Трейт BST и BSTImpl разрешается расширять любым образом 15 | * * * * * Изменять сигнатуры классов и методов, данные в условии, нельзя 16 | * * * * * Постарайтесь не использовать var и мутабильные коллекции 17 | * * * * * В задаче про распечатку дерева, нужно раскомментировать и реализовать метод toString() 18 | * 19 | * * Для этой структуры нужно реализовать генератор узлов. 20 | * * Генератор: 21 | * * * * * должен создавать дерево, содержащее nodesCount узлов. 22 | * * * * * не должен использовать переменные или мутабильные структуры. 23 | * 24 | */ 25 | trait BST { 26 | val value: Int 27 | val left: Option[BST] 28 | val right: Option[BST] 29 | 30 | def add(newValue: Int): BST 31 | 32 | def find(value: Int): Option[BST] 33 | } 34 | 35 | case class BSTImpl(value: Int, 36 | left: Option[BSTImpl] = None, 37 | right: Option[BSTImpl] = None) extends BST { 38 | 39 | def add(newValue: Int): BST = ??? 40 | 41 | def find(value: Int): Option[BST] = ??? 42 | 43 | // override def toString() = ??? 44 | 45 | } 46 | 47 | object TreeTest extends App { 48 | 49 | val sc = new java.util.Scanner(System.in) 50 | val maxValue = 110000 51 | val nodesCount = sc.nextInt() 52 | 53 | val markerItem = (Math.random() * maxValue).toInt 54 | val markerItem2 = (Math.random() * maxValue).toInt 55 | val markerItem3 = (Math.random() * maxValue).toInt 56 | 57 | // Generate huge tree 58 | val root: BST = BSTImpl(maxValue / 2) 59 | val tree: BST = ??? // generator goes here 60 | 61 | // add marker items 62 | val testTree = tree.add(markerItem).add(markerItem2).add(markerItem3) 63 | 64 | // check that search is correct 65 | require(testTree.find(markerItem).isDefined) 66 | require(testTree.find(markerItem).isDefined) 67 | require(testTree.find(markerItem).isDefined) 68 | 69 | println(testTree) 70 | } -------------------------------------------------------------------------------- /src/main/scala/java2scala/tagless/Filter.scala: -------------------------------------------------------------------------------- 1 | package java2scala.tagless 2 | 3 | import java2scala.tagless.Filter.{And, ColorIs, PriceLT} 4 | import java2scala.tagless.OrFilter.Simple 5 | 6 | sealed trait Filter 7 | 8 | final case class Product( 9 | color: String, 10 | price: BigDecimal 11 | ) 12 | 13 | object Filter { 14 | final case class ColorIs(color: String) extends Filter 15 | final case class PriceLT(upper: BigDecimal) extends Filter 16 | final case class And(x: Filter, y: Filter) extends Filter 17 | 18 | def show(filter: Filter): String = filter match { 19 | case ColorIs(color) => s"color = $color" 20 | case PriceLT(upper) => s"price <= $upper" 21 | case And(x, y) => s"${show(x)} AND ${show(y)} " 22 | } 23 | 24 | def filter(flt: Filter)(product: Product): Boolean = flt match { 25 | case ColorIs(color) => product.color == color 26 | case PriceLT(upper) => product.price <= upper 27 | case And(x, y) => filter(x)(product) && filter(y)(product) 28 | } 29 | 30 | } 31 | 32 | sealed trait OrFilter 33 | 34 | object OrFilter extends App { 35 | final case class Simple(x: Filter) extends OrFilter 36 | final case class Or(x: OrFilter, y: OrFilter) extends OrFilter 37 | 38 | def show(flt: OrFilter): String = flt match { 39 | case Simple(x) => Filter.show(x) 40 | case Or(x, y) => s"${show(x)} OR ${show(y)}" 41 | } 42 | 43 | def filter(flt: OrFilter)(product: Product): Boolean = 44 | flt match { 45 | case Simple(x) => Filter.filter(x)(product) 46 | case Or(x, y) => filter(x)(product) || filter(y)(product) 47 | } 48 | 49 | } 50 | 51 | object FilterApp extends App { 52 | lazy val isRed: Filter = ColorIs("red") 53 | lazy val priceLT100 = PriceLT(100) 54 | lazy val combined = And(isRed, priceLT100) 55 | 56 | println(Filter.show(isRed)) 57 | println(Filter.show(priceLT100)) 58 | println(Filter.show(combined)) 59 | 60 | lazy val products = List(Product("yellow", 50), Product("red", 50), Product("red", 200)) 61 | println(products.filter(Filter.filter(isRed))) 62 | println(products.filter(Filter.filter(priceLT100))) 63 | println(products.filter(Filter.filter(combined))) 64 | 65 | lazy val fltOr: OrFilter = OrFilter.Or(Simple(combined), Simple(ColorIs("yellow"))) 66 | println("-" * 10 + "[ OR ]" + "-" * 10) 67 | 68 | println(OrFilter.show(fltOr)) 69 | 70 | println(products.filter(OrFilter.filter(fltOr))) 71 | } 72 | -------------------------------------------------------------------------------- /src/main/scala/lectures/concurrent/akka/Worker.scala: -------------------------------------------------------------------------------- 1 | package lectures.concurrent.akka 2 | 3 | import akka.actor.{Actor, ActorLogging, ActorRef, Props} 4 | import scala.concurrent.duration._ 5 | 6 | object Worker { 7 | def props(pingDelay: Long, breakDelay: Long, pingsForPong: Int, pongsToSwitch: Int): Props = { 8 | Props(classOf[Worker], pingDelay, breakDelay, pingsForPong, pongsToSwitch) 9 | } 10 | } 11 | 12 | class Worker(pingDelay: Long, 13 | breakDelay: Long, 14 | pingsForPong: Int, 15 | pongsToSwitch: Int 16 | ) extends Actor with ActorLogging { 17 | 18 | import context.dispatcher 19 | 20 | val scheduler = context.system.scheduler 21 | 22 | def getNewRole: Receive = { 23 | case BecomePing(ponger: ActorRef) => 24 | context.become(processPing(ponger, pongsToSwitch)) 25 | self ! Ping 26 | case BecomePong() => 27 | context.become(processPong(0)) 28 | scheduler.scheduleOnce(breakDelay millis) { 29 | self ! PongerFailure("failure imitation") 30 | } 31 | } 32 | 33 | def processPing(ponger: ActorRef, pongsLeftToSwitch: Int): Receive = getNewRole.orElse { 34 | case Ping => 35 | scheduler.scheduleOnce(pingDelay millis) { 36 | self ! Ping 37 | } 38 | ponger ! Ping 39 | case Pong if pongsLeftToSwitch == 1 => 40 | context.become(getNewRole) 41 | context.parent ! SetFinished(ponger, self) 42 | case Pong => context.become(processPing(ponger, pongsLeftToSwitch - 1)) 43 | case WorkerStatusTest => sender ! WorkerStatus(true) // case for test purpose only 44 | case msg => log.debug("UNKNOWN MESSAGE" + msg) 45 | } 46 | 47 | def processPong(pingCount: Int): Receive = getNewRole.orElse { 48 | case PongerFailure(msg) => 49 | scheduler.scheduleOnce(breakDelay millis) { 50 | self ! PongerFailure("failure imitation") 51 | } 52 | throw new PongerFailureException(msg) 53 | case Ping if pingCount == (pingsForPong - 1) => 54 | context.become(processPong(0)) 55 | sender ! Pong 56 | case Ping => 57 | context.become(processPong(pingCount + 1)) 58 | case WorkerStatusTest => 59 | sender ! WorkerStatus(false) // case for test purpose only 60 | case msg => log.debug("UNKNOWN MESSAGE" + msg) 61 | } 62 | 63 | def receive = getNewRole 64 | 65 | override def postStop() = { 66 | log.info(s"${this.self.path} has stopped") 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/scala/java2scala/shop/CartStore.scala: -------------------------------------------------------------------------------- 1 | package java2scala.shop 2 | import java.util.UUID 3 | 4 | import cats.data.OptionT 5 | import cats.effect.IO 6 | import cats.effect.concurrent.Ref 7 | import java2scala.shop.IOCartStore.State 8 | import cats.implicits._ 9 | 10 | trait CartStore { 11 | def getOrCreate(user: UUID): IO[Cart] 12 | def get(id: UUID): IO[Cart] 13 | def putProduct(cart: UUID, product: UUID, quantity: BigDecimal): IO[Unit] 14 | def removeProduct(cart: UUID, product: UUID): IO[Unit] 15 | } 16 | 17 | object CartStore {} 18 | 19 | final case class IOCartStore(state: Ref[IO, State]) extends CartStore { 20 | 21 | def getOrCreate(user: UUID): IO[Cart] = 22 | OptionT(state.get.map(_.byUser.get(user))).getOrElseF { 23 | for { 24 | id <- IO(UUID.randomUUID()) 25 | ref <- Ref[IO].of(Cart(id, user, Map())) 26 | res <- state.modify(_.addNewCartRef(id, user, ref)) 27 | } yield res 28 | }.flatMap(_.get) 29 | // state.get 30 | // .map(_.byUser.get(user)) 31 | // .flatMap { 32 | // case Some(cart) => cart.pure[IO] 33 | // case None => 34 | // for { 35 | // id <- IO(UUID.randomUUID()) 36 | // ref <- Ref[IO].of(Cart(id, user, Map())) 37 | // res <- state.modify(_.addNewCartRef(id, user, ref)) 38 | // } yield res 39 | // } 40 | // .flatMap(_.get) 41 | 42 | private def getRef(id: UUID): IO[Ref[IO, Cart]] = 43 | state.get.flatMap(_.byID.get(id).liftTo[IO](CartNotFound(id))) 44 | 45 | private def updateRef(id: UUID)(f: Cart => Cart): IO[Unit] = getRef(id).flatMap(_.update(f)) 46 | 47 | def get(id: UUID): IO[Cart] = getRef(id).flatMap(_.get) 48 | 49 | def putProduct(cart: UUID, product: UUID, quantity: BigDecimal): IO[Unit] = 50 | updateRef(cart)(_.addProduct(product, quantity)) 51 | def removeProduct(cart: UUID, product: UUID): IO[Unit] = 52 | updateRef(cart)(_.removeProduct(product)) 53 | } 54 | 55 | object IOCartStore { 56 | final case class State(byID: Map[UUID, Ref[IO, Cart]], byUser: Map[UUID, Ref[IO, Cart]]) { 57 | def addNewCartRef(id: UUID, userId: UUID, cartRef: Ref[IO, Cart]): (State, Ref[IO, Cart]) = 58 | byUser.get(userId) match { 59 | case Some(ref) => this -> ref 60 | case None => State(byID + (id -> cartRef), byUser + (userId -> cartRef)) -> cartRef 61 | } 62 | } 63 | 64 | def create: IO[CartStore] = 65 | for (ref <- Ref[IO].of(State(Map(), Map()))) yield IOCartStore(ref) 66 | } 67 | -------------------------------------------------------------------------------- /src/main/scala/java2scala/shop/domain.scala: -------------------------------------------------------------------------------- 1 | package java2scala.shop 2 | import java.util.UUID 3 | 4 | import io.circe.derivation.annotations.JsonCodec 5 | import cats.implicits._ 6 | 7 | @JsonCodec 8 | final case class Product( 9 | id: UUID, 10 | name: String, 11 | description: String, 12 | price: Option[Price] 13 | ) 14 | 15 | object Product { 16 | implicit val key: Key[Product] = new Key[Product] { 17 | def key(a: Product): UUID = a.id 18 | def notFound(uuid: UUID): Throwable = ProductNotFound(uuid) 19 | 20 | def multiple(uuid: UUID): Throwable = MultipleProducts(uuid) 21 | } 22 | } 23 | 24 | @JsonCodec 25 | final case class Price( 26 | minerals: Option[BigDecimal], 27 | gas: Option[BigDecimal], 28 | supply: Option[BigDecimal] 29 | ) 30 | 31 | @JsonCodec 32 | final case class User( 33 | id: UUID, 34 | name: String 35 | ) 36 | object User { 37 | implicit val key: Key[User] = new Key[User] { 38 | def key(a: User): UUID = a.id 39 | def notFound(uuid: UUID): Throwable = UserNotFound(uuid) 40 | def multiple(uuid: UUID): Throwable = MultipleUsers(uuid) 41 | } 42 | } 43 | 44 | @JsonCodec 45 | final case class ProductItem( 46 | productId: UUID, 47 | quantity: BigDecimal 48 | ) 49 | 50 | object ProductItem { 51 | // implicit val key: Key[ProductItem] = new Key[ProductItem] { 52 | // def key(a: ProductItem): UUID = a.productId 53 | // def notFound(uuid: UUID): Throwable = ProductNotFound(uuid) 54 | // 55 | // def multiple(uuid: UUID): Throwable = MultipleProducts } 56 | } 57 | 58 | @JsonCodec 59 | final case class Cart( 60 | id: UUID, 61 | user: UUID, 62 | items: Map[UUID, BigDecimal] 63 | ) { 64 | def addProduct(id: UUID, quantity: BigDecimal): Cart = 65 | copy(items = items + (id -> items.get(id).fold(quantity)(_ + quantity))) 66 | 67 | def removeProduct(id: UUID): Cart = copy(items = items - id) 68 | } 69 | 70 | abstract class StacklessException(message: String) extends Exception(message, null, false, false) 71 | 72 | final case class ProductNotFound(id: UUID) extends StacklessException(s"Product $id not found") 73 | final case class MultipleProducts(id: UUID) extends StacklessException(s"Multiple products with id $id") 74 | final case class CartNotFound(id: UUID) extends StacklessException(s"Cart $id not found") 75 | final case class UserNotFound(id: UUID) extends StacklessException(s"User $id not found") 76 | final case class MultipleUsers(id: UUID) extends StacklessException(s"Multiple users with id $id") 77 | -------------------------------------------------------------------------------- /src/test/scala/java2scala/homeworks/funcs/FiniteEquivalencesSuite.scala: -------------------------------------------------------------------------------- 1 | package java2scala.homeworks.funcs 2 | 3 | import org.scalacheck.Arbitrary 4 | import org.scalactic.Equality 5 | import org.scalatest.prop.PropertyChecks 6 | import org.scalatest.{Assertion, FlatSpec, Matchers, WordSpec} 7 | import FiniteEquivalences._ 8 | 9 | class FiniteEquivalencesSuite extends WordSpec with Matchers with PropertyChecks { 10 | 11 | def checkEquivalence[A: Arbitrary: Equality, B: Arbitrary: Equality](eq: Equivalent[A, B]): Assertion = { 12 | forAll { a: A => 13 | assert(eq.from(eq.to(a)) === a) 14 | } 15 | 16 | forAll { b: B => 17 | eq.to(eq.from(b)) shouldBe b 18 | } 19 | } 20 | 21 | "Finite Equivalences" when { 22 | "checking boolToThree" should { 23 | "be a section" in forAll { (f: Boolean => Three, b: Boolean) => 24 | boolToThree.from(boolToThree.to(f))(b) shouldEqual f(b) 25 | } 26 | "be a retraction" in forAll { p: (Three, Three) => 27 | boolToThree.to(boolToThree.from(p)) shouldEqual p 28 | } 29 | } 30 | 31 | "checking threeToBool" should { 32 | "be a section" in forAll { (f: Three => Boolean, t: Three) => 33 | threeToBool.from(threeToBool.to(f))(t) shouldEqual f(t) 34 | } 35 | "be a retraction" in forAll { t: (Boolean, Boolean, Boolean) => 36 | threeToBool.to(threeToBool.from(t)) shouldEqual t 37 | } 38 | } 39 | 40 | "checking boolToBoolToBool" should { 41 | "be a section" in forAll { (f: Boolean => Boolean => Boolean, x: Boolean, y: Boolean) => 42 | boolToBoolToBool.from(boolToBoolToBool.to(f))(x)(y) shouldEqual f(x)(y) 43 | } 44 | "be a retraction" in forAll { (f: (Boolean => Boolean) => Boolean, g: Boolean => Boolean) => 45 | boolToBoolToBool.to(boolToBoolToBool.from(f))(g) shouldEqual f(g) 46 | } 47 | } 48 | 49 | "checking threeToUnit" should { 50 | "be a section" in forAll { (f: Three => Unit, t: Three) => 51 | threeToUnit.from(threeToUnit.to(f))(t) shouldEqual f(t) 52 | } 53 | "be a retraction" in forAll { u: Unit => 54 | threeToUnit.to(threeToUnit.from(u)) shouldEqual u 55 | } 56 | } 57 | 58 | "checking unitToThree" should { 59 | "be a section" in forAll { (f: Unit => Three, u: Unit) => 60 | unitToThree.from(unitToThree.to(f))(u) shouldEqual f(u) 61 | } 62 | "be a retraction" in forAll { t: Three => 63 | unitToThree.to(unitToThree.from(t)) shouldEqual t 64 | } 65 | } 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/main/scala/lectures/collections/OptionVsNPE.scala: -------------------------------------------------------------------------------- 1 | package lectures.collections 2 | 3 | import scala.util.Random 4 | 5 | /** 6 | * В этом задании Вам предстоит работать с очень нестабильным внешним сервисом. 7 | * 8 | * Для успешного завершения задания вы должны реализовать метод businessLogic в объекте OptionVsNPE 9 | * Этот метод должен делать следующее: 10 | * * * * * Получить и распечатать результат или, если была ошибка ResourceException, 11 | * распечатать "Try again with new resource" и повторить все заново 12 | * * * * * Получить ресурс через ResourceProducer 13 | * * * * * Если ресурс не получен, кидать ResourceException (throw new ResourceException) 14 | * * * * * Если ресурс удачно получен, на его основе получить Connection 15 | * * * * * Если соединение не получено, пробовать, пока соединение не будет получено 16 | * * * * * Вызвать у соединения метод result 17 | * * * * * Если метод result возвращает Null, заменить его дефолтным сообщением из объекта Connection 18 | * 19 | * Для успешного решения задания: 20 | * * * * * Замените знаки вопроса реализацией методов 21 | * * * * * Нельзя менять содержимое объектов ConnectionProducer, ResourceProducer 22 | * * * * * Не должно быть ни одного NPE 23 | * * * * * Можно менять входные и выходные параметры методов Connection 24 | * 25 | * трейт FailUtil - содержит методы для эмуляции спорадических ошибок 26 | * 27 | * 28 | */ 29 | class ResourceException extends Exception("Ресурс не отвечает") 30 | 31 | trait FailUtil { 32 | val failRate: Double 33 | 34 | def timeToFail = Math.random() > failRate 35 | } 36 | 37 | object ResourceProducer extends FailUtil { 38 | def produce = if (timeToFail) null else Resource(Random.alphanumeric.take(10).mkString) 39 | 40 | val failRate: Double = 0.3 41 | } 42 | 43 | object ConnectionProducer extends FailUtil { 44 | val failRate: Double = 0.5 45 | 46 | def produce(resource: Resource) = if (timeToFail) null else Connection(resource) 47 | 48 | def result(connection: Connection) = if (timeToFail) null else connection.resource.name 49 | } 50 | 51 | case class Connection(resource: Resource) { 52 | private val defaultResult = "something went wrong!" 53 | 54 | //ConnectionProducer.result(this) 55 | def result: String = ??? 56 | } 57 | 58 | case class Resource(name: String) 59 | 60 | object OptionVsNPE extends App { 61 | 62 | def businessLogic: String = try { 63 | // ResourceProducer 64 | val result: String = ??? 65 | println(result) 66 | result 67 | } catch { 68 | case e: ResourceException => ??? 69 | } 70 | 71 | businessLogic 72 | } 73 | -------------------------------------------------------------------------------- /src/main/scala/lectures/collections/comprehension/Couriers.scala: -------------------------------------------------------------------------------- 1 | package lectures.collections.comprehension 2 | 3 | /** 4 | * Помогите курьерам разобраться с обслуживанием адресов 5 | * 6 | * Каждый день на работу выходит 'courierCount' курьеров 7 | * Им нужно обслужить 'addressesCount' адресов 8 | * Каждый курьер может обслужить courier.canServe адресов, но только при условии, что позволит дорожная ситуация. 9 | * Т.е. если trafficDegree < 5, то курьер обслужит все адреса, которые может, иначе - ни одного 10 | * 11 | * Входные данные для приложения содержат 2 строки 12 | * В первой строке - количество адресов, которые требуется обслужить 13 | * Во второй - количество курьеров, вышедших на работу. 14 | * 15 | * Ваша задача: 16 | * Изучить код и переписать его так, 17 | * что бы в нем не было ни одного цикла for, ни одной переменной или мутабильной коллекции 18 | * 19 | * Для этого используйте функции комбинаторы: filter, withFilter, fold, map, flatMap и т.д. 20 | * 21 | */ 22 | 23 | case class Traffic(degree: Double) 24 | 25 | object Courier { 26 | def couriers(courierCount: Int): List[Courier] = 27 | (for (i <- 1 to courierCount) yield { 28 | Courier(i) 29 | }).toList 30 | } 31 | 32 | case class Courier(index: Int) { 33 | val canServe = (Math.random() * 10).toInt 34 | } 35 | 36 | object Address { 37 | def addresses(addressesCount: Int): List[Address] = 38 | (for (i <- 1 to addressesCount) yield { 39 | Address(s"$i$i$i") 40 | }).toList 41 | } 42 | 43 | case class Address(postIndex: String) 44 | 45 | object CouriersWithComprehension extends App { 46 | 47 | import Address._ 48 | import Courier._ 49 | 50 | val sc = new java.util.Scanner(System.in) 51 | val addressesCount = sc.nextInt() 52 | val courierCount = sc.nextInt() 53 | val addrs = addresses(addressesCount) 54 | val cours = couriers(courierCount) 55 | 56 | // какие адреса были обслужены 57 | def serveAddresses(addresses: List[Address], couriers: List[Courier]) = { 58 | var accum = 0 59 | for (courier <- couriers; 60 | trafficDegree = traffic().degree; 61 | t <- 0 until courier.canServe if trafficDegree < 5 && accum < addresses.length 62 | ) yield { 63 | val addr = addresses(accum) 64 | accum = accum + 1 65 | addr 66 | } 67 | } 68 | 69 | def traffic(): Traffic = new Traffic(Math.random() * 10) 70 | 71 | def printServedAddresses(addresses: List[Address], couriers: List[Courier]) = 72 | for (a <- serveAddresses(addresses, couriers)) { 73 | println(a.postIndex) 74 | } 75 | 76 | printServedAddresses(addrs, cours) 77 | 78 | } 79 | -------------------------------------------------------------------------------- /src/main/resources/shop/products.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "2ba1ec6e-5ac4-11e9-9022-6f45462a67f6", 4 | "name": "Drone", 5 | "price": { 6 | "minerals": 50, 7 | "supply": 1 8 | }, 9 | "description": "basic worker unit for Zerg" 10 | }, 11 | { 12 | "id": "2ba2490c-5ac4-11e9-844e-dfda4f939c0b", 13 | "name": "Overlord", 14 | "price": { 15 | "minerals": 100 16 | }, 17 | "description": "flying supply unit" 18 | }, 19 | { 20 | "id": "2ba2b89c-5ac4-11e9-8535-473dd236f4a3", 21 | "name": "Zergling", 22 | "price": { 23 | "minerals": 50, 24 | "supply": 0.5 25 | }, 26 | "description": "small and fast melee attacker" 27 | }, 28 | { 29 | "id": "2ba31616-5ac4-11e9-a4f9-7bd3cba06388", 30 | "name": "Baneling", 31 | "price": { 32 | "minerals": 25, 33 | "gas": 25, 34 | "supply": 1 35 | }, 36 | "description": "suicide bomber" 37 | }, 38 | { 39 | "id": "2ba36d28-5ac4-11e9-b840-7b608eb24330", 40 | "name": "Roach", 41 | "description": "armored-ground unit" 42 | }, 43 | { 44 | "id": "2ba3bff8-5ac4-11e9-be91-a384266ef456", 45 | "name": "Queen", 46 | "description": "Light air and ground defence, spawn larvae and creep" 47 | }, 48 | { 49 | "id": "2ba41200-5ac4-11e9-990a-43b255c46649", 50 | "name": "Hydralisk", 51 | "description": "ranged Lair-tech unit" 52 | }, 53 | { 54 | "id": "2ba464ee-5ac4-11e9-8c3c-8f54859a5790", 55 | "name": "Mutalisk", 56 | "description": "extremely fast air attack unit" 57 | }, 58 | { 59 | "id": "2ba4b66a-5ac4-11e9-8c70-9b7354c19a82", 60 | "name": "Corruptor", 61 | "description": "unit that has strong anti-air capabilities but slow speed" 62 | }, 63 | { 64 | "id": "2ba509b2-5ac4-11e9-b570-07164ec23aa2", 65 | "name": "Infestor", 66 | "description": "offensive spellcaster" 67 | }, 68 | { 69 | "id": "c52c6ba2-5ac4-11e9-a80e-63c4e1dfc80c", 70 | "name": "Swarm Host", 71 | "description": "siege unitm spawn locusts" 72 | }, 73 | { 74 | "id": "c52cc44e-5ac4-11e9-91c2-4bd4140a1c9a", 75 | "name": "Ultralisk", 76 | "description": "toughest late-game unit" 77 | }, 78 | { 79 | "id": "c52d1796-5ac4-11e9-9cf4-c3c1b90a189e", 80 | "name": "Viper", 81 | "description": "flying support caster" 82 | }, 83 | { 84 | "id": "c52d6caa-5ac4-11e9-9e9c-cb83b713bc32", 85 | "name": "Brood Lord", 86 | "description": "flying heavy-assault" 87 | }, 88 | { 89 | "id": "c52dc628-5ac4-11e9-be95-5fd031e4e900", 90 | "name": "Overseer", 91 | "description": "Mutated overseer, detector" 92 | } 93 | ] -------------------------------------------------------------------------------- /src/main/scala/java2scala/Lecture8.scala: -------------------------------------------------------------------------------- 1 | package java2scala 2 | 3 | import cats.effect.{ExitCode, IO, IOApp} 4 | import akka.http.scaladsl.server._ 5 | import Directives._ 6 | import akka.actor.ActorSystem 7 | import akka.http.scaladsl.Http 8 | import akka.http.scaladsl.marshalling.ToResponseMarshaller 9 | import akka.http.scaladsl.model.StatusCodes 10 | import akka.stream.{ActorMaterializer, Materializer} 11 | import cats.effect.concurrent.Ref 12 | import cats.implicits._ 13 | 14 | import scala.collection.immutable 15 | object Lecture8 extends IOApp { 16 | 17 | // implicit val ioListStringMarshaller: ToResponseMarshaller[IO[List[String]]] = ??? 18 | 19 | def route(tags: AppTags): Route = 20 | handleRejections(RejH) { 21 | path("") { 22 | complete("Hello World") 23 | } ~ 24 | pathPrefix("tags") { 25 | get { complete(tags.allTags.map(_.toString()).unsafeToFuture()) } ~ 26 | (put & parameter("tag")) { tag => 27 | complete(tags.addTag(tag).as("ok added").unsafeToFuture()) 28 | } 29 | } ~ 30 | pathPrefix("users") { 31 | parameters(("id".as[Int].?, "version".?)) { (id, version) => 32 | complete(s"id = $id version = $version") 33 | } 34 | } ~ 35 | pathPrefix("products" / IntNumber / LongNumber / Segment) { (num, num2, str) => 36 | complete(s"product[$num, $num2] : $str") // http://localhost:8080/products/3/5/etert 37 | } ~ 38 | pathPrefix("foo") { 39 | parameterMultiMap { pm => 40 | complete(pm.get("bar").toString) 41 | } 42 | } 43 | } 44 | 45 | case object MyRejection extends Rejection 46 | 47 | object RejH extends RejectionHandler { 48 | def apply(rejs: immutable.Seq[Rejection]): Option[Route] = 49 | if (rejs.contains(MyRejection)) 50 | Some(complete(StatusCodes.NotImplemented, "lol no")) 51 | else None 52 | } 53 | 54 | implicit val system: ActorSystem = ActorSystem("our-server") 55 | implicit val materializer: Materializer = ActorMaterializer() 56 | 57 | def run(args: List[String]): IO[ExitCode] = 58 | for { 59 | tags <- AppTags(Nil) 60 | appRoute = route(tags) 61 | _ <- IO.fromFuture(IO(Http().bindAndHandle(appRoute, "0.0.0.0", 8080))) 62 | } yield ExitCode.Success 63 | 64 | } 65 | 66 | final class AppTags(ref: Ref[IO, List[String]]) { 67 | def allTags: IO[List[String]] = ref.get 68 | def addTag(tag: String): IO[Unit] = ref.update(tag :: _) 69 | } 70 | 71 | object AppTags { 72 | def apply(initial: List[String]): IO[AppTags] = 73 | for (ref <- Ref[IO].of(initial)) yield new AppTags(ref) 74 | } 75 | -------------------------------------------------------------------------------- /src/test/scala/lectures/matching/SortingStuffGeneratorBasedTest.scala: -------------------------------------------------------------------------------- 1 | package lectures.matching 2 | 3 | import lectures.matching.SortingStuff.{Book, StuffBox, Watches} 4 | import org.scalacheck.Gen 5 | import org.scalatest.prop.PropertyChecks 6 | import org.scalatest.{Matchers, WordSpec} 7 | 8 | import scala.util.Random 9 | 10 | 11 | /** 12 | * Короткий список самых востребованных генераторов: 13 | * Gen.alphaString 14 | * Gen.delay 15 | * Gen.oneOf 16 | * Gen.resultOf 17 | * Gen.zip 18 | * Gen.map 19 | * Gen.suchThat 20 | * Gen.mapOf 21 | * Gen.pic 22 | * Gen.choose 23 | * 24 | * Допишите 2 теста: 25 | * Для "find knife" теста создайте генератор, Option[Knife]. Тест должен показать, что если нож есть в вещах, 26 | * то метод findMyKnife его отыщет. 27 | * 28 | * Для "put boots ..." создайте генератор и проверьте правильность работы метода sortJunk по аналогии с предыдущими тестами. 29 | * 30 | */ 31 | 32 | class SortingStuffGeneratorBasedTest extends WordSpec with Matchers with PropertyChecks { 33 | 34 | val cheepWatchGen: Gen[Watches] = Gen.zip(Gen.choose(0f, 1000f), Gen.alphaStr).map(w => Watches(w._2, w._1)) 35 | val bookGenerator = Gen.alphaStr.map(name => Book(name, Random.nextBoolean())) 36 | val interestingBookGen = bookGenerator.filter(_.isInteresting) 37 | 38 | // Override configuration if you need 39 | implicit override val generatorDrivenConfig: PropertyCheckConfiguration = 40 | PropertyCheckConfig(minSize = 10, maxSize = 20) 41 | 42 | val get: AfterWord = new AfterWord("have") 43 | 44 | "This test" should get { 45 | "proper cheep watch generator" in { 46 | forAll(cheepWatchGen) { (watch: Watches) => { 47 | watch.cost should be <= 1000f 48 | } 49 | } 50 | } 51 | "proper interesting book generator" in { 52 | val books = interestingBookGen 53 | forAll(books) { (book: Book) => { 54 | book shouldBe 'interesting 55 | } 56 | } 57 | } 58 | } 59 | 60 | "Sort stuff" should { 61 | "return collections" which { 62 | "total size is equal to item amount" in pendingUntilFixed{ 63 | val ms = generatorDrivenConfig.minSuccessful 64 | 65 | val books = (1 to ms) flatMap { _ => interestingBookGen.sample } 66 | val watches = (1 to ms) flatMap { _ => cheepWatchGen.sample } 67 | 68 | val StuffBox(goodBooks, niceWatches, _, junk) = SortingStuff.sortJunk(Random.shuffle(books ++ watches).toList) 69 | goodBooks should have size books.size 70 | niceWatches should have size 0 71 | junk should have size watches.size 72 | } 73 | } 74 | "find knife" which { 75 | "was occasionally disposed" in pending 76 | } 77 | 78 | "put boots in a proper place" when { 79 | "boots were produced by Converse or Adidas" in pending 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/scala/lectures/akka/chat/Session.scala: -------------------------------------------------------------------------------- 1 | package lectures.akka.chat 2 | 3 | import akka.actor.typed.scaladsl.{Behaviors, ActorContext} 4 | import akka.actor.typed.{ActorRef, Behavior} 5 | import com.typesafe.scalalogging.LazyLogging 6 | 7 | object Session extends LazyLogging { 8 | sealed trait Message 9 | 10 | final case class ChatList(names: List[String]) extends Message 11 | final case class Connected(name: String, login: String, chat: ActorRef[Chat.Message]) extends Message 12 | final case class UserEnter(name: String) extends Message 13 | final case class UserLeave(name: String) extends Message 14 | final case class NewMessage(login: String, text: String) extends Message 15 | final case class Input(in: In) extends Message 16 | final case class Init(hub: ActorRef[Hub.Message], out: ActorRef[Out]) extends Message 17 | case object Disconnect extends Message 18 | 19 | val initial: Behavior[Message] = Behaviors.receiveMessage { 20 | case Init(hub, out) => 21 | logger.debug("initialized") 22 | initialized(hub, out) 23 | case _ => Behaviors.same 24 | } 25 | 26 | private def initialized(hub: ActorRef[Hub.Message], out: ActorRef[Out]): Behavior[Message] = { 27 | 28 | def common(ctx: ActorContext[Message]): Message => Behavior[Message] = { 29 | case ChatList(names) => 30 | out ! Out.ChatRoomList(names) 31 | Behaviors.same 32 | case Connected(name, login, newChat) => 33 | out ! Out.Connected(name) 34 | inChat(newChat, login) 35 | case Input(in) => 36 | import In._ 37 | in match { 38 | case Enter(newLogin, name) => 39 | hub ! Hub.Connect(name, newLogin, ctx.self) 40 | case Create(name) => hub ! Hub.NewChat(name) 41 | case Channels() => hub ! Hub.GetChats(ctx.self) 42 | 43 | } 44 | Behaviors.same 45 | case _ => Behaviors.same 46 | } 47 | 48 | def inChat(chat: ActorRef[Chat.Message], login: String): Behavior[Message] = Behaviors.receive { (ctx, mess) => 49 | mess match { 50 | case NewMessage(author, text) => 51 | out ! Out.MessageSent(author, text) 52 | Behaviors.same 53 | case UserEnter(userLogin) => 54 | out ! Out.NewPersonEntered(userLogin) 55 | Behaviors.same 56 | case Input(In.Send(text)) => 57 | chat ! Chat.SendText(login, text) 58 | Behaviors.same 59 | case msg => common(ctx)(msg) 60 | } 61 | } 62 | 63 | val inLobby: Behavior[Message] = Behaviors.receive { common(_)(_) } 64 | 65 | inLobby 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/test/scala/inclasss/Streams.scala: -------------------------------------------------------------------------------- 1 | package inclasss 2 | 3 | import akka.actor.{ActorRef, ActorSystem, PoisonPill} 4 | import akka.stream.{ActorMaterializer, ClosedShape, OverflowStrategy} 5 | import akka.stream.scaladsl.{Broadcast, Flow, GraphDSL, Keep, Merge, Sink, Source} 6 | import com.typesafe.config.{Config, ConfigFactory} 7 | import GraphDSL.Implicits._ 8 | import akka.stream.javadsl.RunnableGraph 9 | 10 | import scala.io.StdIn 11 | 12 | object Streams { 13 | implicit val system = ActorSystem("streams", ConfigFactory.load("chat.conf")) 14 | implicit val materializer = ActorMaterializer() 15 | 16 | import system.dispatcher 17 | import Numeric.Implicits._ 18 | 19 | val simpleSource = Source(List(1, 2, 3)) 20 | val actorSource = Source.actorRef[String](100, OverflowStrategy.dropNew) 21 | 22 | val parseInt = Flow[String] 23 | .map(s => util.Try(s.toInt).toOption) 24 | .collect { case Some(x) => 2 * x + 1 } 25 | 26 | val parseDouble = Flow[String] 27 | .map(s => util.Try(s.toDouble)) 28 | .collect { case util.Success(d) => d } 29 | 30 | val sinkPrint = Sink.foreach(println) 31 | 32 | def sinkSum[N](implicit N: Numeric[N]) = Sink.fold[N, N](N.zero)(_ + _) 33 | 34 | val graph = 35 | actorSource 36 | .alsoTo(sinkPrint) 37 | .via(parseInt) 38 | .alsoTo(sinkPrint) 39 | .toMat(sinkSum)(Keep.both) 40 | 41 | val graph2 = 42 | GraphDSL 43 | .create(actorSource, sinkSum[Int], sinkSum[Double]) { case triple => triple } { 44 | implicit b => 45 | (src, sumInt, sumDouble) => 46 | val bcast = b.add(Broadcast[String](2)) 47 | val bcastInt = b.add(Broadcast[Int](2)) 48 | val bcastDouble = b.add(Broadcast[Double](2)) 49 | val merge = b.add(Merge[String](2)) 50 | 51 | src ~> bcast 52 | 53 | bcast ~> parseInt ~> bcastInt 54 | 55 | bcastInt ~> sumInt 56 | 57 | bcast ~> parseDouble ~> bcastDouble 58 | 59 | bcastDouble ~> sumDouble 60 | 61 | bcastInt ~> Flow[Int].map(i => s"int $i") ~> merge 62 | 63 | bcastDouble ~> Flow[Double].map(d => s"double $d") ~> merge 64 | 65 | merge ~> Sink.foreach(println) 66 | 67 | ClosedShape 68 | } 69 | 70 | def readInputTo(ref: ActorRef): Unit = { 71 | val l = StdIn.readLine().trim 72 | if (l == "stop") { 73 | ref ! PoisonPill 74 | } else { 75 | ref ! l 76 | readInputTo(ref) 77 | } 78 | } 79 | 80 | def main(args: Array[String]): Unit = { 81 | val (ref, intSum, doubleSum) = RunnableGraph.fromGraph(graph2).run(materializer) 82 | readInputTo(ref) 83 | intSum.onComplete { x => 84 | println(s"int sum is $x") 85 | } 86 | doubleSum.onComplete { x => 87 | println(s" double sum is $x") 88 | } 89 | 90 | for (_ <- intSum; _ <- doubleSum) system.terminate() 91 | 92 | } 93 | 94 | } 95 | -------------------------------------------------------------------------------- /src/main/scala/java2scala/tagless/FilterTF.scala: -------------------------------------------------------------------------------- 1 | package java2scala.tagless 2 | 3 | import java2scala.tagless.FilterTF.colorIs 4 | 5 | 6 | 7 | 8 | trait FilterTF[T] { 9 | def colorIs(color: String): T 10 | def priceLT(upper: BigDecimal): T 11 | def and(x: T, y: T): T 12 | } 13 | 14 | object FilterTF extends App { 15 | def apply[T](implicit filterTF: FilterTF[T]): FilterTF[T] = filterTF 16 | 17 | def colorIs[T](color: String)(implicit fi: FilterTF[T]): T = 18 | fi.colorIs(color) 19 | def priceLT[T](upper: BigDecimal)(implicit fi: FilterTF[T]): T = 20 | fi.priceLT(upper) 21 | 22 | implicit def showInt[T]: FilterTF[String] = 23 | new FilterTF[String] { 24 | def colorIs(color: String): String = s"color = $color" 25 | def priceLT(upper: BigDecimal): String = s"price <= $upper" 26 | def and(x: String, y: String): String = s"($x) AND ($y)" 27 | } 28 | 29 | // type ProductPred = Product => Boolean 30 | 31 | implicit def filterInt: FilterTF[Product => Boolean] = 32 | new FilterTF[Product => Boolean] { 33 | def colorIs(color: String): Product => Boolean = _.color == color 34 | def priceLT(upper: BigDecimal): Product => Boolean = _.price <= upper 35 | def and(x: Product => Boolean, y: Product => Boolean): Product => Boolean = 36 | p => x(p) && y(p) 37 | } 38 | 39 | } 40 | 41 | trait Or[T] { 42 | def or(x: T, y: T): T 43 | } 44 | 45 | object Or { 46 | def apply[T](implicit or: Or[T]): Or[T] = or 47 | 48 | implicit def showInt: Or[String] = new Or[String] { 49 | def or(x: String, y: String): String = s"($x) OR ($y)" 50 | } 51 | 52 | implicit def filterInt: Or[Product => Boolean] = new Or[Product => Boolean] { 53 | def or(x: Product => Boolean, y: Product => Boolean): Product => Boolean = 54 | p => x(p) || y(p) 55 | } 56 | } 57 | 58 | object FilterTFApp extends App { 59 | def isRed[T: FilterTF]: T = colorIs[T]("red") 60 | def priceLT100[T: FilterTF]: T = FilterTF[T].priceLT(100) 61 | def combined[T: FilterTF]: T = FilterTF[T].and(isRed[T], priceLT100[T]) 62 | 63 | println(isRed[String]) 64 | println(priceLT100[String]) 65 | println(combined[String]) 66 | 67 | val products = List(Product("yellow", 50), Product("red", 50), Product("red", 200)) 68 | println(products.filter(isRed[Product => Boolean])) 69 | println(products.filter(priceLT100[Product => Boolean])) 70 | println(products.filter(combined[Product => Boolean])) 71 | 72 | def fltOr[T: FilterTF: Or]: T = 73 | Or[T].or(combined, FilterTF.colorIs("yellow")) 74 | 75 | def fltOr2[T: FilterTF: Or]: T = 76 | FilterTF[T].and( 77 | Or[T].or( 78 | FilterTF[T].colorIs("yellow"), FilterTF[T].colorIs("red")), 79 | FilterTF[T].priceLT(60) 80 | ) 81 | 82 | println("-" * 10 + "[ OR ]" + "-" * 10) 83 | 84 | println(fltOr[String]) 85 | println(fltOr2[String]) 86 | 87 | println(products.filter(fltOr[Product => Boolean])) 88 | println(products.filter(fltOr2[Product => Boolean])) 89 | 90 | } 91 | -------------------------------------------------------------------------------- /src/test/scala/java2scala/homeworks/CharAutomataSuite.scala: -------------------------------------------------------------------------------- 1 | package java2scala.homeworks 2 | 3 | import org.scalatest.{FlatSpec, Matchers} 4 | import org.scalatest.prop.TableDrivenPropertyChecks._ 5 | import CharAutomataSuite.tests 6 | 7 | class CharAutomataSuite extends FlatSpec with Matchers { 8 | import CharAutomata.{balance, find, parseInt} 9 | "parenthesis balancer" should "identify correct sequences" in { 10 | forAll(tests) { (string, _, paren, _, _) => 11 | balance(string).isRight shouldBe paren 12 | } 13 | } 14 | 15 | "substring finder" should "find index of the first string occurence" in { 16 | forAll(tests) { (string, sub, _, _, res) => 17 | find(sub)(string).toOption shouldBe res 18 | } 19 | } 20 | 21 | "num parser" should "parse integers" in { 22 | forAll(tests) { (string, _, _, n, _) => 23 | parseInt(string) shouldBe Right(n) 24 | } 25 | } 26 | 27 | "and combinator" should "merge results of `balance` and `find`" in { 28 | forAll(tests) { (string, sub, paren, _, found) => 29 | (balance and find(sub))(string).toOption shouldBe 30 | found.filter(_ => paren).map(((), _)) 31 | } 32 | } 33 | 34 | it should "merge results of `find` and `parse`" in { 35 | forAll(tests) { (string, sub, _, n, found) => 36 | (find(sub) and CharAutomata.parseInt)(string).toOption shouldBe 37 | found.map((_, n)) 38 | 39 | } 40 | } 41 | 42 | it should "merge results of `balance` , `find` and `parse`" in { 43 | forAll(tests) { (string, sub, paren, n, found) => 44 | (parseInt and balance and find(sub))(string).toOption shouldBe 45 | found.filter(_ => paren).map(s => ((n, ()), s)) 46 | } 47 | } 48 | 49 | "or combinator" should "choose between results of `balance` and `parseInt`" in { 50 | forAll(tests) { (string, _, paren, n, _) => 51 | (balance or parseInt)(string) shouldBe Right(Right(n).filterOrElse(_ => !paren, ())) 52 | } 53 | } 54 | 55 | it should "choose between results `find`, `parseInt` and `balance`" in { 56 | forAll(tests) { (string, sub, paren, n, found) => 57 | (find(sub) or parseInt or balance)(string) shouldBe 58 | Right(Left(found.map(i => Left(i)).getOrElse(Right(n)))) 59 | } 60 | } 61 | 62 | } 63 | 64 | object CharAutomataSuite { 65 | final case class TestCase(string: String, sub: String, paren: Boolean, num: Int, found: Option[Int]) { 66 | def asTuple = (string, sub, paren, num, found) 67 | } 68 | 69 | val testCases = Vector( 70 | TestCase("(())", "", paren = true, num = 0, found = Some(0)), 71 | TestCase("()()(1)()", "()", paren = true, num = 1, found = Some(0)), 72 | TestCase("()((12)((24)))", ")(", paren = true, num = 12, found = Some(1)), 73 | TestCase("(())lol(()lol))", "lol", paren = false, num = 0, found = Some(4)), 74 | TestCase("(6(5(4)3)2)1)", "lol", paren = false, num = 6, found = None), 75 | TestCase("()((000)(())234)", "lol", paren = true, num = 234, found = None), 76 | TestCase("((ke))kek(())", "kek", paren = true, num = 0, found = Some(6)) 77 | ) 78 | 79 | val tests = Table(("string", "sub", "paren", "num", "found"), testCases.map(_.asTuple): _*) 80 | } 81 | -------------------------------------------------------------------------------- /src/main/scala/lectures/functions/AuthenticationDomain.scala: -------------------------------------------------------------------------------- 1 | package lectures.functions 2 | 3 | import scala.util.Random 4 | 5 | /** 6 | * Created by s.popov2 on 10.06.2016. 7 | */ 8 | 9 | trait Credentials 10 | 11 | object CardCredentials { 12 | def apply(): CardCredentials = CardCredentials((Math.random()* 1000).toInt ) 13 | } 14 | case class CardCredentials(cardNumber: Int) extends Credentials 15 | 16 | object LPCredentials { 17 | def apply(): LPCredentials = LPCredentials(Random.alphanumeric.take(10).mkString, Random.alphanumeric.take(10).mkString) 18 | } 19 | case class LPCredentials(login: String, passwordHash: String) extends Credentials 20 | 21 | trait User { 22 | def id: Int 23 | def credentials: Credentials 24 | } 25 | case class AnonymousUser() extends User { 26 | def id = throw new Exception("Anonymous user have no identification") 27 | def credentials = throw new Exception("Anonymous user have no credentials") 28 | } 29 | 30 | object CardUser { 31 | def apply(): CardUser = CardUser((Math.random() * 5).toInt , CardCredentials()) 32 | } 33 | case class CardUser(id: Int, credentials: CardCredentials) extends User 34 | 35 | object LPUser { 36 | def apply(): LPUser = LPUser((Math.random() * 5).toInt , LPCredentials()) 37 | } 38 | case class LPUser(id: Int, credentials: LPCredentials) extends User 39 | 40 | object AuthenticationData { 41 | 42 | val cardUserCreds = CardCredentials(12345678) 43 | val cardUserCreds2 = CardCredentials(87654321) 44 | val authUserCreds = LPCredentials("qwerty", "qwerty") 45 | val authUserCreds2 = LPCredentials("qwerty2", "qwerty2") 46 | 47 | val registeredCards: Set[CardCredentials] = Set( 48 | CardCredentials(), CardCredentials(), CardCredentials(), cardUserCreds, 49 | CardCredentials(), CardCredentials(), CardCredentials(), CardCredentials(), 50 | CardCredentials(), CardCredentials(), cardUserCreds2 51 | ) 52 | 53 | val registeredLoginAndPassword: Set[LPCredentials] = Set( 54 | LPCredentials(), LPCredentials(), LPCredentials(), LPCredentials(), 55 | LPCredentials(), LPCredentials(), LPCredentials(), LPCredentials(), 56 | LPCredentials(), LPCredentials(), LPCredentials(), LPCredentials(), 57 | LPCredentials() 58 | ) 59 | 60 | val testUsers = List[User]( 61 | AnonymousUser(), AnonymousUser(), AnonymousUser(), AnonymousUser(), AnonymousUser(), 62 | AnonymousUser(), AnonymousUser(), AnonymousUser(), AnonymousUser(), AnonymousUser(), 63 | AnonymousUser(), AnonymousUser(), AnonymousUser(), AnonymousUser(), AnonymousUser(), 64 | CardUser(), CardUser(), CardUser(), CardUser(), CardUser(), CardUser(), CardUser(), 65 | CardUser(), CardUser(), CardUser(), CardUser(), CardUser(), CardUser(), CardUser(), 66 | CardUser(), CardUser(), CardUser(), CardUser(), CardUser(), CardUser(), CardUser(), 67 | LPUser(), LPUser(), LPUser(), LPUser(), LPUser(), LPUser(), LPUser(), LPUser(), LPUser(), 68 | LPUser(), LPUser(), LPUser(), LPUser(), LPUser(), LPUser(), LPUser(), LPUser(), LPUser(), 69 | LPUser(), LPUser(), LPUser(), LPUser(), LPUser(), LPUser(), 70 | LPUser(1234, authUserCreds), LPUser(4567, authUserCreds2), 71 | CardUser(4567, cardUserCreds), CardUser(45679, cardUserCreds2) 72 | ) 73 | } -------------------------------------------------------------------------------- /src/main/scala/lectures/akka/chat/ChatServer.scala: -------------------------------------------------------------------------------- 1 | package lectures.akka.chat 2 | 3 | import akka.event.Logging 4 | import akka.http.scaladsl.Http 5 | import akka.http.scaladsl.model.ws.{Message, TextMessage} 6 | import akka.http.scaladsl.server.Directives._ 7 | import akka.stream.scaladsl.{Flow, Sink, Source} 8 | import akka.stream.{ActorMaterializer, Attributes, OverflowStrategy} 9 | import akka.actor.typed.ActorRef 10 | import akka.actor.typed.scaladsl.AskPattern._ 11 | import akka.actor.typed.scaladsl.adapter._ 12 | import akka.util.Timeout 13 | import akka.{NotUsed, actor => untyped} 14 | import com.typesafe.config.ConfigFactory 15 | import io.circe.parser._ 16 | import io.circe.syntax._ 17 | import lectures.akka.chat.Chat.Disconnect 18 | 19 | import scala.concurrent.duration._ 20 | import scala.io.StdIn 21 | 22 | object ChatServer { 23 | implicit val system = untyped.ActorSystem("websocket-chat", ConfigFactory.load("chat.conf")) 24 | implicit val materializer = ActorMaterializer() 25 | implicit val timeout = Timeout(1.second) 26 | implicit def sched = system.scheduler 27 | 28 | import system.dispatcher 29 | 30 | val hub = Hub() 31 | 32 | def chatUser(hub: ActorRef[Hub.Message]): Flow[Message, Message, NotUsed] = 33 | Flow 34 | .lazyInitAsync(() => 35 | (hub ? Hub.NewSession).map { sessionRef => 36 | val input: Sink[Message, NotUsed] = Flow[Message].collect { case mes: TextMessage => mes } 37 | .mapAsync(1) { mes => 38 | val builder = StringBuilder.newBuilder 39 | mes.textStream.runForeach(builder ++= _).map(_ => builder.result) 40 | } 41 | .map(parse) 42 | .collect { case Right(json) => json.as[In] } 43 | .collect { case Right(in) => Session.Input(in) } 44 | .log("decode") 45 | .withAttributes(Attributes.logLevels(onElement = Logging.InfoLevel)) 46 | .toMat(Sink.foreach { in => 47 | sessionRef ! in 48 | }) { 49 | case (_, fd) => 50 | fd.onComplete { _ => 51 | println("disconnect") 52 | sessionRef ! Session.Disconnect 53 | } 54 | NotUsed 55 | } 56 | 57 | val output: Source[Message, NotUsed] = 58 | Source 59 | .actorRef[Out](1000, OverflowStrategy.dropHead) 60 | .mapMaterializedValue { ref => 61 | sessionRef ! Session.Init(hub, ref) 62 | NotUsed 63 | } 64 | .map(mess => TextMessage(mess.asJson.spaces2)) 65 | 66 | Flow.fromSinkAndSource(input, output) 67 | }) 68 | .mapMaterializedValue(_ => NotUsed) 69 | 70 | val route = path("chat") { 71 | handleWebSocketMessages(chatUser(hub)) 72 | } 73 | 74 | def main(args: Array[String]): Unit = { 75 | Http() 76 | .bindAndHandle(route, "0.0.0.0", 9889) 77 | .flatMap { bnd => 78 | println(s"bound to ${bnd.localAddress}") 79 | println(s"enter `stop` to shutdown") 80 | while (StdIn.readLine().trim != "stop") {} 81 | bnd.unbind() 82 | } 83 | .flatMap(_ => system.terminate()) 84 | .flatMap(_ => hub.terminate()) 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/main/scala/lectures/matching/SortingStuff.scala: -------------------------------------------------------------------------------- 1 | package lectures.matching 2 | 3 | /** 4 | * Раскладывание вещей по коробкам 5 | * 6 | * У Вас есть вещи 3-х разных типов: 7 | * * * * Watches - часы 8 | * * * * Boots - кроссовки 9 | * * * * Book - книги 10 | * 11 | * Вы хотите привести свои вещи в порядок и оставить только нужные 12 | * Для этого Вы завели себе коробку с отделениями для каждого типа вещей 13 | * * * * * StuffBox 14 | * 15 | * В StuffBox вы кладете вещи таким образом: 16 | * * * * * Все часы дороже 1000 - в StuffBox.watches 17 | * * * * * Все кроссовки от Converse или Adidas - в StuffBox.boots 18 | * * * * * Все интересные книги - в StuffBox.books 19 | * * * * * Остальное - в StuffBox.junk 20 | * 21 | * После того, как Вы разложили вещи, вы пытаетеь найти свой любимый нож, 22 | * который вы могли случайно положить в junk. 23 | * 24 | * После запуска SortingStuff должен напечатать ответ на вопрос: 25 | * "Is the knife in a junk? - " 26 | * 27 | * Чтобы выполнить задание, раскомментируйте код и следуйте подсказкам 28 | * 29 | */ 30 | 31 | object SortingStuff extends App { 32 | 33 | object Knife extends Stuff 34 | 35 | trait Stuff 36 | 37 | case class Boots(brand: String, size: Int = 43) extends Stuff 38 | 39 | case class Watches(brand: String, cost: Float) extends Stuff 40 | 41 | case class Book(name: String, isInteresting: Boolean = false) extends Stuff 42 | 43 | val stuff = List( 44 | Boots("Adidas", 42), 45 | Book("Game of thrones 1", true), 46 | Boots("Reebok", 42), 47 | Watches("Nautica", 10000), 48 | Boots("Converse", 43), 49 | Boots("Converse", 43), 50 | Watches("Breitling", 100000), 51 | Watches("Electronika", 1000), 52 | Boots("Skorohod", 50), 53 | Boots("Noname", 45), 54 | Watches("Zarya", 15000), 55 | Book("Game of thrones 3"), 56 | Book("Game of thrones 4"), 57 | Watches("Casio", 5000), 58 | Watches("Citizen", 5000), 59 | Book("Game of thrones 2", true), 60 | Book("Idiot", true), 61 | Book("Lubovnaya lubov"), 62 | Knife 63 | ) 64 | 65 | case class StuffBox(books: List[Book] = Nil, 66 | watches: List[Watches] = Nil, 67 | boots: List[Boots] = Nil, 68 | junk: List[Stuff] = Nil) 69 | 70 | def sortJunk(stuff: List[Stuff]): StuffBox = ??? ///sort(stuff, StuffBox()) 71 | // // Замените знаки вопроса подходящим кодом 72 | // // Поправьте логику метода 73 | // private def sort(stuff: List[Stuff], stuffBox: StuffBox): StuffBox = ??? { 74 | // case _ => stuffBox 75 | // case ??? => 76 | // val newBox = putStuffInRightBox(item, stuffBox) 77 | // sort(rest, newBox) 78 | // 79 | // } 80 | // // Метод должен положить вещь в правильную коробку 81 | // private def putStuffInRightBox(item: Stuff, stuffBox: StuffBox) = ??? { 82 | // case ??? => stuffBox.copy(watches = it :: stuffBox.watches) 83 | // case junk@_ => stuffBox.copy(junk = junk :: stuffBox.junk) 84 | // case ??? => stuffBox.copy(boots = it :: stuffBox.boots) 85 | // } 86 | // 87 | // def findMyKnife(stuffBox: StuffBox): Boolean = stuffBox match { 88 | // case ??? if junk.contains(Knife) => true 89 | // case _ => false 90 | // } 91 | 92 | // //вместо вопросов подставьте композицию функций sortJunk и findMyKnife 93 | // val knifeIsInJunk = (???) (stuff) 94 | 95 | //print(s"Is knife in a junk? - $knifeIsInJunk") 96 | } 97 | -------------------------------------------------------------------------------- /src/test/scala/inclasss/AkkaTypedHello.scala: -------------------------------------------------------------------------------- 1 | package inclasss 2 | 3 | import akka.actor.typed.scaladsl.Behaviors 4 | import akka.actor.typed.scaladsl.AskPattern._ 5 | import akka.actor.typed.{ActorRef, ActorSystem, Behavior} 6 | import akka.util.Timeout 7 | 8 | import scala.concurrent.duration._ 9 | 10 | object AkkaTypedHello { 11 | 12 | sealed trait Command 13 | 14 | object Command { 15 | 16 | final case class GetGreeter(word: String, respond: ActorRef[ActorRef[GreeterCommand]]) extends Command 17 | 18 | final case class GetGreeting(word: String, personName: String, respond: ActorRef[String]) extends Command 19 | 20 | final case class Delayed(command: Command) extends Command 21 | 22 | } 23 | 24 | sealed trait GreeterCommand 25 | 26 | object GreeterCommand { 27 | 28 | final case class GetGreeting(personName: String, respond: ActorRef[String]) extends GreeterCommand 29 | 30 | } 31 | 32 | def greeter(word: String): Behavior[GreeterCommand] = { 33 | import GreeterCommand._ 34 | Behaviors.receiveMessage { 35 | case GetGreeting(personName, respond) => 36 | respond ! s"$word, $personName !" 37 | Behaviors.same 38 | } 39 | } 40 | 41 | val system = ActorSystem[Command]( 42 | Behaviors.withTimers[Command] { timers => 43 | import Command._ 44 | Behaviors.receive[Command] { 45 | (ctx, message) => 46 | def getGreeter(word: String): ActorRef[GreeterCommand] = 47 | ctx 48 | .child(word) 49 | .map(_.asInstanceOf[ActorRef[GreeterCommand]]) 50 | .getOrElse(ctx.spawn(greeter(word), word)) 51 | 52 | message match { 53 | case GetGreeter(word, respond) => 54 | val actor = getGreeter(word) 55 | respond ! actor 56 | 57 | case msg @ GetGreeting(word, personName, respond) => 58 | timers.startSingleTimer("delay", Delayed(msg), 100.millis) 59 | 60 | case Delayed(GetGreeting(word, personName, respond)) => 61 | getGreeter(word) ! GreeterCommand.GetGreeting(personName, respond) 62 | 63 | } 64 | Behaviors.same 65 | } 66 | }, 67 | "hello" 68 | ) 69 | 70 | def main(args: Array[String]): Unit = { 71 | 72 | import system.executionContext 73 | implicit val sched = system.scheduler 74 | implicit val timeout = Timeout(10.second) 75 | 76 | (system ? ((respond: ActorRef[String]) => Command.GetGreeting("aloha", "Anton", respond))).onComplete { 77 | case util.Success(message) => 78 | println(s"received message: $message") 79 | case util.Failure(ex) => 80 | ex.printStackTrace() 81 | } 82 | 83 | val greeterRef = 84 | system ? ((respond: ActorRef[ActorRef[GreeterCommand]]) => Command.GetGreeter("hello", respond)) 85 | 86 | greeterRef.foreach(_ ? ((respond: ActorRef[String]) => GreeterCommand.GetGreeting("Oleg", respond)) onComplete { 87 | case util.Success(message) => 88 | println(s"received message: $message") 89 | case util.Failure(ex) => 90 | ex.printStackTrace() 91 | }) 92 | // val greeter = system ? (GetGreeter("hello", _: ActorRef[ActorRef[String]])) 93 | 94 | // system ("hello", "Oleg") 95 | // system ! ("aloha", "Anton") 96 | // system ! ("hello", "Anton") 97 | 98 | // system.terminate() 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /src/main/scala/java2scala/Lecture11.scala: -------------------------------------------------------------------------------- 1 | package java2scala 2 | 3 | import cats.{Contravariant, Functor} 4 | import cats.effect.{ExitCode, IO, IOApp, Timer} 5 | 6 | import scala.annotation.unchecked.uncheckedVariance 7 | import scala.collection.mutable 8 | import cats.implicits._ 9 | 10 | import scala.concurrent.duration._ 11 | 12 | object Lecture11 extends IOApp { 13 | 14 | trait X1 { 15 | def thisAndThat(y: Y): List[X1] = List(this, y) 16 | } 17 | 18 | abstract class X extends X1 { 19 | def x: String 20 | 21 | def singleList: List[X] = List(this) 22 | } 23 | 24 | abstract class Y extends X { 25 | def y: Int 26 | 27 | override def singleList: List[Y] = List(this) 28 | } 29 | 30 | abstract class Z extends X { 31 | def z: Double 32 | } 33 | 34 | trait Y1 extends X1 35 | 36 | def foo(x: X): String = x.x 37 | 38 | def bar(y: Y): String = foo(y) 39 | 40 | def fooL(xs: List[X]): String = xs.map(_.x).mkString(",") 41 | 42 | def barL(ys: List[Y]): String = fooL(ys) 43 | 44 | case class Pair[+A](first: A, second: A) { 45 | def _1: A = first 46 | 47 | def toList: List[A] = List(first, second) 48 | 49 | def withFirst[B >: A](newFirst: B): Pair[B] = Pair(newFirst, second) 50 | } 51 | 52 | object Pair { 53 | implicit val functor: Functor[Pair] = new Functor[Pair] { 54 | def map[A, B](fa: Pair[A])(f: A => B): Pair[B] = Pair(f(fa.first), f(fa.second)) 55 | } 56 | } 57 | 58 | val y1 = new Y { def x = "a"; def y = 1 } 59 | val y2 = new Y { def x = "b"; def y = 2 } 60 | val pairOfYs: Pair[Y] = Pair(y1, y2) 61 | 62 | y1.thisAndThat(y2) 63 | 64 | trait Consumer[-A] { 65 | def consume(a: A): IO[Unit] 66 | 67 | def consumeAll(a: List[A]): IO[Unit] = a.traverse_(consume) 68 | } 69 | 70 | object Consumer { 71 | implicit val contravariant: Contravariant[Consumer] = new Contravariant[Consumer] { 72 | def contramap[A, B](fa: Consumer[A])(f: B => A): Consumer[B] = b => fa.consume(f(b)) 73 | } 74 | } 75 | 76 | trait Producer[+A] { 77 | def produce(x: Consumer[A]): IO[Unit] 78 | } 79 | 80 | object Producer { 81 | def of[A](xs: A*): Producer[A] = 82 | consumer => consumer.consumeAll(xs.toList) 83 | 84 | def tick[A](duration: FiniteDuration)(init: A)(f: A => A): Producer[A] = 85 | consumer => { 86 | def go(x: A): IO[Unit] = 87 | for { 88 | _ <- consumer.consume(x) 89 | _ <- Timer[IO].sleep(duration) 90 | res <- go(f(x)) 91 | } yield res 92 | go(init) 93 | } 94 | 95 | implicit val functor: Functor[Producer] = ??? 96 | } 97 | 98 | val printer: Consumer[String] = s => IO(println(s)) 99 | 100 | val xPrinter: Consumer[X] = x => IO(println(s"x: ${x.x}")) 101 | 102 | def consumerManyYs(consumer: Consumer[Y]): IO[Unit] = 103 | consumer.consume(new Y { def x = "a"; def y = 1 }) *> 104 | consumer.consume(new Y { def x = "b"; def y = 2 }) 105 | 106 | consumerManyYs(xPrinter.contramap(y => y)) 107 | consumerManyYs(xPrinter) 108 | 109 | // same as 110 | // def consumerManyYs[T >: Y](consumer: Consumer[T]): IO[Unit] = 111 | // consumer.consume(new Y { def x = "a"; def y = 1 }) *> 112 | // consumer.consume(new Y { def x = "b"; def y = 2 }) 113 | 114 | val ys: Producer[Y] = Producer.of(y1, y2) 115 | 116 | val zs = Producer.tick[Z](1 second)(new Z { def x = "start"; def z = 0 })( 117 | prev => new Z { def x = s"next ${prev.z}"; def z = prev.z + 1 } 118 | ) 119 | 120 | def printAll(producer: Producer[X]): IO[Unit] = 121 | producer.produce(xPrinter) 122 | 123 | def run(args: List[String]): IO[ExitCode] = 124 | printAll(ys) *> printAll(zs) as ExitCode.Success 125 | } 126 | -------------------------------------------------------------------------------- /src/main/scala/java2scala/homeworks/CharAutomata.scala: -------------------------------------------------------------------------------- 1 | package java2scala.homeworks 2 | 3 | trait CharAutomata[+A] { 4 | 5 | /** потребить один символ и перейти в следующее состояние */ 6 | def consume(char: Char): CharAutomata[A] 7 | 8 | /** получить текущий результат, если это конец строки */ 9 | def result: Either[String, A] 10 | 11 | /** потребить строку символ за символом */ 12 | def apply(source: String): Either[String, A] = ??? 13 | 14 | /** создать автомат, который запустит оба автомата 15 | * и если первый вернёт ошибку, вернёт результат второго 16 | */ 17 | def or[B](auto: CharAutomata[B]): CharAutomata[Either[A, B]] = ??? 18 | 19 | /** создать автомат, который запустит оба автомата 20 | * вернёт результаты обоих, если оба вернут успешный результат 21 | * и вернёт ошибку, если вернёт ошибку хотя бы один 22 | */ 23 | def and[B](auto: CharAutomata[B]): CharAutomata[(A, B)] = ??? 24 | } 25 | 26 | object CharAutomata { 27 | 28 | /** создаёт автомат, всегда результирующий с ошибкой 29 | * с заданным текстом message 30 | */ 31 | def error(message: String): CharAutomata[Nothing] = ??? 32 | 33 | /** создаёт автомат, всегда успешно результирующий 34 | * с заданным значением `value` 35 | */ 36 | def const[A](value: A): CharAutomata[A] = ??? 37 | 38 | /** создаёт автомат, возвращающий 39 | * первое вхождение строчки `substring` 40 | * или ошибкой 41 | */ 42 | def find(substring: String): CharAutomata[Int] = ??? 43 | 44 | /** создаёт автомат, определяющий является ли строчка, 45 | * если исключить из неё все символы, кроме `'('` и `')'` 46 | * корректной скобочной последовательностью */ 47 | def balance: CharAutomata[Unit] = ??? 48 | 49 | /** создаёт автомат, ищущий первое число, из цифр подряд 50 | * и возвращающий результат в качестве BigInt либо 0 51 | */ 52 | def parseInt: CharAutomata[BigInt] = ??? 53 | 54 | /** класс для реализации метода `error` */ 55 | class Error(string: String) extends CharAutomata[Nothing] { 56 | def consume(char: Char): CharAutomata[Nothing] = ??? 57 | 58 | def result: Either[String, Nothing] = ??? 59 | } 60 | 61 | /** класс для реализации метода `const` */ 62 | class Const[A] private[CharAutomata] (value: A) extends CharAutomata[A] { 63 | def consume(char: Char): CharAutomata[A] = ??? 64 | 65 | def result: Either[String, A] = ??? 66 | } 67 | 68 | /** класс для реализации метода `find` */ 69 | class Find private[CharAutomata] (substring: String) extends CharAutomata[Int] { 70 | def consume(char: Char): CharAutomata[Int] = ??? 71 | 72 | def result: Either[String, Int] = ??? 73 | } 74 | 75 | /** класс для реализации метода `balance` */ 76 | class ParenBalance private[CharAutomata] extends CharAutomata[Unit] { 77 | def consume(char: Char): CharAutomata[Unit] = ??? 78 | 79 | def result: Either[String, Unit] = ??? 80 | } 81 | 82 | /** класс для реализации метода `parseInt` */ 83 | class ParseInteger private[CharAutomata] extends CharAutomata[BigInt] { 84 | def consume(char: Char): CharAutomata[BigInt] = ??? 85 | 86 | def result: Either[String, BigInt] = ??? 87 | } 88 | 89 | /** класс для реализации метода `and` */ 90 | class And[A, B] private[CharAutomata] (autoA: CharAutomata[A], autoB: CharAutomata[B]) extends CharAutomata[(A, B)] { 91 | def consume(char: Char): CharAutomata[(A, B)] = ??? 92 | 93 | def result: Either[String, (A, B)] = ??? 94 | } 95 | 96 | /** класс для реализации метода `or` */ 97 | class Or[A, B] private[CharAutomata] (autoA: CharAutomata[A], autoB: CharAutomata[B]) extends CharAutomata[Either[A, B]] { 98 | def consume(char: Char): CharAutomata[Either[A, B]] = ??? 99 | 100 | def result: Either[String, Either[A, B]] = ??? 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/main/scala/java2scala/tagless/FromProduct.scala: -------------------------------------------------------------------------------- 1 | package java2scala.tagless 2 | 3 | import cats.{Eq, Order, Show} 4 | import simulacrum.typeclass 5 | import cats.syntax.order._ 6 | import cats.syntax.show._ 7 | import cats.instances.string._ 8 | import cats.instances.bigDecimal._ 9 | import Conditional.ops._ 10 | import FromProduct.ops._ 11 | import ToProduct.ops._ 12 | 13 | @typeclass 14 | trait FromProduct[F[_]] { 15 | def price: F[BigDecimal] 16 | def color: F[String] 17 | } 18 | 19 | object FromProduct { 20 | implicit def show: FromProduct[ShowF] = new FromProduct[ShowF] { 21 | def price: String = "[price]" 22 | def color: String = "[color]" 23 | } 24 | implicit def prod: FromProduct[ProdF] = new FromProduct[ProdF] { 25 | def price: ProdF[BigDecimal] = p => p.price 26 | def color: ProdF[String] = p => p.color 27 | } 28 | } 29 | 30 | trait Comparison[F[_], A] { 31 | def eq1(x: F[A], y: F[A]): F[Boolean] 32 | def gt(x: F[A], y: F[A]): F[Boolean] 33 | } 34 | 35 | object Comparison { 36 | def apply[F[_], A](implicit comp: Comparison[F, A]): Comparison[F, A] = comp 37 | 38 | implicit def show[A]: Comparison[ShowF, A] = new Comparison[ShowF, A] { 39 | def eq1(x: ShowF[A], y: ShowF[A]): ShowF[Boolean] = s"$x == $y" 40 | def gt(x: ShowF[A], y: ShowF[A]): ShowF[Boolean] = s"$x <= $y" 41 | } 42 | 43 | implicit def prod[A: Order]: Comparison[ProdF, A] = new Comparison[ProdF, A] { 44 | def eq1(x: ProdF[A], y: ProdF[A]): ProdF[Boolean] = p => x(p) === y(p) 45 | def gt(x: ProdF[A], y: ProdF[A]): ProdF[Boolean] = p => x(p) >= y(p) 46 | } 47 | } 48 | 49 | trait Const[F[_], A] { 50 | def value(a: A): F[A] 51 | } 52 | 53 | object Const { 54 | def apply[F[_], A](implicit cnst: Const[F, A]) = cnst 55 | 56 | implicit def show[A: Show]: Const[ShowF, A] = new Const[ShowF, A] { 57 | def value(a: A): ShowF[A] = a.show 58 | } 59 | 60 | implicit def prod[A]: Const[ProdF, A] = new Const[ProdF, A] { 61 | def value(a: A): ProdF[A] = _ => a 62 | } 63 | } 64 | 65 | @typeclass 66 | trait ToProduct[F[_]] { 67 | def product(price: F[BigDecimal], color: F[String]): F[Product] 68 | } 69 | 70 | object ToProduct { 71 | implicit val show: ToProduct[ShowF] = new ToProduct[ShowF] { 72 | def product(price: String, color: String): String = 73 | s"Product(price = $price, color = $color" 74 | } 75 | 76 | implicit val prod: ToProduct[ProdF] = new ToProduct[ProdF] { 77 | def product(price: ProdF[BigDecimal], color: ProdF[String]): ProdF[Product] = 78 | p => Product(color(p), price(p)) 79 | } 80 | } 81 | 82 | @typeclass 83 | trait Conditional[F[_]] { 84 | def ifThenElse[A](cond: F[Boolean], th: F[A], el: F[A]): F[A] 85 | } 86 | 87 | object Conditional { 88 | implicit val show: Conditional[ShowF] = new Conditional[ShowF] { 89 | def ifThenElse[A](cond: String, th: String, el: String): String = 90 | s"if ($cond) then $th else $el" 91 | } 92 | 93 | implicit val prod: Conditional[ProdF] = new Conditional[ProdF] { 94 | def ifThenElse[A](cond: ProdF[Boolean], th: ProdF[A], el: ProdF[A]): ProdF[A] = 95 | p => if (cond(p)) th(p) else el(p) 96 | } 97 | } 98 | 99 | object TypedTF extends App { 100 | def mutate[ 101 | F[_]: FromProduct: ToProduct: Const[?[_], String]: Const[?[_], BigDecimal]: Conditional: Comparison[?[_], String]] = 102 | Conditional[F].ifThenElse( 103 | Comparison[F, String] 104 | .eq1(FromProduct[F].color, Const[F, String].value("red")), 105 | ToProduct[F].product( 106 | FromProduct[F].price, 107 | Const[F, String].value("yellow") 108 | ), 109 | ToProduct[F].product( 110 | Const[F, BigDecimal].value(100), 111 | FromProduct[F].color 112 | ) 113 | ) 114 | 115 | println(mutate[ShowF]) 116 | 117 | println(mutate[ProdF].apply(Product(color = "red", price = 50))) 118 | println(mutate[ProdF].apply(Product(color = "yellow", price = 50))) 119 | 120 | } 121 | -------------------------------------------------------------------------------- /src/main/scala/java2scala/Lecture9.scala: -------------------------------------------------------------------------------- 1 | package java2scala 2 | 3 | import java.time.Instant 4 | 5 | import cats.Eval 6 | import cats.effect.{ExitCode, IO, IOApp, Timer} 7 | import cats.effect.concurrent.{Deferred, MVar} 8 | 9 | import scala.concurrent.duration._ 10 | import cats.implicits._ 11 | import cats.effect.syntax.all._ 12 | 13 | trait ChurchList[A] { self => 14 | def fold[R](z: Eval[R])(ag: A => Eval[R] => Eval[R]): Eval[R] 15 | 16 | def ::(x: A): ChurchList[A] = new ChurchList[A] { 17 | def fold[R](z: Eval[R])(ag: A => Eval[R] => Eval[R]): Eval[R] = 18 | Eval.defer(ag(x)(self.fold(z)(ag))) 19 | } 20 | 21 | def map[B](f: A => B): ChurchList[B] = 22 | new ChurchList[B] { 23 | def fold[R](z: Eval[R])(ag: B => Eval[R] => Eval[R]): Eval[R] = 24 | self.fold(z)(a => ag(f(a))) 25 | } 26 | 27 | def filter(p: A => Boolean): ChurchList[A] = new ChurchList[A] { 28 | def fold[R](z: Eval[R])(ag: A => Eval[R] => Eval[R]): Eval[R] = 29 | self.fold(z)(a => if (p(a)) ag(a) else identity) 30 | } 31 | 32 | def flatMap[B](f: A => ChurchList[B]): ChurchList[B] = new ChurchList[B] { 33 | def fold[R](z: Eval[R])(ag: B => Eval[R] => Eval[R]): Eval[R] = 34 | self.fold(z)(a => r => f(a).fold(r)(ag)) 35 | } 36 | 37 | def ++(that: ChurchList[A]): ChurchList[A] = new ChurchList[A] { 38 | def fold[R](z: Eval[R])(ag: A => Eval[R] => Eval[R]): Eval[R] = self.fold(that.fold(z)(ag))(ag) 39 | } 40 | 41 | def drop(count: Int): ChurchList[A] = 42 | self 43 | .fold[Int => Eval[ChurchList[A]]](Eval.now(i => Eval.now(ChurchList.empty)))( 44 | a => 45 | lf => 46 | Eval.later { 47 | case 0 => lf.flatMap(f => f(0).map(a :: _)) 48 | case i => lf.flatMap(f => f(i - 1)) 49 | } 50 | ) 51 | .value(count) 52 | .value 53 | 54 | def headOption: Option[A] = fold[Option[A]](Eval.now(None))(a => b => Eval.now(Some(a))).value 55 | 56 | def toList: List[A] = fold[List[A]](Eval.now(Nil))(e => ll => ll.map(e :: _)).value 57 | } 58 | 59 | object ChurchList { 60 | def apply[A](xs: A*): ChurchList[A] = new ChurchList[A] { 61 | def fold[R](z: Eval[R])(ag: A => Eval[R] => Eval[R]): Eval[R] = xs.foldRight(z)((a, lb) => ag(a)(lb)) 62 | } 63 | 64 | def empty[A]: ChurchList[A] = new ChurchList[A] { 65 | def fold[R](z: Eval[R])(ag: A => Eval[R] => Eval[R]): Eval[R] = z 66 | } 67 | } 68 | 69 | object Lecture9 extends App { 70 | val list = List.range(1, 10000).foldRight(ChurchList.empty[Int])(_ :: _) 71 | 72 | println(list.fold(Eval.now(0))(x => y => y.map(_ + x)).value) 73 | } 74 | 75 | object Lecture9IO extends IOApp { 76 | def currentTime: IO[String] = 77 | for (millis <- Timer[IO].clock.realTime(MILLISECONDS)) 78 | yield Instant.ofEpochMilli(millis).toString 79 | 80 | def produce(name: String, mvar: MVar[IO, (String, Double)], idx: Int = 0): IO[Nothing] = 81 | for { 82 | _ <- IO(println(s"producing $name $idx")) 83 | _ <- mvar.put(name -> (idx * 0.5)) 84 | time <- currentTime 85 | _ <- IO(println(s"produced $name $idx $time")) 86 | _ <- Timer[IO].sleep(1.1 second) 87 | res <- produce(name, mvar, idx + 1) 88 | } yield res 89 | 90 | def consumer(name: String, mvar: MVar[IO, (String, Double)], limit: Double = 10): IO[String] = 91 | for { 92 | _ <- IO(println(s"consuming $name left $limit")) 93 | (pinger, quantity) <- mvar.take 94 | time <- currentTime 95 | _ <- IO(println(s"$name received $quantity from $pinger $time")) 96 | _ <- Timer[IO].sleep(1.4 second) 97 | res <- if (limit > quantity) consumer(name, mvar, limit - quantity) else IO(name) 98 | } yield res 99 | 100 | val process: IO[Unit] = for { 101 | x <- MVar[IO].empty[(String, Double)] 102 | y <- MVar[IO].empty[(String, Double)] 103 | charlie <- produce("Charlie", x).start 104 | alice <- produce("Alice", x).start 105 | stas <- produce("Stas", y).start 106 | name <- consumer("Bob", x).race(consumer("Oleg", y, 1000)) 107 | _ <- IO(println(s"completed $name")) 108 | } yield () 109 | 110 | def run(args: List[String]): IO[ExitCode] = process as ExitCode.Success 111 | } 112 | -------------------------------------------------------------------------------- /src/main/resources/программа обучения.txt: -------------------------------------------------------------------------------- 1 | Цели и структура курса 2 | Настрока рабочего места. Инсталяция scala, idea, sbt. 3 | Запуск пробного предустановленного проекта 4 | 5 | Введение 6 | Виды яыков. Функциональные языки 7 | Scala - multi-paradigm 8 | Примеры 9 | Императивный стиль 10 | Функциональный стиль 11 | Типы в скала 12 | Иерархия типов 13 | Вывод типов 14 | Задания 15 | Основные конструкциии языка 16 | Пакеты 17 | Импорты 18 | Переименование пакетов 19 | Определения 20 | Константы 21 | Переменные 22 | Ленивые декларации 23 | Функции 24 | Функции 25 | Значения по умолчанию 26 | Процедуры 27 | Переменная длинна аргументов 28 | Функции как значения. Функции высшего порядка. 29 | Каррированные функции 30 | Композиция функций одной переменной 31 | compose, andThen 32 | Композиция функций несколькоих переменных 33 | curried, tupled 34 | Call-by-name параметры 35 | Разрешение циклических зависимостей 36 | Повторное вычисление 37 | Функции. Задания 38 | Операторы 39 | Операторы витвления IF 40 | Циклы 41 | Задания 42 | Pattern Matching 43 | Синтаксис 44 | Возможности 45 | Пример для case class 46 | Пример для коллекции 47 | Задания 48 | Partial functions 49 | Задания 50 | Обзор коллекций 51 | Коллекции в скала 52 | Трейты, составляющие основу коллекций в scala 53 | Основные методы (map, flatMap, collect, foldLeft, transform ...) 54 | Примеры коллекций 55 | Option 56 | Задания 57 | For comprehension 58 | Tuples 59 | Задания 60 | Объекты и классы 61 | Классы 62 | Уровни доступа Private, public, protected. 63 | Ограничение досупа(scoped). До пакета. До инстанса. 64 | Кейс классы. 65 | Трейты 66 | Объекты. Кейс объекты. Объекты компаньоны 67 | Чем полезны компаньоны 68 | Подробнее об apply 69 | Подробнее об unapply 70 | Задания 71 | Коротко о тестировании в скала. 72 | ScalaTest 73 | FunSuit 74 | FlatSpec 75 | WordSpec 76 | Mocks 77 | ScalaCheck 78 | Задания 79 | Исключительные ситуации 80 | Checked / Unckecked / Fatal / NonFatal 81 | try{}catch{} 82 | Try{} 83 | Задания 84 | ООП 85 | extends и with 86 | Полиморфизм, инкапсуляция, наследование, абстракция. 87 | SOLID 88 | Наследлвание в скала 89 | Линейное наследоване, ключевое слово extends, ключевое слово override 90 | Super, final, sealed 91 | Mix in наследование - трейты 92 | Diamond problem. 93 | Линеизация 94 | Анонимные классы 95 | Self type annotation 96 | Задания 97 | Type parameters. Общая информация. 98 | Экзистенциальные типы 99 | Конструктор типов. Higher Kinded Type 100 | Ограничение параметров типов (type bounds) 101 | Вариативность, ковариантность, контрвариантность 102 | Структурные типы 103 | Абстрактные типы 104 | В чем разница между абстрактные типами и тайп параметрами. 105 | type erasure 106 | Задания 107 | Имплиситы. 108 | Механизм обнаружения и работы имплиситов 109 | Implicit conversions. Pimp my library. Примеры из predef. 110 | Implicit parameters 111 | Implicit contexts 112 | Type classes 113 | Задания 114 | Потоки (Streams) 115 | Структурные типы 116 | Path dependent types 117 | Асинхронность в SCALA 118 | Futures 119 | Как выполняеться Future. ExecutionContext. ForkJoinPool 120 | Статические методы 121 | Callback функции 122 | Комбинаторы над Future 123 | Promise, зачем он нужен. Пример 124 | Правила работы с Future 125 | Задание 126 | Akka actors 127 | Что такое актор. 128 | Actor System. Конфигурция и применение 129 | Простой актор 130 | методы Ask, tell, receive 131 | SupervisionStrategy. 132 | Метод become. 133 | 134 | SBT в деталях 135 | Структура проекта SBT 136 | build.sbt 137 | project 138 | зависимости 139 | контексты 140 | config 141 | project 142 | task 143 | создание своего таска 144 | плагины 145 | 146 | Связь с JAVA. 147 | Конвертация коллекций 148 | Способы исследования сгенерированного кода 149 | JAD 150 | javap 151 | 152 | Мат. часть 153 | Понятяие категории. Морфизмы. Функторы. 154 | Монада и моноид 155 | Applicative 156 | Применение в скале. 157 | Функциональные шаблоны. 158 | Free monada. 159 | Trampoline 160 | Reader monada. 161 | список для самостоятельного изучения. 162 | 163 | Ограничения и подводные камни 164 | инициализация lazy val 165 | def vs val и ETA conversion 166 | -------------------------------------------------------------------------------- /src/main/scala/lectures/collections/CherryTree.scala: -------------------------------------------------------------------------------- 1 | package lectures.collections 2 | 3 | import lectures.collections.CherryTree.{Node, Node1, Node2} 4 | 5 | import scala.collection.generic._ 6 | import scala.collection.{GenTraversableOnce, LinearSeq, LinearSeqOptimized, mutable} 7 | 8 | sealed trait CherryTree[+T] extends LinearSeq[T] 9 | with LinearSeqOptimized[T, CherryTree[T]] 10 | with GenericTraversableTemplate[T, CherryTree] 11 | with Product with Serializable{ 12 | override def init: CherryTree[T] = ??? 13 | override def last: T = ??? 14 | def append[S >: T](x: S): CherryTree[S] 15 | def prepend[S >: T](x: S): CherryTree[S] = ??? 16 | def concat[S >: T](xs: CherryTree[S]): CherryTree[S] = ??? 17 | override def toString(): String = super.toString() 18 | override def companion = CherryTree 19 | override def stringPrefix: String = "CherryTree" 20 | 21 | 22 | // If we have a default builder, there are faster ways to perform some operations 23 | @inline private[this] def isDefaultCBF[A, B, That](bf: CanBuildFrom[CherryTree[A], B, That]): Boolean = bf eq CherryTree.ReusableCBF 24 | 25 | override def :+[B >: T, That](elem: B)(implicit bf: CanBuildFrom[CherryTree[T], B, That]) = 26 | if (isDefaultCBF(bf)) append(elem).asInstanceOf[That] else super.:+(elem) 27 | 28 | override def +:[B >: T, That](elem: B)(implicit bf: CanBuildFrom[CherryTree[T], B, That]) = 29 | if (isDefaultCBF(bf)) prepend(elem).asInstanceOf[That] else super.:+(elem) 30 | 31 | override def ++[B >: T, That](that: GenTraversableOnce[B])(implicit bf: CanBuildFrom[CherryTree[T], B, That]) = 32 | if (isDefaultCBF(bf)) concat(that.asInstanceOf[CherryTree[B]]).asInstanceOf[That] else super.++(that) 33 | } 34 | case object CherryNil extends CherryTree[Nothing] { 35 | override def head = throw new NoSuchElementException("head of empty CherryList") 36 | override def tail = throw new UnsupportedOperationException("tail of empty CherryList") 37 | override def foreach[U](f: (Nothing) => U) = () 38 | override def append[S >: Nothing](x: S): CherryTree[S] = CherrySingle(x) 39 | override def size = 0 40 | override def isEmpty = true 41 | } 42 | final case class CherrySingle[+T](x: T) extends CherryTree[T] { 43 | override def head = x 44 | override def tail = CherryNil 45 | override def foreach[U](f: T => U) = f(x) 46 | def append[S >: T](y: S) = CherryBranch(Node1(x), CherryNil, Node1(y)) 47 | override def size = 1 48 | override def isEmpty = false 49 | } 50 | final case class CherryBranch[+T](left: Node[T], inner: CherryTree[Node2[T]], right: Node[T]) extends CherryTree[T] { 51 | override def head = left match { 52 | case Node1(x) => x 53 | case Node2(x, _) => x 54 | } 55 | override def tail = left match { 56 | case Node1(_) => inner match { 57 | case CherryNil => right match { 58 | case Node1(x) => CherrySingle(x) 59 | case Node2(x, y) => CherryBranch(Node1(x), CherryNil, Node1(y)) 60 | } 61 | case tree => CherryBranch(tree.head, tree.tail, right) 62 | } 63 | case Node2(_, x) => CherryBranch(Node1(x), inner, right) 64 | } 65 | override def foreach[U](f: T => U) = { 66 | left.foreach(f) 67 | inner.foreach(_.foreach(f)) 68 | right.foreach(f) 69 | } 70 | def append[S >: T](x: S) = right match { 71 | case Node1(y) => CherryBranch(left, inner, Node2(y, x)) 72 | case n: Node2[S] => CherryBranch(left, inner.append(n), Node1(x)) 73 | } 74 | override def size = left.size + inner.size * 2 + right.size 75 | override def isEmpty = false 76 | } 77 | 78 | 79 | object CherryTree extends SeqFactory[CherryTree] { 80 | private class CherryTreeBuilder[T]() extends mutable.Builder[T, CherryTree[T]] { 81 | private[this] var coll: CherryTree[T] = CherryNil 82 | def +=(elem: T) = {coll = coll.append(elem); this } 83 | def clear(): Unit = coll = CherryNil 84 | def result: CherryTree[T] = coll 85 | } 86 | 87 | implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, CherryTree[A]] = 88 | ReusableCBF.asInstanceOf[GenericCanBuildFrom[A]] 89 | 90 | def newBuilder[T]: mutable.Builder[T, CherryTree[T]] = new CherryTreeBuilder[T] 91 | 92 | sealed trait Node[+T] { 93 | def foreach[U](f: T => U): Unit 94 | def size: Int 95 | } 96 | final case class Node1[+T](x: T) extends Node[T] { 97 | override def foreach[U](f: (T) => U): Unit = f(x) 98 | def size = 1 99 | } 100 | final case class Node2[+T](x: T, y: T) extends Node[T] { 101 | def foreach[U](f: (T) => U): Unit = { 102 | f(x) 103 | f(y) 104 | } 105 | def size = 2 106 | } 107 | } 108 | 109 | -------------------------------------------------------------------------------- /src/main/scala/java2scala/Lecture6.scala: -------------------------------------------------------------------------------- 1 | package java2scala 2 | import scala.collection.immutable.{Seq, IndexedSeq} 3 | 4 | import scala.reflect.runtime.universe._ 5 | // 6 | object Lecture6 extends App { 7 | // println(List("foo", "bar", "baz").zipWithIndex) 8 | val res0 = for (x <- List(1, 2, 3)) yield x + 1 9 | val res0Desugared = List(1, 2, 3).map(x => x + 1) 10 | assert(res0 == res0Desugared) 11 | 12 | val res1 = for { 13 | x <- List(1, 2, 3) 14 | y <- List.range(0, x) 15 | } yield x + y 16 | val res1Desugared = List(1, 2, 3).flatMap(x => List.range(0, x).map(y => x + y)) 17 | 18 | val res2 = for { 19 | x <- List(1, 2, 3, 4) 20 | y <- List.range(0, x) 21 | z <- List.range(0, y) 22 | } yield x + y + z 23 | 24 | val res2Desugared = 25 | List(1, 2, 3, 4).flatMap { x => 26 | List.range(0, x).flatMap { y => 27 | List.range(0, y).map { z => 28 | x + y + z 29 | } 30 | } 31 | } 32 | 33 | val res3 = for { 34 | x <- List(1, 2, 3, 4) 35 | y <- List(1, 2, 3, 4) 36 | z <- List(1, 2, 3, 4) 37 | } yield 1 38 | 39 | val res3Desugared1 = 40 | List(1, 2, 3, 4).flatMap { x => 41 | List(1, 2, 3, 4).flatMap { y => 42 | List(1, 2, 3, 4).map { z => 43 | 1 44 | } 45 | } 46 | } 47 | 48 | val res3Desugared2 = 49 | List(1, 2, 3, 4).flatMap { x => 50 | List(1, 2, 3, 4) 51 | }.flatMap { y => 52 | List(1, 2, 3, 4) 53 | }.map { z => 54 | 1 55 | } 56 | 57 | val res4 = for { 58 | x <- List(1, 2, 3, 4) 59 | y <- List.range(0, x) if x + y < 5 60 | z <- List.range(0, y) 61 | } yield x + y + z 62 | 63 | val res4Desugared = 64 | List(1, 2, 3, 4).flatMap { x => 65 | List.range(0, x).withFilter(y => x + y < 5).flatMap { y => 66 | List.range(0, y).map { z => 67 | x + y + z 68 | } 69 | } 70 | } 71 | 72 | val res5 = for { 73 | x <- List(1, 2, 3, 4) 74 | y <- List.range(0, x) 75 | (z, i) <- List.range(0, y).zipWithIndex 76 | } yield x + y + z + i 77 | 78 | val res5Desugared = 79 | List(1, 2, 3, 4).flatMap { x => 80 | List.range(0, x).withFilter(y => x + y < 5).flatMap { y => 81 | List.range(0, y).zipWithIndex.map { p => 82 | val z = p._1 83 | val i = p._2 84 | x + y + z + i 85 | } 86 | } 87 | } 88 | 89 | def res6 = 90 | for { 91 | x <- List(1, 2, 3, 4) 92 | y <- List.range(0, x) 93 | (z, i) <- List.range(0, y).zipWithIndex 94 | } println(x + y + z + i) 95 | 96 | def res6Desugared = 97 | List(1, 2, 3, 4).foreach { x => 98 | List.range(0, x).foreach { y => 99 | if (x + y < 5) 100 | List.range(0, y).zipWithIndex.foreach { p => 101 | val z = p._1 102 | val i = p._2 103 | x + y + z + i 104 | } 105 | } 106 | } 107 | 108 | List(1, 2, 3).flatMap(x => Some(x).filter(_ > 1)) 109 | // val res = for { 110 | // x <- Vector(1, 2, 3) 111 | // list = List.range(x, 0, -1) 112 | // (y, i) <- list.zipWithIndex 113 | // } yield s" {x = $x, y = $y, i = $i}" 114 | // 115 | // res.foreach(println) 116 | // println(res) 117 | 118 | final class Fruit(val name: String, val color: Long) 119 | 120 | object Fruit { 121 | def apply(name: String, color: Long): Fruit = new Fruit(name, color) 122 | def unapply(x: Fruit): Option[(String, Long)] = Some((x.name, x.color)).filter(_._2 != 2) 123 | } 124 | 125 | object pear { 126 | def unapply(x: Fruit): Boolean = x.name == "pear" 127 | } 128 | 129 | object fruirs { 130 | def unapplySeq(x: Fruit): Option[List[Int]] = Some(List.range(1, x.color.toInt)) 131 | } 132 | 133 | val fruit = Fruit("pear", 2) 134 | 135 | // fruit match { 136 | // case fruirs(c) => println(s"fruirs : $c") 137 | // case pear() => println("a pear") 138 | // case Fruit(name, color) => println((name, color)) 139 | // case _ => println("something else") 140 | // } 141 | 142 | val xs = List(1, 2, 3, 4, 5, 6, 7) 143 | 144 | xs match { 145 | case Seq() => "empty" 146 | case Seq(a, 3, c, rest @ _*) => println(a, c, rest) 147 | case _ => "???" 148 | } 149 | 150 | object Lol { 151 | def apply(xs: Int*) = xs ++ xs 152 | } 153 | 154 | // println(Lol(List.range(1, 10): _*)) 155 | 156 | val digits = ".*?(\\d+).*?(\\d+).*".r 157 | 158 | // println(digits.findFirstMatchIn("asdfsd123123fd232sf").map(_.group(1))) 159 | 160 | "asdfsd123123fd232sf" match { 161 | case digits(x, y) => println(x, y) 162 | } 163 | 164 | } 165 | -------------------------------------------------------------------------------- /src/main/scala/java2scala/Lecture4.scala: -------------------------------------------------------------------------------- 1 | package java2scala 2 | 3 | import java2scala.Lecture3.{Base, Color, GenColor} 4 | import java2scala.Lecture3.Color.{Blue, Green, Red} 5 | 6 | import scala.Function.const 7 | 8 | trait ShowInt { 9 | def name(n: Int): String 10 | 11 | def name2(n: Int, m: Int): String = s"${name(n)} :: ${name(m)}" 12 | } 13 | 14 | case class Lol() { 15 | def sdfsdf_+++++(lol: Lol): String = "lol" 16 | } 17 | 18 | object Lecture4 extends App { 19 | type BoolToBool = Boolean => Boolean 20 | type BoolToBool2 = Function1[Boolean, Boolean] 21 | type BoolAndStrinToDouble = Function2[Boolean, String, Double] 22 | type BoolAndStrinToDouble2 = (Boolean, String) => Double 23 | type MakeString = () => String 24 | type MakeString2 = Function0[String] 25 | 26 | type Tuple0 = Unit 27 | val x: Tuple0 = () 28 | type IntToString = Int => String 29 | 30 | type BoolAndInt = (Boolean, Int) 31 | val boolAndInt = (true, 4) 32 | 33 | val (someBool, someInt) = boolAndInt 34 | 35 | final case class Person(infant: Boolean, name: String) 36 | 37 | val person = Person(false, "Eldar") 38 | 39 | val Person(infant, name) = person 40 | 41 | val bid: BoolToBool = x => x 42 | val bnot: BoolToBool = !_ 43 | val constTrue: BoolToBool = _ => true 44 | val constFalse: BoolToBool = const(false) 45 | 46 | val plus3: Int => Int = x => x + 3 47 | val plus4: Int => Int = _ + 4 48 | val plus5: Int => Int = 5 + 49 | val plus5a: Int => Int = x => 5.+(x) 50 | val plus5b: Int => Int = 5.+ 51 | 52 | val xx = 5.+(1) 53 | val xx2 = 5 + 1 54 | 55 | val u = (i: Long) => 6 + i 56 | 57 | def foo(int: Int, long: Long, str: String, double: Double): Boolean = int == long 58 | 59 | val y = namer.name2 _ 60 | val y1 = namer.name2(3, _) 61 | 62 | // println(plus3(2)) 63 | // println(plus4(2)) 64 | // println(plus5(2)) 65 | 66 | def foo1 = foo _ 67 | def foo2 = foo(1, _, "sss", _) 68 | 69 | val namer: ShowInt = x => s"the int $x" 70 | 71 | def name3(x: Int, y: Int, namer: ShowInt) = println(namer.name2(x, y)) 72 | 73 | name3(-1, 4, x => s"the int $x") 74 | 75 | val colorToBool: Color => Boolean = { 76 | case Red => true 77 | case Blue | Green => false 78 | } 79 | 80 | val genColorToString: GenColor => String = { 81 | case Base(color) => s"base $color" 82 | case _ => "not base" 83 | } 84 | 85 | val plus: Int => Int => Int = x => y => x + y 86 | val plus2: (Int, Int) => Int = (x, y) => x + y 87 | def plus2a = plus2.curried 88 | 89 | def plusM(x: Int)(y: Int) = x + y 90 | def plusS(x: Int, y: Int) = x + y 91 | 92 | def transformInt(x: Int, f: Int => Int) = f(x) 93 | println(transformInt(6, plusS(4, _))) 94 | println(transformInt(6, plusM(4))) 95 | 96 | sealed trait EvenList[A] { 97 | override def toString = { 98 | val builder = StringBuilder.newBuilder 99 | builder ++= "EvenList(" 100 | def go(lst: EvenList[A]): Unit = lst match { 101 | case EvenNil() => 102 | case cons: EvenCons[A] => 103 | builder ++= cons.x.toString 104 | builder ++= ", " 105 | builder ++= cons.y.toString 106 | builder ++= ", " 107 | go(cons.tail) 108 | } 109 | go(this) 110 | builder append ")" 111 | builder.result() 112 | } 113 | } 114 | 115 | case class EvenNil[A]() extends EvenList[A] 116 | class EvenCons[A](val x: A, val y: A, tail0: => EvenList[A]) extends EvenList[A] { 117 | lazy val tail = tail0 118 | } 119 | 120 | object EvenCons { 121 | def apply[A](x: A, y: A, tail: => EvenList[A]): EvenCons[A] = new EvenCons(x, y, tail) 122 | } 123 | 124 | // def sumOdd(lst: EvenList[Int]): Int = lst match { 125 | // case EvenNil() => 0 126 | // case EvenCons(x, y, rest) => y + sumOdd(rest()) 127 | // } 128 | // 129 | // val sumOddA: EvenList[Int] => Int = { 130 | // case EvenNil() => 0 131 | // case EvenCons(x, y, rest) => y + sumOddA(rest()) 132 | // } 133 | 134 | def app[A, B](x: A, f: A => B): B = f(x) 135 | 136 | // def range(from: Int, to: Int): EvenList[Int] = { 137 | // def go(to: Int, acc: EvenList[Int]): EvenList[Int] = 138 | // if (from >= to - 1) acc 139 | // else go(to - 2, new EvenCons(to - 2, to - 1, acc)) 140 | // 141 | // go(to, EvenNil()) 142 | // } 143 | 144 | def range2(from: Int, to: Int): EvenList[Int] = 145 | if (from >= to - 1) EvenNil() 146 | else EvenCons(from, from + 1, range2(from + 2, to)) 147 | // { 148 | // def go(to: Int, acc: EvenList[Int]): EvenList[Int] = 149 | // if (from >= to - 1) acc 150 | // else go(to - 2, new EvenCons(to - 2, to - 1, acc)) 151 | // 152 | // go(to, EvenNil()) 153 | // } 154 | 155 | // println(range(1, 1000)) 156 | // println(app(range(1, 100), sumOddA)) 157 | // println(app[EvenList[Int], Int](range(1, 100), { 158 | // case EvenNil() => 0 159 | // case EvenCons(x, y, rest) => x + ??? 160 | // })) 161 | 162 | println(app[EvenList[Int], Unit](range2(1, 10000000), _ => ())) 163 | println(app[EvenList[Int], String](range2(1, 10000), _.toString)) 164 | // println(plus(2)(3)) 165 | // println(plus2a(2)(3)) 166 | 167 | // println(namer.name2(4, 5)) 168 | } 169 | -------------------------------------------------------------------------------- /src/test/scala/java2scala/homeworks/funcs/ChurchSuite.scala: -------------------------------------------------------------------------------- 1 | package java2scala.homeworks.funcs 2 | 3 | import org.scalactic.Equality 4 | import org.scalatest.prop.PropertyChecks 5 | import org.scalatest.{Matchers, PropSpec, WordSpec} 6 | 7 | import scala.Function.uncurried 8 | 9 | class ChurchSuite extends WordSpec with Matchers with PropertyChecks { 10 | "ChurchBool" when { 11 | "converting to and from boolean" should { 12 | "be isomorphic" in forAll { b: Boolean => 13 | ChurchBool(b).toBool shouldEqual b 14 | } 15 | 16 | "convert True to true" in { 17 | ChurchBool.True.toBool shouldEqual true 18 | } 19 | 20 | "convert False to false" in { 21 | ChurchBool.False.toBool shouldEqual false 22 | } 23 | } 24 | 25 | "checking conditions" should { 26 | "use first expr for true" in forAll { (x: Int, y: Int) => 27 | ChurchBool.True.cif(x)(y) shouldEqual x 28 | } 29 | 30 | "use second expr for false" in forAll { (x: Int, y: Int) => 31 | ChurchBool.False.cif(x)(y) shouldEqual y 32 | } 33 | } 34 | 35 | "negating" should { 36 | "negate converted to the negated" in forAll { b: Boolean => 37 | (!ChurchBool(b)).toBool shouldEqual !b 38 | } 39 | 40 | "double negate to the same" in forAll { b: Boolean => 41 | (!(!ChurchBool(b))).toBool shouldEqual b 42 | } 43 | } 44 | 45 | "calc AND" should { 46 | "keep and" in forAll { (b: Boolean, c: Boolean) => 47 | (ChurchBool(b) && ChurchBool(c)).toBool shouldEqual b && c 48 | } 49 | 50 | "true neutral" in forAll { b: Boolean => 51 | (ChurchBool(b) && ChurchBool.True).toBool shouldEqual b 52 | (ChurchBool.True && ChurchBool(b)).toBool shouldEqual b 53 | } 54 | 55 | "false absorb" in forAll { b: Boolean => 56 | (ChurchBool(b) && ChurchBool.False).toBool shouldEqual false 57 | (ChurchBool.False && ChurchBool(b)).toBool shouldEqual false 58 | } 59 | } 60 | 61 | "calc OR" should { 62 | "keep OR" in forAll { (b: Boolean, c: Boolean) => 63 | (ChurchBool(b) || ChurchBool(c)).toBool shouldEqual b || c 64 | } 65 | 66 | "true absorb" in forAll { b: Boolean => 67 | (ChurchBool(b) || ChurchBool.True).toBool shouldEqual true 68 | (ChurchBool.True || ChurchBool(b)).toBool shouldEqual true 69 | } 70 | 71 | "false neutral" in forAll { b: Boolean => 72 | (ChurchBool(b) || ChurchBool.False).toBool shouldEqual b 73 | (ChurchBool.False || ChurchBool(b)).toBool shouldEqual b 74 | } 75 | } 76 | } 77 | 78 | "Church List" when { 79 | "folding" should { 80 | "be compatible with foldRight" in forAll { (list: List[Int], z: Long, c: Int => Long => Long) => 81 | ChurchList(list: _*).fold(z)(c) 82 | } 83 | 84 | "preserve list structure" in forAll { list: List[Int] => 85 | ChurchList(list: _*).toList shouldEqual list 86 | } 87 | 88 | "preserve vector structure" in forAll { vec: Vector[Int] => 89 | ChurchList(vec: _*).toList.toVector shouldEqual vec 90 | } 91 | } 92 | 93 | "mapping" should { 94 | "be compatible with collection map" in forAll { (list: Array[Int], f: Int => Long, z: Long, c: Long => Long => Long) => 95 | ChurchList(list: _*).map(f).toList shouldEqual list.map(f) 96 | } 97 | "keep composition" in forAll { (list: List[Int], f: Int => String, g: String => Long) => 98 | ChurchList(list: _*).map(f).map(g) shouldEqual ChurchList(list: _*).map(f andThen g) 99 | } 100 | 101 | } 102 | 103 | "filtering" should { 104 | "be compatible with collection filter" in forAll { (list: List[Int], f: Int => Boolean) => 105 | ChurchList(list: _*).filter(f).toList shouldEqual list.filter(f) 106 | } 107 | 108 | "keep and" in forAll { (list: List[Int], f: Int => Boolean, g: Int => Boolean) => 109 | ChurchList(list: _*).filter(f).filter(g) shouldEqual 110 | ChurchList(list: _*).filter(x => f(x) && g(x)) 111 | } 112 | } 113 | 114 | "head option" should { 115 | "return None for empty" in { 116 | ChurchList.empty[Int].headOption shouldEqual None 117 | } 118 | 119 | "return first element for concatenation" in forAll { (x: Int, xs: List[Int]) => 120 | (x :: ChurchList(xs: _*)).headOption shouldEqual Some(x) 121 | } 122 | } 123 | 124 | "flatMap" should { 125 | "be compatible with list flatMap" in forAll { (l: List[Int], f: Int => List[Long]) => 126 | ChurchList(l: _*).flatMap(l => ChurchList(f(l): _*)).toList shouldEqual l.flatMap(f) 127 | 128 | } 129 | 130 | "return zero for empty" in { 131 | ChurchList.empty[Int].flatMap(_ => ChurchList(1)).headOption shouldEqual None 132 | } 133 | 134 | "return zero for empty map " in { 135 | ChurchList(1).flatMap(_ => ChurchList.empty[Int]).headOption shouldEqual None 136 | } 137 | 138 | "respect left unit rule" in forAll { (x: Int, f: Int => ChurchList[Long]) => 139 | ChurchList(x).flatMap(f) shouldEqual f(x) 140 | } 141 | 142 | "respect right unit rule" in forAll { xs: ChurchList[Int] => 143 | xs.flatMap(x => ChurchList(x)) shouldEqual xs 144 | } 145 | 146 | "respect associativity rule" in forAll { (xs: ChurchList[Int], f: Int => ChurchList[Long], g: Long => ChurchList[Int]) => 147 | xs.flatMap(f).flatMap(g) shouldEqual xs.flatMap(l => f(l).flatMap(g)) 148 | } 149 | 150 | "be equal to map" in forAll { (xs: ChurchList[Int], f: Int => Long) => 151 | xs.flatMap(x => ChurchList(f(x))) shouldEqual xs.map(f) 152 | } 153 | } 154 | 155 | "concatetation" should { 156 | "be compatible with list concatenation" in { (xs: List[Long], ys: List[Long]) => 157 | (ChurchList(xs: _*) ++ ChurchList(ys: _*)).toList shouldEqual xs ++ ys 158 | } 159 | 160 | "distribute with map" in { (xs: ChurchList[Long], ys: ChurchList[Long], f: Long => Int) => 161 | xs.map(f) ++ ys.map(f) shouldEqual (xs ++ ys).map(f) 162 | } 163 | 164 | "distribute with filter" in { (xs: ChurchList[Long], ys: ChurchList[Long], f: Long => Boolean) => 165 | xs.filter(f) ++ ys.filter(f) shouldEqual (xs ++ ys).filter(f) 166 | } 167 | } 168 | } 169 | } 170 | --------------------------------------------------------------------------------