├── .gitignore ├── README.md ├── day1 ├── basics.ipynb └── fp_only │ └── fp_only.ipynb ├── day2 └── monads.ipynb ├── day3 └── akka.ipynb └── little-projects └── Bank.ipynb /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | MANIFEST 3 | build 4 | dist 5 | _build 6 | docs/man/*.gz 7 | docs/source/api/generated 8 | docs/source/config.rst 9 | docs/gh-pages 10 | notebook/static/components 11 | notebook/static/style/*.min.css* 12 | notebook/static/*/js/built/ 13 | notebook/static/*/built/ 14 | notebook/static/built/ 15 | notebook/static/*/js/main.min.js* 16 | notebook/static/lab/*bundle.js 17 | node_modules 18 | *.py[co] 19 | __pycache__ 20 | *.egg-info 21 | *~ 22 | *.bak 23 | .ipynb_checkpoints 24 | .tox 25 | .DS_Store 26 | \#*# 27 | .#* 28 | .coverage 29 | src 30 | 31 | *.swp 32 | *.map 33 | .idea/ 34 | Read the Docs 35 | config.rst 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Как я scala учил 2 | 3 | ![](https://pp.userapi.com/c639427/v639427301/36a46/xTO4HZimLNA.jpg) 4 | 5 | Для себя вы тут можете найти много интересных вещей, если вы хотите работать со scala, но пока не очень можете в него 6 | 7 | Это моя личная история боли и радости. Всё написанное дальше - это то, что я делал на момент изучения. Я не хочу, чтобы вы учили или делали так же. Просто рассказываю о том, что я делал. Вы можете пойти по этому пути, но за результат я ответственность не беру. 8 | 9 | Зависимости: 10 | 11 | 1. [anaconda3](https://www.continuum.io/downloads) 12 | 13 | 2. ```bash <(curl https://raw.githubusercontent.com/alexarchambault/jupyter-scala/master/jupyter-scala)``` 14 | 15 | ### Оглавление 16 | 1. [Основы синтаксиса](https://github.com/tvorogme/scala/blob/master/day1/basics.ipynb). 17 | 2. [Монады, функторы, etc.](https://github.com/tvorogme/scala/blob/master/day2/monads.ipynb) 18 | 3. [Akka](https://github.com/tvorogme/scala-tutorial/blob/master/day3/akka.ipynb) *in progress* 19 | 20 | ### Мини-проекты 21 | 1. [Scala Bank](https://github.com/tvorogme/scala/blob/master/little-projects/Bank.ipynb) 22 | 23 | -------------------------------------------------------------------------------- /day1/basics.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Посмотрим на дикого зверя\n", 8 | "\n", 9 | "Посмотрим, что нам даёт scala в качестве типов данных" 10 | ] 11 | }, 12 | { 13 | "cell_type": "markdown", 14 | "metadata": {}, 15 | "source": [ 16 | "Переменная - это ```var```
\n", 17 | "Константа - это ```val```" 18 | ] 19 | }, 20 | { 21 | "cell_type": "code", 22 | "execution_count": 1, 23 | "metadata": { 24 | "collapsed": false 25 | }, 26 | "outputs": [ 27 | { 28 | "name": "stdout", 29 | "output_type": "stream", 30 | "text": [ 31 | "6\n" 32 | ] 33 | }, 34 | { 35 | "data": { 36 | "text/plain": [ 37 | "\u001b[36mk\u001b[39m: \u001b[32mInt\u001b[39m = \u001b[32m6\u001b[39m" 38 | ] 39 | }, 40 | "execution_count": 1, 41 | "metadata": {}, 42 | "output_type": "execute_result" 43 | } 44 | ], 45 | "source": [ 46 | "var k: Int = 5\n", 47 | "k += 1\n", 48 | "println(k)" 49 | ] 50 | }, 51 | { 52 | "cell_type": "code", 53 | "execution_count": 2, 54 | "metadata": { 55 | "collapsed": false 56 | }, 57 | "outputs": [ 58 | { 59 | "data": { 60 | "text/plain": [ 61 | "\u001b[36mk\u001b[39m: \u001b[32mInt\u001b[39m = \u001b[32m5\u001b[39m" 62 | ] 63 | }, 64 | "execution_count": 2, 65 | "metadata": {}, 66 | "output_type": "execute_result" 67 | } 68 | ], 69 | "source": [ 70 | "val k: Int = 5" 71 | ] 72 | }, 73 | { 74 | "cell_type": "code", 75 | "execution_count": 2, 76 | "metadata": { 77 | "collapsed": true 78 | }, 79 | "outputs": [], 80 | "source": [ 81 | "// Попробуйте\n", 82 | "// k += 1" 83 | ] 84 | }, 85 | { 86 | "cell_type": "markdown", 87 | "metadata": {}, 88 | "source": [ 89 | "Мы можем как указывать тип того, что мы хотим положить в val или var, а можем и не указывать." 90 | ] 91 | }, 92 | { 93 | "cell_type": "code", 94 | "execution_count": 3, 95 | "metadata": { 96 | "collapsed": false 97 | }, 98 | "outputs": [ 99 | { 100 | "data": { 101 | "text/plain": [ 102 | "\u001b[36mx\u001b[39m: \u001b[32mLong\u001b[39m = \u001b[32m100000000L\u001b[39m\n", 103 | "\u001b[36my\u001b[39m: \u001b[32mDouble\u001b[39m = \u001b[32m123.456\u001b[39m\n", 104 | "\u001b[36mmessage\u001b[39m: \u001b[32mString\u001b[39m = \u001b[32m\"Привет\"\u001b[39m\n", 105 | "\u001b[36misScala\u001b[39m: \u001b[32mBoolean\u001b[39m = \u001b[32mtrue\u001b[39m" 106 | ] 107 | }, 108 | "execution_count": 3, 109 | "metadata": {}, 110 | "output_type": "execute_result" 111 | } 112 | ], 113 | "source": [ 114 | "val x: Long = 100000000\n", 115 | "val y: Double = 123.456\n", 116 | "val message: String = \"Привет\"\n", 117 | "val isScala: Boolean = true" 118 | ] 119 | }, 120 | { 121 | "cell_type": "code", 122 | "execution_count": 3, 123 | "metadata": { 124 | "collapsed": false 125 | }, 126 | "outputs": [], 127 | "source": [ 128 | "// x += 1\n", 129 | "// y += 1\n", 130 | "// message += \".\"\n", 131 | "// isScala = false" 132 | ] 133 | }, 134 | { 135 | "cell_type": "code", 136 | "execution_count": 4, 137 | "metadata": { 138 | "collapsed": false 139 | }, 140 | "outputs": [ 141 | { 142 | "data": { 143 | "text/plain": [ 144 | "\u001b[36mx\u001b[39m: \u001b[32mLong\u001b[39m = \u001b[32m100000000L\u001b[39m\n", 145 | "\u001b[36my\u001b[39m: \u001b[32mDouble\u001b[39m = \u001b[32m123.456\u001b[39m\n", 146 | "\u001b[36mmessage\u001b[39m: \u001b[32mString\u001b[39m = \u001b[32m\"Пока\"\u001b[39m\n", 147 | "\u001b[36misScala\u001b[39m: \u001b[32mBoolean\u001b[39m = \u001b[32mtrue\u001b[39m" 148 | ] 149 | }, 150 | "execution_count": 4, 151 | "metadata": {}, 152 | "output_type": "execute_result" 153 | } 154 | ], 155 | "source": [ 156 | "var x: Long = 100000000\n", 157 | "var y: Double = 123.456\n", 158 | "var message: String = \"Пока\"\n", 159 | "var isScala: Boolean = true" 160 | ] 161 | }, 162 | { 163 | "cell_type": "code", 164 | "execution_count": 5, 165 | "metadata": { 166 | "collapsed": true 167 | }, 168 | "outputs": [], 169 | "source": [ 170 | "x += 1\n", 171 | "y += 1\n", 172 | "message += \".\"\n", 173 | "isScala = false" 174 | ] 175 | }, 176 | { 177 | "cell_type": "markdown", 178 | "metadata": {}, 179 | "source": [ 180 | "Каждая переменная является объектом. Мы можем от неё что-нибудь позвать!" 181 | ] 182 | }, 183 | { 184 | "cell_type": "code", 185 | "execution_count": 6, 186 | "metadata": { 187 | "collapsed": false 188 | }, 189 | "outputs": [ 190 | { 191 | "data": { 192 | "text/plain": [ 193 | "\u001b[36mres5\u001b[39m: \u001b[32mClass\u001b[39m[\u001b[32mLong\u001b[39m] = long" 194 | ] 195 | }, 196 | "execution_count": 6, 197 | "metadata": {}, 198 | "output_type": "execute_result" 199 | } 200 | ], 201 | "source": [ 202 | "x.getClass()" 203 | ] 204 | }, 205 | { 206 | "cell_type": "code", 207 | "execution_count": 7, 208 | "metadata": { 209 | "collapsed": false 210 | }, 211 | "outputs": [ 212 | { 213 | "data": { 214 | "text/plain": [ 215 | "\u001b[36mres6\u001b[39m: \u001b[32mFloat\u001b[39m = \u001b[32m1.0E8F\u001b[39m" 216 | ] 217 | }, 218 | "execution_count": 7, 219 | "metadata": {}, 220 | "output_type": "execute_result" 221 | } 222 | ], 223 | "source": [ 224 | "x.floor" 225 | ] 226 | }, 227 | { 228 | "cell_type": "code", 229 | "execution_count": 8, 230 | "metadata": { 231 | "collapsed": false 232 | }, 233 | "outputs": [ 234 | { 235 | "data": { 236 | "text/plain": [ 237 | "\u001b[36mres7\u001b[39m: \u001b[32mFloat\u001b[39m = \u001b[32m1.0E8F\u001b[39m" 238 | ] 239 | }, 240 | "execution_count": 8, 241 | "metadata": {}, 242 | "output_type": "execute_result" 243 | } 244 | ], 245 | "source": [ 246 | "x.ceil" 247 | ] 248 | }, 249 | { 250 | "cell_type": "markdown", 251 | "metadata": {}, 252 | "source": [ 253 | "Строки" 254 | ] 255 | }, 256 | { 257 | "cell_type": "code", 258 | "execution_count": 9, 259 | "metadata": { 260 | "collapsed": false 261 | }, 262 | "outputs": [ 263 | { 264 | "data": { 265 | "text/plain": [ 266 | "\u001b[36ms\u001b[39m: \u001b[32mString\u001b[39m = \u001b[32m\"Одна строчка\"\u001b[39m\n", 267 | "\u001b[36mraw_s\u001b[39m: \u001b[32mString\u001b[39m = \u001b[32m\"\"\"\n", 268 | "Много строк с \"ковычками\"\n", 269 | " и теееекстом\n", 270 | "\"\"\"\u001b[39m" 271 | ] 272 | }, 273 | "execution_count": 9, 274 | "metadata": {}, 275 | "output_type": "execute_result" 276 | } 277 | ], 278 | "source": [ 279 | "// прямо как в Python\n", 280 | "val s = \"Одна строчка\"\n", 281 | "val raw_s = \"\"\"Много строк с \"ковычками\"\n", 282 | " и теееекстом\"\"\"" 283 | ] 284 | }, 285 | { 286 | "cell_type": "code", 287 | "execution_count": 10, 288 | "metadata": { 289 | "collapsed": false 290 | }, 291 | "outputs": [ 292 | { 293 | "data": { 294 | "text/plain": [ 295 | "\u001b[36mraw_s_regex\u001b[39m: \u001b[32mString\u001b[39m = \u001b[32m\"\"\"\n", 296 | "\\s+\n", 297 | "\"\"\"\u001b[39m" 298 | ] 299 | }, 300 | "execution_count": 10, 301 | "metadata": {}, 302 | "output_type": "execute_result" 303 | } 304 | ], 305 | "source": [ 306 | "// RegeXP\n", 307 | "val raw_s_regex = \"\"\"\\s+\"\"\"" 308 | ] 309 | }, 310 | { 311 | "cell_type": "code", 312 | "execution_count": 11, 313 | "metadata": { 314 | "collapsed": false 315 | }, 316 | "outputs": [ 317 | { 318 | "data": { 319 | "text/plain": [ 320 | "\u001b[36minterpol\u001b[39m: \u001b[32mString\u001b[39m = \u001b[32m\"S=Одна строчка\"\u001b[39m\n", 321 | "\u001b[36mi\u001b[39m: \u001b[32mDouble\u001b[39m = \u001b[32m10.1234\u001b[39m\n", 322 | "\u001b[36mprice\u001b[39m: \u001b[32mString\u001b[39m = \u001b[32m\"$10.1234 dollars\"\u001b[39m" 323 | ] 324 | }, 325 | "execution_count": 11, 326 | "metadata": {}, 327 | "output_type": "execute_result" 328 | } 329 | ], 330 | "source": [ 331 | "val interpol = s\"S=$s\" // Заменет $s\n", 332 | "val i = 10.1234\n", 333 | "val price = s\"$$$i dollars\" // Забьёт на множество даларов" 334 | ] 335 | }, 336 | { 337 | "cell_type": "code", 338 | "execution_count": 12, 339 | "metadata": { 340 | "collapsed": false 341 | }, 342 | "outputs": [ 343 | { 344 | "data": { 345 | "text/plain": [ 346 | "\u001b[36mf_price\u001b[39m: \u001b[32mString\u001b[39m = \u001b[32m\"10.12 dollars\"\u001b[39m" 347 | ] 348 | }, 349 | "execution_count": 12, 350 | "metadata": {}, 351 | "output_type": "execute_result" 352 | } 353 | ], 354 | "source": [ 355 | "// Питонячая приблуда\n", 356 | "val f_price = f\"${i}%.2f dollars\"" 357 | ] 358 | }, 359 | { 360 | "cell_type": "markdown", 361 | "metadata": {}, 362 | "source": [ 363 | "Картежи" 364 | ] 365 | }, 366 | { 367 | "cell_type": "code", 368 | "execution_count": 13, 369 | "metadata": { 370 | "collapsed": false 371 | }, 372 | "outputs": [ 373 | { 374 | "data": { 375 | "text/plain": [ 376 | "\u001b[36mx\u001b[39m: \u001b[32mInt\u001b[39m = \u001b[32m1\u001b[39m\n", 377 | "\u001b[36my\u001b[39m: \u001b[32mInt\u001b[39m = \u001b[32m2\u001b[39m\n", 378 | "\u001b[36mtpl\u001b[39m: (\u001b[32mInt\u001b[39m, \u001b[32mInt\u001b[39m) = (\u001b[32m1\u001b[39m, \u001b[32m2\u001b[39m)" 379 | ] 380 | }, 381 | "execution_count": 13, 382 | "metadata": {}, 383 | "output_type": "execute_result" 384 | } 385 | ], 386 | "source": [ 387 | "val (x,y) = (1,2)\n", 388 | "val tpl = (1,2)" 389 | ] 390 | }, 391 | { 392 | "cell_type": "markdown", 393 | "metadata": {}, 394 | "source": [ 395 | "Их основная проблема заключается в том, что они начинаются с 1. WAT???" 396 | ] 397 | }, 398 | { 399 | "cell_type": "code", 400 | "execution_count": 14, 401 | "metadata": { 402 | "collapsed": false 403 | }, 404 | "outputs": [ 405 | { 406 | "name": "stdout", 407 | "output_type": "stream", 408 | "text": [ 409 | "1\n", 410 | "2\n" 411 | ] 412 | } 413 | ], 414 | "source": [ 415 | "println(tpl._1)\n", 416 | "println(tpl._2) " 417 | ] 418 | }, 419 | { 420 | "cell_type": "markdown", 421 | "metadata": {}, 422 | "source": [ 423 | "Давайте пробежимся по стандартным вещам (массивы, списки, множества, словари). Свойства хранения данных scala таковы, что когда вы делаете операцию над объектом, то вам возращается копия этого объекта." 424 | ] 425 | }, 426 | { 427 | "cell_type": "code", 428 | "execution_count": 15, 429 | "metadata": { 430 | "collapsed": false 431 | }, 432 | "outputs": [ 433 | { 434 | "data": { 435 | "text/plain": [ 436 | "\u001b[36mrandomArray\u001b[39m: \u001b[32mArray\u001b[39m[\u001b[32mString\u001b[39m] = \u001b[33mArray\u001b[39m(\u001b[32m\"Андрей\"\u001b[39m, \u001b[32m\"Творог\"\u001b[39m, \u001b[32m\"Жизнь\"\u001b[39m)\n", 437 | "\u001b[36mrandomList\u001b[39m: \u001b[32mList\u001b[39m[\u001b[32mString\u001b[39m] = \u001b[33mList\u001b[39m(\u001b[32m\"Python\"\u001b[39m, \u001b[32m\"Мера\"\u001b[39m, \u001b[32m\"Тонна\"\u001b[39m)\n", 438 | "\u001b[36mrandomSet\u001b[39m: \u001b[32mSet\u001b[39m[\u001b[32mString\u001b[39m] = \u001b[33mSet\u001b[39m(\u001b[32m\"Гавана\"\u001b[39m, \u001b[32m\"Классный\"\u001b[39m, \u001b[32m\"Кокаин\"\u001b[39m, \u001b[32m\"Смерть\"\u001b[39m)" 439 | ] 440 | }, 441 | "execution_count": 15, 442 | "metadata": {}, 443 | "output_type": "execute_result" 444 | } 445 | ], 446 | "source": [ 447 | "val randomArray = Array(\"Андрей\", \"Творог\", \"Жизнь\") \n", 448 | "val randomList = List(\"Python\", \"Мера\", \"Тонна\")\n", 449 | "val randomSet = Set(\"Гавана\", \"Классный\", \"Кокаин\", \"Смерть\") " 450 | ] 451 | }, 452 | { 453 | "cell_type": "markdown", 454 | "metadata": {}, 455 | "source": [ 456 | "Так же вы можете задавать словари вот таким синтаксисом:" 457 | ] 458 | }, 459 | { 460 | "cell_type": "code", 461 | "execution_count": 16, 462 | "metadata": { 463 | "collapsed": false 464 | }, 465 | "outputs": [ 466 | { 467 | "data": { 468 | "text/plain": [ 469 | "\u001b[36mrandomMap\u001b[39m: \u001b[32mMap\u001b[39m[\u001b[32mString\u001b[39m, \u001b[32mString\u001b[39m] = \u001b[33mMap\u001b[39m(\u001b[32m\"Я\"\u001b[39m -> \u001b[32m\"крутой\"\u001b[39m, \u001b[32m\"Собака\"\u001b[39m -> \u001b[32m\"кошка\"\u001b[39m, \u001b[32m\"Граф\"\u001b[39m -> \u001b[32m\"Петр 1\"\u001b[39m)" 470 | ] 471 | }, 472 | "execution_count": 16, 473 | "metadata": {}, 474 | "output_type": "execute_result" 475 | } 476 | ], 477 | "source": [ 478 | "val randomMap = Map(\"Я\" -> \"крутой\", \"Собака\" -> \"кошка\", \"Граф\" -> \"Петр 1\")" 479 | ] 480 | }, 481 | { 482 | "cell_type": "markdown", 483 | "metadata": {}, 484 | "source": [ 485 | "Как заметно выше ^ квадратные скобки задействованны для описания типа данных. А как же обратиться к элементу?" 486 | ] 487 | }, 488 | { 489 | "cell_type": "code", 490 | "execution_count": 17, 491 | "metadata": { 492 | "collapsed": false 493 | }, 494 | "outputs": [ 495 | { 496 | "name": "stdout", 497 | "output_type": "stream", 498 | "text": [ 499 | "Второй элемент списка Творог\n", 500 | "Я самый крутой\n" 501 | ] 502 | }, 503 | { 504 | "data": { 505 | "text/plain": [ 506 | "\u001b[36mkey\u001b[39m: \u001b[32mString\u001b[39m = \u001b[32m\"Я\"\u001b[39m" 507 | ] 508 | }, 509 | "execution_count": 17, 510 | "metadata": {}, 511 | "output_type": "execute_result" 512 | } 513 | ], 514 | "source": [ 515 | "println(\"Второй элемент списка \" + randomArray(1))\n", 516 | "\n", 517 | "var key = \"Я\"\n", 518 | "println(key + \" самый \" + randomMap(key))" 519 | ] 520 | }, 521 | { 522 | "cell_type": "markdown", 523 | "metadata": {}, 524 | "source": [ 525 | "Для того, чтобы посмотреть есть ли элемент в множестве, можно просто обратиться к нему!" 526 | ] 527 | }, 528 | { 529 | "cell_type": "code", 530 | "execution_count": 18, 531 | "metadata": { 532 | "collapsed": false 533 | }, 534 | "outputs": [ 535 | { 536 | "data": { 537 | "text/plain": [ 538 | "\u001b[36mres17\u001b[39m: \u001b[32mBoolean\u001b[39m = \u001b[32mtrue\u001b[39m" 539 | ] 540 | }, 541 | "execution_count": 18, 542 | "metadata": {}, 543 | "output_type": "execute_result" 544 | } 545 | ], 546 | "source": [ 547 | "randomSet(\"Классный\")" 548 | ] 549 | }, 550 | { 551 | "cell_type": "code", 552 | "execution_count": 19, 553 | "metadata": { 554 | "collapsed": false 555 | }, 556 | "outputs": [ 557 | { 558 | "data": { 559 | "text/plain": [ 560 | "\u001b[36mres18\u001b[39m: \u001b[32mBoolean\u001b[39m = \u001b[32mfalse\u001b[39m" 561 | ] 562 | }, 563 | "execution_count": 19, 564 | "metadata": {}, 565 | "output_type": "execute_result" 566 | } 567 | ], 568 | "source": [ 569 | "randomSet(\"Не очень\")" 570 | ] 571 | }, 572 | { 573 | "cell_type": "markdown", 574 | "metadata": {}, 575 | "source": [ 576 | "Все элементы списка можно менять, потому что они ```var```" 577 | ] 578 | }, 579 | { 580 | "cell_type": "code", 581 | "execution_count": 20, 582 | "metadata": { 583 | "collapsed": false 584 | }, 585 | "outputs": [], 586 | "source": [ 587 | "randomArray(0) = randomArray(1)" 588 | ] 589 | }, 590 | { 591 | "cell_type": "code", 592 | "execution_count": 21, 593 | "metadata": { 594 | "collapsed": false 595 | }, 596 | "outputs": [ 597 | { 598 | "data": { 599 | "text/plain": [ 600 | "\u001b[36mres20\u001b[39m: \u001b[32mArray\u001b[39m[\u001b[32mString\u001b[39m] = \u001b[33mArray\u001b[39m(\u001b[32m\"Творог\"\u001b[39m, \u001b[32m\"Творог\"\u001b[39m, \u001b[32m\"Жизнь\"\u001b[39m)" 601 | ] 602 | }, 603 | "execution_count": 21, 604 | "metadata": {}, 605 | "output_type": "execute_result" 606 | } 607 | ], 608 | "source": [ 609 | "randomArray" 610 | ] 611 | }, 612 | { 613 | "cell_type": "markdown", 614 | "metadata": {}, 615 | "source": [ 616 | "Для таких операций, как append, prepend и concatenate существуют операторы:" 617 | ] 618 | }, 619 | { 620 | "cell_type": "code", 621 | "execution_count": 22, 622 | "metadata": { 623 | "collapsed": false 624 | }, 625 | "outputs": [ 626 | { 627 | "data": { 628 | "text/plain": [ 629 | "\u001b[36mres21\u001b[39m: \u001b[32mList\u001b[39m[\u001b[32mString\u001b[39m] = \u001b[33mList\u001b[39m(\u001b[32m\"Python\"\u001b[39m, \u001b[32m\"Мера\"\u001b[39m, \u001b[32m\"Тонна\"\u001b[39m, \u001b[32m\"Андрей\"\u001b[39m)" 630 | ] 631 | }, 632 | "execution_count": 22, 633 | "metadata": {}, 634 | "output_type": "execute_result" 635 | } 636 | ], 637 | "source": [ 638 | "randomList :+ \"Андрей\"" 639 | ] 640 | }, 641 | { 642 | "cell_type": "code", 643 | "execution_count": 23, 644 | "metadata": { 645 | "collapsed": false 646 | }, 647 | "outputs": [ 648 | { 649 | "data": { 650 | "text/plain": [ 651 | "\u001b[36mres22\u001b[39m: \u001b[32mList\u001b[39m[\u001b[32mString\u001b[39m] = \u001b[33mList\u001b[39m(\u001b[32m\"Андрей\"\u001b[39m, \u001b[32m\"Python\"\u001b[39m, \u001b[32m\"Мера\"\u001b[39m, \u001b[32m\"Тонна\"\u001b[39m)" 652 | ] 653 | }, 654 | "execution_count": 23, 655 | "metadata": {}, 656 | "output_type": "execute_result" 657 | } 658 | ], 659 | "source": [ 660 | "\"Андрей\" :: randomList" 661 | ] 662 | }, 663 | { 664 | "cell_type": "code", 665 | "execution_count": 24, 666 | "metadata": { 667 | "collapsed": false 668 | }, 669 | "outputs": [ 670 | { 671 | "data": { 672 | "text/plain": [ 673 | "\u001b[36mres23\u001b[39m: \u001b[32mList\u001b[39m[\u001b[32mString\u001b[39m] = \u001b[33mList\u001b[39m(\u001b[32m\"Python\"\u001b[39m, \u001b[32m\"Мера\"\u001b[39m, \u001b[32m\"Тонна\"\u001b[39m, \u001b[32m\"LOL\"\u001b[39m, \u001b[32m\"KEK\"\u001b[39m, \u001b[32m\"CHEBUREK\"\u001b[39m)" 674 | ] 675 | }, 676 | "execution_count": 24, 677 | "metadata": {}, 678 | "output_type": "execute_result" 679 | } 680 | ], 681 | "source": [ 682 | "randomList ++ List(\"LOL\", \"KEK\", \"CHEBUREK\")" 683 | ] 684 | }, 685 | { 686 | "cell_type": "markdown", 687 | "metadata": {}, 688 | "source": [ 689 | "## FOR" 690 | ] 691 | }, 692 | { 693 | "cell_type": "code", 694 | "execution_count": 25, 695 | "metadata": { 696 | "collapsed": false 697 | }, 698 | "outputs": [ 699 | { 700 | "name": "stdout", 701 | "output_type": "stream", 702 | "text": [ 703 | "Python\n", 704 | "Мера\n", 705 | "Тонна\n" 706 | ] 707 | } 708 | ], 709 | "source": [ 710 | "for (i <- randomList) {\n", 711 | " println(i)\n", 712 | "}" 713 | ] 714 | }, 715 | { 716 | "cell_type": "markdown", 717 | "metadata": {}, 718 | "source": [ 719 | "На замен питовскому range тут есть ```to``` и ```until```!" 720 | ] 721 | }, 722 | { 723 | "cell_type": "code", 724 | "execution_count": 26, 725 | "metadata": { 726 | "collapsed": false 727 | }, 728 | "outputs": [ 729 | { 730 | "name": "stdout", 731 | "output_type": "stream", 732 | "text": [ 733 | "1\n", 734 | "2\n", 735 | "3\n", 736 | "4\n", 737 | "5\n" 738 | ] 739 | } 740 | ], 741 | "source": [ 742 | "for (i <- 1 to k) {\n", 743 | " println(i)\n", 744 | "}" 745 | ] 746 | }, 747 | { 748 | "cell_type": "code", 749 | "execution_count": 27, 750 | "metadata": { 751 | "collapsed": false 752 | }, 753 | "outputs": [ 754 | { 755 | "name": "stdout", 756 | "output_type": "stream", 757 | "text": [ 758 | "1\n", 759 | "2\n", 760 | "3\n", 761 | "4\n" 762 | ] 763 | } 764 | ], 765 | "source": [ 766 | "for (i <- 1 until k) {\n", 767 | " println(i)\n", 768 | "}" 769 | ] 770 | }, 771 | { 772 | "cell_type": "markdown", 773 | "metadata": {}, 774 | "source": [ 775 | "# Функциональщина" 776 | ] 777 | }, 778 | { 779 | "cell_type": "code", 780 | "execution_count": 28, 781 | "metadata": { 782 | "collapsed": false 783 | }, 784 | "outputs": [ 785 | { 786 | "data": { 787 | "text/plain": [ 788 | "defined \u001b[32mfunction\u001b[39m \u001b[36mf\u001b[39m" 789 | ] 790 | }, 791 | "execution_count": 28, 792 | "metadata": {}, 793 | "output_type": "execute_result" 794 | } 795 | ], 796 | "source": [ 797 | "// Напишем функцию, которая может печатать\n", 798 | "def f(ints :Int*){\n", 799 | " for (i <- ints) {print(s\"-$i-\")}\n", 800 | "}" 801 | ] 802 | }, 803 | { 804 | "cell_type": "code", 805 | "execution_count": 29, 806 | "metadata": { 807 | "collapsed": false 808 | }, 809 | "outputs": [ 810 | { 811 | "name": "stdout", 812 | "output_type": "stream", 813 | "text": [ 814 | "-1--2--3--4-" 815 | ] 816 | } 817 | ], 818 | "source": [ 819 | "// Воспользуемся\n", 820 | "f(1,2,3,4)" 821 | ] 822 | }, 823 | { 824 | "cell_type": "code", 825 | "execution_count": 30, 826 | "metadata": { 827 | "collapsed": false 828 | }, 829 | "outputs": [ 830 | { 831 | "name": "stdout", 832 | "output_type": "stream", 833 | "text": [ 834 | "-1--2--3--4-" 835 | ] 836 | } 837 | ], 838 | "source": [ 839 | "// Как f(*array) в питоне. Разворачивает лист и передаёт содержимое\n", 840 | "f(Array(1,2,3,4):_*)" 841 | ] 842 | }, 843 | { 844 | "cell_type": "code", 845 | "execution_count": 31, 846 | "metadata": { 847 | "collapsed": false 848 | }, 849 | "outputs": [ 850 | { 851 | "name": "stdout", 852 | "output_type": "stream", 853 | "text": [ 854 | "5" 855 | ] 856 | }, 857 | { 858 | "data": { 859 | "text/plain": [ 860 | "defined \u001b[32mfunction\u001b[39m \u001b[36mf\u001b[39m" 861 | ] 862 | }, 863 | "execution_count": 31, 864 | "metadata": {}, 865 | "output_type": "execute_result" 866 | } 867 | ], 868 | "source": [ 869 | "// Стандартные значения на месте\n", 870 | "def f(x: Int = 5) = print(x)\n", 871 | "f()" 872 | ] 873 | }, 874 | { 875 | "cell_type": "code", 876 | "execution_count": 32, 877 | "metadata": { 878 | "collapsed": false 879 | }, 880 | "outputs": [ 881 | { 882 | "name": "stdout", 883 | "output_type": "stream", 884 | "text": [ 885 | "(x,y)" 886 | ] 887 | }, 888 | { 889 | "data": { 890 | "text/plain": [ 891 | "defined \u001b[32mfunction\u001b[39m \u001b[36mf\u001b[39m" 892 | ] 893 | }, 894 | "execution_count": 32, 895 | "metadata": {}, 896 | "output_type": "execute_result" 897 | } 898 | ], 899 | "source": [ 900 | "// Передовать параметры по имени - на месте\n", 901 | "def f (x:String,y:String) = print(x,y)\n", 902 | "f(y=\"y\", x=\"x\")" 903 | ] 904 | }, 905 | { 906 | "cell_type": "code", 907 | "execution_count": 33, 908 | "metadata": { 909 | "collapsed": false 910 | }, 911 | "outputs": [ 912 | { 913 | "name": "stdout", 914 | "output_type": "stream", 915 | "text": [ 916 | "явный x есть ещё и неявный y\n", 917 | "явный x есть ещё и явный y\n" 918 | ] 919 | }, 920 | { 921 | "data": { 922 | "text/plain": [ 923 | "defined \u001b[32mfunction\u001b[39m \u001b[36mf\u001b[39m\n", 924 | "\u001b[36my\u001b[39m: \u001b[32mString\u001b[39m = \u001b[32m\"неявный y\"\u001b[39m" 925 | ] 926 | }, 927 | "execution_count": 33, 928 | "metadata": {}, 929 | "output_type": "execute_result" 930 | } 931 | ], 932 | "source": [ 933 | "// Неявная передача параметра, что-то новое для питонистов\n", 934 | "def f(x: String)(implicit y:String) = println (s\"$x есть ещё и $y\")\n", 935 | "\n", 936 | "implicit var y = \"неявный y\"\n", 937 | "\n", 938 | "f(\"явный x\")\n", 939 | "f(\"явный x\")(\"явный y\")" 940 | ] 941 | }, 942 | { 943 | "cell_type": "markdown", 944 | "metadata": {}, 945 | "source": [ 946 | "## OOП" 947 | ] 948 | }, 949 | { 950 | "cell_type": "code", 951 | "execution_count": 34, 952 | "metadata": { 953 | "collapsed": false 954 | }, 955 | "outputs": [ 956 | { 957 | "data": { 958 | "text/plain": [ 959 | "defined \u001b[32mclass\u001b[39m \u001b[36mC\u001b[39m" 960 | ] 961 | }, 962 | "execution_count": 34, 963 | "metadata": {}, 964 | "output_type": "execute_result" 965 | } 966 | ], 967 | "source": [ 968 | "// По стандарту всё публично.\n", 969 | "class C {\n", 970 | " def m1 = println(\"m1\")\n", 971 | " private def m2 = println(\"m2\") // Но мы можем поспротивиться этому\n", 972 | " protected def m3 = println(\"m3\") // +1\n", 973 | "}" 974 | ] 975 | }, 976 | { 977 | "cell_type": "code", 978 | "execution_count": 35, 979 | "metadata": { 980 | "collapsed": false 981 | }, 982 | "outputs": [ 983 | { 984 | "data": { 985 | "text/plain": [ 986 | "\u001b[36mc\u001b[39m: \u001b[32mC\u001b[39m = $sess.cmd33Wrapper$Helper$C@500f6ab5" 987 | ] 988 | }, 989 | "execution_count": 35, 990 | "metadata": {}, 991 | "output_type": "execute_result" 992 | } 993 | ], 994 | "source": [ 995 | "val c = new C" 996 | ] 997 | }, 998 | { 999 | "cell_type": "code", 1000 | "execution_count": 36, 1001 | "metadata": { 1002 | "collapsed": false 1003 | }, 1004 | "outputs": [ 1005 | { 1006 | "name": "stdout", 1007 | "output_type": "stream", 1008 | "text": [ 1009 | "m1\n" 1010 | ] 1011 | } 1012 | ], 1013 | "source": [ 1014 | "c.m1" 1015 | ] 1016 | }, 1017 | { 1018 | "cell_type": "code", 1019 | "execution_count": 37, 1020 | "metadata": { 1021 | "collapsed": false 1022 | }, 1023 | "outputs": [ 1024 | { 1025 | "name": "stdout", 1026 | "output_type": "stream", 1027 | "text": [ 1028 | "Point(1, 2, 3) with color: RED\n" 1029 | ] 1030 | }, 1031 | { 1032 | "data": { 1033 | "text/plain": [ 1034 | "defined \u001b[32mclass\u001b[39m \u001b[36mPoint3D\u001b[39m\n", 1035 | "\u001b[36mp\u001b[39m: \u001b[32mPoint3D\u001b[39m = $sess.cmd36Wrapper$Helper$Point3D@29ba5885" 1036 | ] 1037 | }, 1038 | "execution_count": 37, 1039 | "metadata": {}, 1040 | "output_type": "execute_result" 1041 | } 1042 | ], 1043 | "source": [ 1044 | "// В Scala мы создаём конструкторы, а не классы\n", 1045 | "class Point3D(val x:Int, var y:Int, z:Int) { // Тело конструктора\n", 1046 | " private var color = \"RED\"\n", 1047 | " def method() = s\"Point($x, $y, $z) with color: $color\"\n", 1048 | "}\n", 1049 | "val p = new Point3D(1,2,3)\n", 1050 | "println(p.method)" 1051 | ] 1052 | }, 1053 | { 1054 | "cell_type": "code", 1055 | "execution_count": 38, 1056 | "metadata": { 1057 | "collapsed": false 1058 | }, 1059 | "outputs": [ 1060 | { 1061 | "name": "stdout", 1062 | "output_type": "stream", 1063 | "text": [ 1064 | "Point(1, 3, 3) with color: RED\n" 1065 | ] 1066 | } 1067 | ], 1068 | "source": [ 1069 | "// p.x = 6 - не сможет скомпилиться, потому что val\n", 1070 | "p.y = 3 // сможет скомпилиться, потому что var\n", 1071 | "println(p.method)" 1072 | ] 1073 | }, 1074 | { 1075 | "cell_type": "markdown", 1076 | "metadata": {}, 1077 | "source": [ 1078 | "Вопрос в аудиторию, что произойдёт с p.z?" 1079 | ] 1080 | }, 1081 | { 1082 | "cell_type": "code", 1083 | "execution_count": 39, 1084 | "metadata": { 1085 | "collapsed": false 1086 | }, 1087 | "outputs": [ 1088 | { 1089 | "data": { 1090 | "text/plain": [ 1091 | "defined \u001b[32mclass\u001b[39m \u001b[36mPoint2DDefault\u001b[39m" 1092 | ] 1093 | }, 1094 | "execution_count": 39, 1095 | "metadata": {}, 1096 | "output_type": "execute_result" 1097 | } 1098 | ], 1099 | "source": [ 1100 | "class Point2DDefault(val x:Int, val y:Int) {\n", 1101 | " var defaultValue : String = \"я не меняюсь\"\n", 1102 | "\n", 1103 | "\n", 1104 | " def this(x:Int){\n", 1105 | " this(x, 5) // Вызовет тело конструктора\n", 1106 | " }\n", 1107 | "\n", 1108 | "\n", 1109 | " override def toString() = s\"Point($x, $y), $defaultValue\"\n", 1110 | "}" 1111 | ] 1112 | }, 1113 | { 1114 | "cell_type": "code", 1115 | "execution_count": 40, 1116 | "metadata": { 1117 | "collapsed": false 1118 | }, 1119 | "outputs": [ 1120 | { 1121 | "name": "stdout", 1122 | "output_type": "stream", 1123 | "text": [ 1124 | "Point(1, 5), я не меняюсь\n" 1125 | ] 1126 | } 1127 | ], 1128 | "source": [ 1129 | "println(new Point2DDefault(1))" 1130 | ] 1131 | }, 1132 | { 1133 | "cell_type": "markdown", 1134 | "metadata": {}, 1135 | "source": [ 1136 | "Как украсть класс?" 1137 | ] 1138 | }, 1139 | { 1140 | "cell_type": "code", 1141 | "execution_count": 41, 1142 | "metadata": { 1143 | "collapsed": false 1144 | }, 1145 | "outputs": [ 1146 | { 1147 | "data": { 1148 | "text/plain": [ 1149 | "defined \u001b[32mtype\u001b[39m \u001b[36mjust_take_it\u001b[39m" 1150 | ] 1151 | }, 1152 | "execution_count": 41, 1153 | "metadata": {}, 1154 | "output_type": "execute_result" 1155 | } 1156 | ], 1157 | "source": [ 1158 | "type just_take_it = Point2DDefault" 1159 | ] 1160 | }, 1161 | { 1162 | "cell_type": "code", 1163 | "execution_count": 42, 1164 | "metadata": { 1165 | "collapsed": false 1166 | }, 1167 | "outputs": [ 1168 | { 1169 | "name": "stdout", 1170 | "output_type": "stream", 1171 | "text": [ 1172 | "Point(1, 5), я не меняюсь\n" 1173 | ] 1174 | } 1175 | ], 1176 | "source": [ 1177 | "println(new just_take_it(1))" 1178 | ] 1179 | }, 1180 | { 1181 | "cell_type": "markdown", 1182 | "metadata": {}, 1183 | "source": [ 1184 | "## Наследование" 1185 | ] 1186 | }, 1187 | { 1188 | "cell_type": "code", 1189 | "execution_count": 43, 1190 | "metadata": { 1191 | "collapsed": false 1192 | }, 1193 | "outputs": [ 1194 | { 1195 | "data": { 1196 | "text/plain": [ 1197 | "defined \u001b[32mclass\u001b[39m \u001b[36mBase\u001b[39m\n", 1198 | "defined \u001b[32mclass\u001b[39m \u001b[36mDer\u001b[39m" 1199 | ] 1200 | }, 1201 | "execution_count": 43, 1202 | "metadata": {}, 1203 | "output_type": "execute_result" 1204 | } 1205 | ], 1206 | "source": [ 1207 | "class Base(val x: Int)\n", 1208 | "\n", 1209 | "// Чтобы скомпилировать переменную, которая уже использовалась нужно написать \"override\"\n", 1210 | "class Der(override val x: Int, val y : Int) extends Base(x) { \n", 1211 | " def this() {\n", 1212 | " this(0,0)\n", 1213 | " }\n", 1214 | "}" 1215 | ] 1216 | }, 1217 | { 1218 | "cell_type": "markdown", 1219 | "metadata": {}, 1220 | "source": [ 1221 | "## Задаём тип параметром" 1222 | ] 1223 | }, 1224 | { 1225 | "cell_type": "code", 1226 | "execution_count": 44, 1227 | "metadata": { 1228 | "collapsed": false 1229 | }, 1230 | "outputs": [ 1231 | { 1232 | "name": "stdout", 1233 | "output_type": "stream", 1234 | "text": [ 1235 | "перменная 1 типа class java.lang.Integer\n", 1236 | "перменная String типа class java.lang.String\n", 1237 | "перменная String типа class java.lang.String\n" 1238 | ] 1239 | }, 1240 | { 1241 | "data": { 1242 | "text/plain": [ 1243 | "defined \u001b[32mfunction\u001b[39m \u001b[36mf\u001b[39m" 1244 | ] 1245 | }, 1246 | "execution_count": 44, 1247 | "metadata": {}, 1248 | "output_type": "execute_result" 1249 | } 1250 | ], 1251 | "source": [ 1252 | "def f[T](t:T) = println(s\"перменная $t типа ${t.getClass}\")\n", 1253 | "\n", 1254 | "f(1)\n", 1255 | "f(\"String\")\n", 1256 | "f[String](\"String\") // Зададим тип руками" 1257 | ] 1258 | }, 1259 | { 1260 | "cell_type": "markdown", 1261 | "metadata": {}, 1262 | "source": [ 1263 | "## Объекты" 1264 | ] 1265 | }, 1266 | { 1267 | "cell_type": "code", 1268 | "execution_count": 45, 1269 | "metadata": { 1270 | "collapsed": false 1271 | }, 1272 | "outputs": [ 1273 | { 1274 | "name": "stdout", 1275 | "output_type": "stream", 1276 | "text": [ 1277 | "f(5)\n", 1278 | "List(1, 2, 3)\n" 1279 | ] 1280 | }, 1281 | { 1282 | "data": { 1283 | "text/plain": [ 1284 | "defined \u001b[32mobject\u001b[39m \u001b[36mRandObj\u001b[39m" 1285 | ] 1286 | }, 1287 | "execution_count": 45, 1288 | "metadata": {}, 1289 | "output_type": "execute_result" 1290 | } 1291 | ], 1292 | "source": [ 1293 | "object RandObj {\n", 1294 | " val value = List(1,2,3)\n", 1295 | " def f(p:Any) = s\"f($p)\"\n", 1296 | "}\n", 1297 | "println(RandObj.f(5))\n", 1298 | "println(RandObj.value)" 1299 | ] 1300 | }, 1301 | { 1302 | "cell_type": "markdown", 1303 | "metadata": {}, 1304 | "source": [ 1305 | "## Объект и класс одного имени" 1306 | ] 1307 | }, 1308 | { 1309 | "cell_type": "code", 1310 | "execution_count": 46, 1311 | "metadata": { 1312 | "collapsed": false 1313 | }, 1314 | "outputs": [ 1315 | { 1316 | "name": "stdout", 1317 | "output_type": "stream", 1318 | "text": [ 1319 | "X = 123\n" 1320 | ] 1321 | }, 1322 | { 1323 | "data": { 1324 | "text/plain": [ 1325 | "defined \u001b[32mclass\u001b[39m \u001b[36mSomEntity\u001b[39m\n", 1326 | "defined \u001b[32mobject\u001b[39m \u001b[36mSomEntity\u001b[39m\n", 1327 | "\u001b[36mentity\u001b[39m: \u001b[32mSomEntity\u001b[39m = X = 123" 1328 | ] 1329 | }, 1330 | "execution_count": 46, 1331 | "metadata": {}, 1332 | "output_type": "execute_result" 1333 | } 1334 | ], 1335 | "source": [ 1336 | "// Если объект и класс имеют одно наименование, то они сливаются\n", 1337 | "\n", 1338 | "class SomEntity private(){\n", 1339 | " // Всё что ниже будет доступно из объекта!\n", 1340 | " private var x = 123 // Заметим, что тут написанно private\n", 1341 | " override def toString = s\"X = $x\"\n", 1342 | "}\n", 1343 | "\n", 1344 | "\n", 1345 | "// \n", 1346 | "object SomEntity{\n", 1347 | " def create = new SomEntity // Создаёт объект\n", 1348 | " def setX(x:Int, entity: SomEntity) = entity.x = x // Изменяет 'приватную' переменную\n", 1349 | "}\n", 1350 | "var entity = SomEntity.create\n", 1351 | "println(entity)" 1352 | ] 1353 | }, 1354 | { 1355 | "cell_type": "code", 1356 | "execution_count": 47, 1357 | "metadata": { 1358 | "collapsed": false 1359 | }, 1360 | "outputs": [ 1361 | { 1362 | "name": "stdout", 1363 | "output_type": "stream", 1364 | "text": [ 1365 | "X = 789\n" 1366 | ] 1367 | } 1368 | ], 1369 | "source": [ 1370 | "SomEntity.setX(789, entity)\n", 1371 | "println(entity)" 1372 | ] 1373 | }, 1374 | { 1375 | "cell_type": "markdown", 1376 | "metadata": {}, 1377 | "source": [ 1378 | "## Ничего или любое?" 1379 | ] 1380 | }, 1381 | { 1382 | "cell_type": "markdown", 1383 | "metadata": {}, 1384 | "source": [ 1385 | "![](https://prashanthbabu.gitbooks.io/scala_notes/content/Scala_TypeSystem_01.png)" 1386 | ] 1387 | }, 1388 | { 1389 | "cell_type": "code", 1390 | "execution_count": 48, 1391 | "metadata": { 1392 | "collapsed": false 1393 | }, 1394 | "outputs": [ 1395 | { 1396 | "ename": "", 1397 | "evalue": "", 1398 | "output_type": "error", 1399 | "traceback": [ 1400 | "\u001b[31mjava.lang.IllegalStateException\u001b[39m", 1401 | " $sess.cmd47Wrapper$Helper.fail(\u001b[32mcmd47.sc\u001b[39m:\u001b[32m1\u001b[39m)", 1402 | " $sess.cmd47Wrapper$Helper.(\u001b[32mcmd47.sc\u001b[39m:\u001b[32m4\u001b[39m)", 1403 | " $sess.cmd47Wrapper.(\u001b[32mcmd47.sc\u001b[39m:\u001b[32m513\u001b[39m)", 1404 | " $sess.cmd47$.(\u001b[32mcmd47.sc\u001b[39m:\u001b[32m275\u001b[39m)", 1405 | " $sess.cmd47$.(\u001b[32mcmd47.sc\u001b[39m:\u001b[32m-1\u001b[39m)" 1406 | ] 1407 | } 1408 | ], 1409 | "source": [ 1410 | "def fail() : Nothing = throw new IllegalStateException()\n", 1411 | "\n", 1412 | "// Пустоту мы можем присвоить чему угодно!\n", 1413 | "var x: Int = fail()\n", 1414 | "var y: Double = fail()" 1415 | ] 1416 | }, 1417 | { 1418 | "cell_type": "code", 1419 | "execution_count": 49, 1420 | "metadata": { 1421 | "collapsed": false 1422 | }, 1423 | "outputs": [ 1424 | { 1425 | "data": { 1426 | "text/plain": [ 1427 | "\u001b[36mx\u001b[39m: \u001b[32mAny\u001b[39m = 6.123" 1428 | ] 1429 | }, 1430 | "execution_count": 49, 1431 | "metadata": {}, 1432 | "output_type": "execute_result" 1433 | } 1434 | ], 1435 | "source": [ 1436 | "// \"scala.Any\" это супертип, который может быть действительно любым\n", 1437 | "var x: Any = null\n", 1438 | "x = 5\n", 1439 | "x = 6.123" 1440 | ] 1441 | }, 1442 | { 1443 | "cell_type": "markdown", 1444 | "metadata": {}, 1445 | "source": [ 1446 | "## AnyVal\n", 1447 | "\n", 1448 | "1. Подтип Any\n", 1449 | "2. Не имеет методов" 1450 | ] 1451 | }, 1452 | { 1453 | "cell_type": "code", 1454 | "execution_count": 50, 1455 | "metadata": { 1456 | "collapsed": false 1457 | }, 1458 | "outputs": [ 1459 | { 1460 | "data": { 1461 | "text/plain": [ 1462 | "\u001b[36mx\u001b[39m: \u001b[32mAnyVal\u001b[39m = 12.3" 1463 | ] 1464 | }, 1465 | "execution_count": 50, 1466 | "metadata": {}, 1467 | "output_type": "execute_result" 1468 | } 1469 | ], 1470 | "source": [ 1471 | "var x: AnyVal = 3;\n", 1472 | "x = 12.3" 1473 | ] 1474 | }, 1475 | { 1476 | "cell_type": "code", 1477 | "execution_count": 50, 1478 | "metadata": { 1479 | "collapsed": true 1480 | }, 1481 | "outputs": [], 1482 | "source": [ 1483 | "// А если задать x = 'строчка'" 1484 | ] 1485 | }, 1486 | { 1487 | "cell_type": "markdown", 1488 | "metadata": {}, 1489 | "source": [ 1490 | "## AnyRef\n", 1491 | "1. Подтип Any\n", 1492 | "2. Имеет некоторые из методов объекта - norfy, wait, etc." 1493 | ] 1494 | }, 1495 | { 1496 | "cell_type": "code", 1497 | "execution_count": 51, 1498 | "metadata": { 1499 | "collapsed": false 1500 | }, 1501 | "outputs": [ 1502 | { 1503 | "data": { 1504 | "text/plain": [ 1505 | "\u001b[36mx\u001b[39m: \u001b[32mAnyRef\u001b[39m = STRING" 1506 | ] 1507 | }, 1508 | "execution_count": 51, 1509 | "metadata": {}, 1510 | "output_type": "execute_result" 1511 | } 1512 | ], 1513 | "source": [ 1514 | "var x: AnyRef = null; // We can assign null to it\n", 1515 | "x = \"STRING\"" 1516 | ] 1517 | }, 1518 | { 1519 | "cell_type": "code", 1520 | "execution_count": 51, 1521 | "metadata": { 1522 | "collapsed": true 1523 | }, 1524 | "outputs": [], 1525 | "source": [ 1526 | "// А если x = int?" 1527 | ] 1528 | }, 1529 | { 1530 | "cell_type": "markdown", 1531 | "metadata": {}, 1532 | "source": [ 1533 | "Знакомьтесь, UNIT" 1534 | ] 1535 | }, 1536 | { 1537 | "cell_type": "code", 1538 | "execution_count": 52, 1539 | "metadata": { 1540 | "collapsed": true 1541 | }, 1542 | "outputs": [], 1543 | "source": [ 1544 | "// Unit is like void in java\n", 1545 | "var u : Unit = ()" 1546 | ] 1547 | }, 1548 | { 1549 | "cell_type": "markdown", 1550 | "metadata": {}, 1551 | "source": [ 1552 | "Option" 1553 | ] 1554 | }, 1555 | { 1556 | "cell_type": "code", 1557 | "execution_count": 53, 1558 | "metadata": { 1559 | "collapsed": false 1560 | }, 1561 | "outputs": [ 1562 | { 1563 | "data": { 1564 | "text/plain": [ 1565 | "\u001b[36mopt1\u001b[39m: \u001b[32mOption\u001b[39m[\u001b[32mString\u001b[39m] = \u001b[33mSome\u001b[39m(\u001b[32m\"Something\"\u001b[39m)\n", 1566 | "\u001b[36mopt2\u001b[39m: \u001b[32mOption\u001b[39m[\u001b[32mString\u001b[39m] = None" 1567 | ] 1568 | }, 1569 | "execution_count": 53, 1570 | "metadata": {}, 1571 | "output_type": "execute_result" 1572 | } 1573 | ], 1574 | "source": [ 1575 | "// Option это обёртка переменной\n", 1576 | "val opt1 : Option[String] = Some(\"Something\")\n", 1577 | "val opt2 : Option[String] = None" 1578 | ] 1579 | }, 1580 | { 1581 | "cell_type": "code", 1582 | "execution_count": 54, 1583 | "metadata": { 1584 | "collapsed": false 1585 | }, 1586 | "outputs": [ 1587 | { 1588 | "name": "stdout", 1589 | "output_type": "stream", 1590 | "text": [ 1591 | "Something\n", 1592 | "Empty\n" 1593 | ] 1594 | } 1595 | ], 1596 | "source": [ 1597 | "println (opt1.get)\n", 1598 | "println (opt2.getOrElse(\"Empty\"))" 1599 | ] 1600 | }, 1601 | { 1602 | "cell_type": "markdown", 1603 | "metadata": {}, 1604 | "source": [ 1605 | "Either - как Option, но может содержать код ошибки или сообщение об ошибке" 1606 | ] 1607 | }, 1608 | { 1609 | "cell_type": "code", 1610 | "execution_count": 55, 1611 | "metadata": { 1612 | "collapsed": false 1613 | }, 1614 | "outputs": [ 1615 | { 1616 | "data": { 1617 | "text/plain": [ 1618 | "\u001b[36msuccess\u001b[39m: \u001b[32mRight\u001b[39m[\u001b[32mNothing\u001b[39m, \u001b[32mInt\u001b[39m] = \u001b[33mRight\u001b[39m(\u001b[32m3\u001b[39m)\n", 1619 | "\u001b[36mer\u001b[39m: \u001b[32mLeft\u001b[39m[\u001b[32mString\u001b[39m, \u001b[32mNothing\u001b[39m] = \u001b[33mLeft\u001b[39m(\u001b[32m\"BAD ERROR\"\u001b[39m)" 1620 | ] 1621 | }, 1622 | "execution_count": 55, 1623 | "metadata": {}, 1624 | "output_type": "execute_result" 1625 | } 1626 | ], 1627 | "source": [ 1628 | "val success = Right (1 + 2)\n", 1629 | "val er = Left(\"BAD ERROR\")" 1630 | ] 1631 | }, 1632 | { 1633 | "cell_type": "code", 1634 | "execution_count": 56, 1635 | "metadata": { 1636 | "collapsed": false 1637 | }, 1638 | "outputs": [ 1639 | { 1640 | "name": "stdout", 1641 | "output_type": "stream", 1642 | "text": [ 1643 | "Right(3)\n", 1644 | "Left(BAD ERROR)\n" 1645 | ] 1646 | } 1647 | ], 1648 | "source": [ 1649 | "println(success)\n", 1650 | "println(er)" 1651 | ] 1652 | }, 1653 | { 1654 | "cell_type": "markdown", 1655 | "metadata": {}, 1656 | "source": [ 1657 | "## Контейнеры типа T" 1658 | ] 1659 | }, 1660 | { 1661 | "cell_type": "code", 1662 | "execution_count": 57, 1663 | "metadata": { 1664 | "collapsed": false 1665 | }, 1666 | "outputs": [ 1667 | { 1668 | "data": { 1669 | "text/plain": [ 1670 | "\u001b[36mlstInt\u001b[39m: \u001b[32mjava\u001b[39m.\u001b[32mutil\u001b[39m.\u001b[32mArrayList\u001b[39m[\u001b[32mInt\u001b[39m] = []\n", 1671 | "\u001b[36mlstNothing1\u001b[39m: \u001b[32mjava\u001b[39m.\u001b[32mutil\u001b[39m.\u001b[32mArrayList\u001b[39m[\u001b[32mNothing\u001b[39m] = []" 1672 | ] 1673 | }, 1674 | "execution_count": 57, 1675 | "metadata": {}, 1676 | "output_type": "execute_result" 1677 | } 1678 | ], 1679 | "source": [ 1680 | "var lstInt = new java.util.ArrayList[Int]\n", 1681 | "\n", 1682 | "// ничего есть подтип всего!\n", 1683 | "var lstNothing1 = new java.util.ArrayList" 1684 | ] 1685 | }, 1686 | { 1687 | "cell_type": "markdown", 1688 | "metadata": {}, 1689 | "source": [ 1690 | "## Ковариантность и контравариантность" 1691 | ] 1692 | }, 1693 | { 1694 | "cell_type": "code", 1695 | "execution_count": 58, 1696 | "metadata": { 1697 | "collapsed": false 1698 | }, 1699 | "outputs": [ 1700 | { 1701 | "data": { 1702 | "text/plain": [ 1703 | "defined \u001b[32mclass\u001b[39m \u001b[36mBox\u001b[39m" 1704 | ] 1705 | }, 1706 | "execution_count": 58, 1707 | "metadata": {}, 1708 | "output_type": "execute_result" 1709 | } 1710 | ], 1711 | "source": [ 1712 | "class Box[T](var el:T){\n", 1713 | " override def toString = s\"$el\"\n", 1714 | "}" 1715 | ] 1716 | }, 1717 | { 1718 | "cell_type": "code", 1719 | "execution_count": 59, 1720 | "metadata": { 1721 | "collapsed": false 1722 | }, 1723 | "outputs": [ 1724 | { 1725 | "name": "stdout", 1726 | "output_type": "stream", 1727 | "text": [ 1728 | "Победа 2\n", 1729 | "Победа 2\n", 1730 | "Победа 1\n" 1731 | ] 1732 | }, 1733 | { 1734 | "data": { 1735 | "text/plain": [ 1736 | "defined \u001b[32mfunction\u001b[39m \u001b[36msimpleF\u001b[39m\n", 1737 | "defined \u001b[32mfunction\u001b[39m \u001b[36mcovF\u001b[39m\n", 1738 | "\u001b[36mdb\u001b[39m: \u001b[32mBox\u001b[39m[\u001b[32mDer\u001b[39m] = null\n", 1739 | "\u001b[36mbb\u001b[39m: \u001b[32mBox\u001b[39m[\u001b[32mBase\u001b[39m] = null" 1740 | ] 1741 | }, 1742 | "execution_count": 59, 1743 | "metadata": {}, 1744 | "output_type": "execute_result" 1745 | } 1746 | ], 1747 | "source": [ 1748 | "// Метод без *иантность, мы ничего не можем поментяь\n", 1749 | "def simpleF(b : Box[Base]) : Unit = { println(\"Победа 1\") }\n", 1750 | "\n", 1751 | "// Ковариантный метод\n", 1752 | "def covF[T <: Base] (b : Box[T]) : Unit = { println(\"Победа 2\") }\n", 1753 | "\n", 1754 | "var db : Box[Der] = null\n", 1755 | "var bb : Box[Base] = null\n", 1756 | "covF(bb)\n", 1757 | "covF(db)\n", 1758 | "simpleF(bb)\n", 1759 | "//simpleF(db) - Не сработает" 1760 | ] 1761 | }, 1762 | { 1763 | "cell_type": "markdown", 1764 | "metadata": {}, 1765 | "source": [ 1766 | "## Неявные классы" 1767 | ] 1768 | }, 1769 | { 1770 | "cell_type": "code", 1771 | "execution_count": 60, 1772 | "metadata": { 1773 | "collapsed": false 1774 | }, 1775 | "outputs": [ 1776 | { 1777 | "data": { 1778 | "text/plain": [ 1779 | "defined \u001b[32mtype\u001b[39m \u001b[36mFType\u001b[39m\n", 1780 | "defined \u001b[32mfunction\u001b[39m \u001b[36mf\u001b[39m" 1781 | ] 1782 | }, 1783 | "execution_count": 60, 1784 | "metadata": {}, 1785 | "output_type": "execute_result" 1786 | } 1787 | ], 1788 | "source": [ 1789 | "// Типы функций можно задавть вот так:\n", 1790 | "type FType = (String, Int) => String \n", 1791 | "\n", 1792 | "// Создадим функцию, которая будет делать тоже самое\n", 1793 | "def f(s:String, n:Int) = s + n" 1794 | ] 1795 | }, 1796 | { 1797 | "cell_type": "code", 1798 | "execution_count": 61, 1799 | "metadata": { 1800 | "collapsed": false 1801 | }, 1802 | "outputs": [ 1803 | { 1804 | "data": { 1805 | "text/plain": [ 1806 | "\u001b[36mg\u001b[39m: (\u001b[32mString\u001b[39m, \u001b[32mInt\u001b[39m) => \u001b[32mString\u001b[39m = " 1807 | ] 1808 | }, 1809 | "execution_count": 61, 1810 | "metadata": {}, 1811 | "output_type": "execute_result" 1812 | } 1813 | ], 1814 | "source": [ 1815 | "val g : FType = (s,n) => s + n // Создадим функцию типа FType" 1816 | ] 1817 | }, 1818 | { 1819 | "cell_type": "code", 1820 | "execution_count": 62, 1821 | "metadata": { 1822 | "collapsed": false 1823 | }, 1824 | "outputs": [ 1825 | { 1826 | "data": { 1827 | "text/plain": [ 1828 | "\u001b[36mres61_0\u001b[39m: \u001b[32mString\u001b[39m = \u001b[32m\"a1\"\u001b[39m\n", 1829 | "\u001b[36mres61_1\u001b[39m: \u001b[32mString\u001b[39m = \u001b[32m\"a1\"\u001b[39m" 1830 | ] 1831 | }, 1832 | "execution_count": 62, 1833 | "metadata": {}, 1834 | "output_type": "execute_result" 1835 | } 1836 | ], 1837 | "source": [ 1838 | "f(\"a\", 1)\n", 1839 | "g(\"a\", 1)" 1840 | ] 1841 | }, 1842 | { 1843 | "cell_type": "code", 1844 | "execution_count": 63, 1845 | "metadata": { 1846 | "collapsed": false 1847 | }, 1848 | "outputs": [ 1849 | { 1850 | "data": { 1851 | "text/plain": [ 1852 | "\u001b[36mres62\u001b[39m: \u001b[32mString\u001b[39m = \u001b[32m\"a1\"\u001b[39m" 1853 | ] 1854 | }, 1855 | "execution_count": 63, 1856 | "metadata": {}, 1857 | "output_type": "execute_result" 1858 | } 1859 | ], 1860 | "source": [ 1861 | "g.apply(\"a\", 1)" 1862 | ] 1863 | }, 1864 | { 1865 | "cell_type": "markdown", 1866 | "metadata": {}, 1867 | "source": [ 1868 | "## Каррирование" 1869 | ] 1870 | }, 1871 | { 1872 | "cell_type": "code", 1873 | "execution_count": 64, 1874 | "metadata": { 1875 | "collapsed": false 1876 | }, 1877 | "outputs": [ 1878 | { 1879 | "data": { 1880 | "text/plain": [ 1881 | "defined \u001b[32mfunction\u001b[39m \u001b[36mf\u001b[39m" 1882 | ] 1883 | }, 1884 | "execution_count": 64, 1885 | "metadata": {}, 1886 | "output_type": "execute_result" 1887 | } 1888 | ], 1889 | "source": [ 1890 | "def f (a : Int) (b : Int) (c: Int) = a + b + c" 1891 | ] 1892 | }, 1893 | { 1894 | "cell_type": "code", 1895 | "execution_count": 65, 1896 | "metadata": { 1897 | "collapsed": false 1898 | }, 1899 | "outputs": [ 1900 | { 1901 | "data": { 1902 | "text/plain": [ 1903 | "\u001b[36mres64\u001b[39m: \u001b[32mInt\u001b[39m = \u001b[32m6\u001b[39m" 1904 | ] 1905 | }, 1906 | "execution_count": 65, 1907 | "metadata": {}, 1908 | "output_type": "execute_result" 1909 | } 1910 | ], 1911 | "source": [ 1912 | "f(1)(2)(3)" 1913 | ] 1914 | }, 1915 | { 1916 | "cell_type": "markdown", 1917 | "metadata": {}, 1918 | "source": [ 1919 | "Создадим новую функцию:" 1920 | ] 1921 | }, 1922 | { 1923 | "cell_type": "code", 1924 | "execution_count": 66, 1925 | "metadata": { 1926 | "collapsed": false 1927 | }, 1928 | "outputs": [ 1929 | { 1930 | "data": { 1931 | "text/plain": [ 1932 | "\u001b[36mf12\u001b[39m: \u001b[32mInt\u001b[39m => \u001b[32mInt\u001b[39m = " 1933 | ] 1934 | }, 1935 | "execution_count": 66, 1936 | "metadata": {}, 1937 | "output_type": "execute_result" 1938 | } 1939 | ], 1940 | "source": [ 1941 | "val f12 = f(1)(2)_" 1942 | ] 1943 | }, 1944 | { 1945 | "cell_type": "code", 1946 | "execution_count": 67, 1947 | "metadata": { 1948 | "collapsed": false 1949 | }, 1950 | "outputs": [ 1951 | { 1952 | "data": { 1953 | "text/plain": [ 1954 | "\u001b[36mres66_0\u001b[39m: \u001b[32mInt\u001b[39m = \u001b[32m6\u001b[39m\n", 1955 | "\u001b[36mres66_1\u001b[39m: \u001b[32mInt\u001b[39m = \u001b[32m7\u001b[39m" 1956 | ] 1957 | }, 1958 | "execution_count": 67, 1959 | "metadata": {}, 1960 | "output_type": "execute_result" 1961 | } 1962 | ], 1963 | "source": [ 1964 | "f12(3)\n", 1965 | "f12(4)" 1966 | ] 1967 | }, 1968 | { 1969 | "cell_type": "markdown", 1970 | "metadata": {}, 1971 | "source": [ 1972 | "## Partial function application" 1973 | ] 1974 | }, 1975 | { 1976 | "cell_type": "code", 1977 | "execution_count": 68, 1978 | "metadata": { 1979 | "collapsed": false 1980 | }, 1981 | "outputs": [ 1982 | { 1983 | "data": { 1984 | "text/plain": [ 1985 | "defined \u001b[32mfunction\u001b[39m \u001b[36mf\u001b[39m\n", 1986 | "\u001b[36mf1\u001b[39m: \u001b[32mInt\u001b[39m => \u001b[32mInt\u001b[39m = \n", 1987 | "\u001b[36mres67_2\u001b[39m: \u001b[32mInt\u001b[39m = \u001b[32m2\u001b[39m\n", 1988 | "\u001b[36mres67_3\u001b[39m: \u001b[32mInt\u001b[39m = \u001b[32m3\u001b[39m" 1989 | ] 1990 | }, 1991 | "execution_count": 68, 1992 | "metadata": {}, 1993 | "output_type": "execute_result" 1994 | } 1995 | ], 1996 | "source": [ 1997 | "def f(x:Int, y:Int) = x + y\n", 1998 | "\n", 1999 | "// Define a partially applied function - use the _ for the lefover parameter\n", 2000 | "val f1 = f(1, _ :Int)\n", 2001 | "\n", 2002 | "f1(1)\n", 2003 | "f1(2)" 2004 | ] 2005 | }, 2006 | { 2007 | "cell_type": "markdown", 2008 | "metadata": {}, 2009 | "source": [ 2010 | "## Типажи \n", 2011 | "\n", 2012 | "> Абстрактный тип данных, используемый как «простая концептуальная модель для структурирования объектно ориентированных программ». Типажи подобны примесям, но могут содержать только методы. Также отличается способ разрешения конфликтов — типажи не допускают совпадения названий методов." 2013 | ] 2014 | }, 2015 | { 2016 | "cell_type": "code", 2017 | "execution_count": 69, 2018 | "metadata": { 2019 | "collapsed": false 2020 | }, 2021 | "outputs": [ 2022 | { 2023 | "data": { 2024 | "text/plain": [ 2025 | "defined \u001b[32mtrait\u001b[39m \u001b[36mBaseT\u001b[39m" 2026 | ] 2027 | }, 2028 | "execution_count": 69, 2029 | "metadata": {}, 2030 | "output_type": "execute_result" 2031 | } 2032 | ], 2033 | "source": [ 2034 | "trait BaseT {\n", 2035 | " // Эта переменная будет доступна во всех подтипах, потому что она задана\n", 2036 | " val fromBase : String = \"FromBase\"\n", 2037 | " // Каждый класс обязан задать это значение\n", 2038 | " val fromDer : String\n", 2039 | "\n", 2040 | " // Каждый класс обязан задать это значение\n", 2041 | " def abstractMessage\n", 2042 | "\n", 2043 | " // Вывод всего и вся\n", 2044 | " def message = println(s\"Values $fromBase $fromDer $abstractMessage\")\n", 2045 | "}" 2046 | ] 2047 | }, 2048 | { 2049 | "cell_type": "code", 2050 | "execution_count": 71, 2051 | "metadata": { 2052 | "collapsed": false 2053 | }, 2054 | "outputs": [ 2055 | { 2056 | "data": { 2057 | "text/plain": [ 2058 | "defined \u001b[32mclass\u001b[39m \u001b[36mDerC\u001b[39m\n", 2059 | "\u001b[36mx\u001b[39m: \u001b[32mwrapper\u001b[39m.\u001b[32mwrapper\u001b[39m.\u001b[32mDerC\u001b[39m = $sess.cmd70Wrapper$Helper$DerC@4770a412" 2060 | ] 2061 | }, 2062 | "execution_count": 71, 2063 | "metadata": {}, 2064 | "output_type": "execute_result" 2065 | } 2066 | ], 2067 | "source": [ 2068 | "class DerC(override val fromDer:String) extends BaseT {\n", 2069 | " override def abstractMessage = println(\"Derived class implementation\")\n", 2070 | "}\n", 2071 | "\n", 2072 | "val x = new DerC(\"Derived\")" 2073 | ] 2074 | }, 2075 | { 2076 | "cell_type": "code", 2077 | "execution_count": 72, 2078 | "metadata": { 2079 | "collapsed": false 2080 | }, 2081 | "outputs": [ 2082 | { 2083 | "name": "stdout", 2084 | "output_type": "stream", 2085 | "text": [ 2086 | "FromBase\n", 2087 | "Derived\n" 2088 | ] 2089 | } 2090 | ], 2091 | "source": [ 2092 | "println(x.fromBase)\n", 2093 | "println(x.fromDer)" 2094 | ] 2095 | }, 2096 | { 2097 | "cell_type": "code", 2098 | "execution_count": 73, 2099 | "metadata": { 2100 | "collapsed": false 2101 | }, 2102 | "outputs": [ 2103 | { 2104 | "name": "stdout", 2105 | "output_type": "stream", 2106 | "text": [ 2107 | "Derived class implementation\n", 2108 | "Derived class implementation\n", 2109 | "Values FromBase Derived ()\n" 2110 | ] 2111 | } 2112 | ], 2113 | "source": [ 2114 | "x.abstractMessage\n", 2115 | "x.message" 2116 | ] 2117 | }, 2118 | { 2119 | "cell_type": "code", 2120 | "execution_count": 75, 2121 | "metadata": { 2122 | "collapsed": false 2123 | }, 2124 | "outputs": [ 2125 | { 2126 | "data": { 2127 | "text/plain": [ 2128 | "defined \u001b[32mtrait\u001b[39m \u001b[36mBaseT1\u001b[39m\n", 2129 | "defined \u001b[32mtrait\u001b[39m \u001b[36mBaseT2\u001b[39m\n", 2130 | "defined \u001b[32mclass\u001b[39m \u001b[36mMultiTrait\u001b[39m\n", 2131 | "defined \u001b[32mclass\u001b[39m \u001b[36mInheritWithMultiTrait\u001b[39m" 2132 | ] 2133 | }, 2134 | "execution_count": 75, 2135 | "metadata": {}, 2136 | "output_type": "execute_result" 2137 | } 2138 | ], 2139 | "source": [ 2140 | "trait BaseT1 {}\n", 2141 | "trait BaseT2 {}\n", 2142 | "\n", 2143 | "// Вы можете использовать несколько типажей для одного класса\n", 2144 | "class MultiTrait extends BaseT1 with BaseT2 \n", 2145 | "class InheritWithMultiTrait extends AnyRef with BaseT1 with BaseT2" 2146 | ] 2147 | }, 2148 | { 2149 | "cell_type": "markdown", 2150 | "metadata": {}, 2151 | "source": [ 2152 | "## Типажи и объекты" 2153 | ] 2154 | }, 2155 | { 2156 | "cell_type": "code", 2157 | "execution_count": 76, 2158 | "metadata": { 2159 | "collapsed": false 2160 | }, 2161 | "outputs": [ 2162 | { 2163 | "data": { 2164 | "text/plain": [ 2165 | "defined \u001b[32mclass\u001b[39m \u001b[36mSomeClass\u001b[39m\n", 2166 | "\u001b[36mxWithBaseT\u001b[39m: \u001b[32mSomeClass\u001b[39m with \u001b[32mBaseT\u001b[39m = $sess.cmd75Wrapper$Helper$$anon$1@2d48c8d4\n", 2167 | "\u001b[36mx\u001b[39m: \u001b[32mBaseT\u001b[39m = $sess.cmd75Wrapper$Helper$$anon$1@2d48c8d4" 2168 | ] 2169 | }, 2170 | "execution_count": 76, 2171 | "metadata": {}, 2172 | "output_type": "execute_result" 2173 | } 2174 | ], 2175 | "source": [ 2176 | "class SomeClass(val fromDer:String){\n", 2177 | " def abstractMessage = println(\"Derived class implementation\")\n", 2178 | "}\n", 2179 | "\n", 2180 | "\n", 2181 | "val xWithBaseT = new SomeClass(\"Test\") with BaseT\n", 2182 | "var x : BaseT = xWithBaseT " 2183 | ] 2184 | }, 2185 | { 2186 | "cell_type": "markdown", 2187 | "metadata": {}, 2188 | "source": [ 2189 | "## Изменяемое и неизменяемое\n", 2190 | "\n", 2191 | "Scala имеет 3 основных типа коллекции. (List, Set, и Map). Как говорится, из коробки они не изменяемые. Но всё зависит от того, откуда они импортированны. А они могут взяться из:\n", 2192 | "\n", 2193 | "1. scala.collection.mutable\n", 2194 | "2. scala.collection.immutable\n" 2195 | ] 2196 | }, 2197 | { 2198 | "cell_type": "markdown", 2199 | "metadata": {}, 2200 | "source": [ 2201 | "Синтаксис" 2202 | ] 2203 | }, 2204 | { 2205 | "cell_type": "code", 2206 | "execution_count": 77, 2207 | "metadata": { 2208 | "collapsed": false 2209 | }, 2210 | "outputs": [ 2211 | { 2212 | "data": { 2213 | "text/plain": [ 2214 | "\u001b[36ml\u001b[39m: \u001b[32mList\u001b[39m[\u001b[32mInt\u001b[39m] = \u001b[33mList\u001b[39m(\u001b[32m1\u001b[39m, \u001b[32m2\u001b[39m, \u001b[32m3\u001b[39m)\n", 2215 | "\u001b[36ms\u001b[39m: \u001b[32mSet\u001b[39m[\u001b[32mInt\u001b[39m] = \u001b[33mSet\u001b[39m(\u001b[32m1\u001b[39m, \u001b[32m2\u001b[39m, \u001b[32m3\u001b[39m)\n", 2216 | "\u001b[36mm\u001b[39m: \u001b[32mMap\u001b[39m[\u001b[32mInt\u001b[39m, \u001b[32mString\u001b[39m] = \u001b[33mMap\u001b[39m(\u001b[32m1\u001b[39m -> \u001b[32m\"1\"\u001b[39m, \u001b[32m2\u001b[39m -> \u001b[32m\"2\"\u001b[39m)" 2217 | ] 2218 | }, 2219 | "execution_count": 77, 2220 | "metadata": {}, 2221 | "output_type": "execute_result" 2222 | } 2223 | ], 2224 | "source": [ 2225 | "val l = List(1,2,3)\n", 2226 | "var s = Set(1,2,3)\n", 2227 | "var m = Map(1 -> \"1\", 2 -> \"2\")" 2228 | ] 2229 | }, 2230 | { 2231 | "cell_type": "markdown", 2232 | "metadata": {}, 2233 | "source": [ 2234 | "Сатандартные действия" 2235 | ] 2236 | }, 2237 | { 2238 | "cell_type": "code", 2239 | "execution_count": 79, 2240 | "metadata": { 2241 | "collapsed": false 2242 | }, 2243 | "outputs": [ 2244 | { 2245 | "name": "stdout", 2246 | "output_type": "stream", 2247 | "text": [ 2248 | "Set(1, 2, 3, 4)\n", 2249 | "Set(1)\n", 2250 | "Set(2, 3)\n", 2251 | "Set(2)\n", 2252 | "List(1, 2, 1, 3, 4)\n", 2253 | "List(1, 2, 1, 3, 4)\n", 2254 | "1\n", 2255 | "1\n", 2256 | "List(1, 2, 3, 4)\n", 2257 | "List(1, 2, 3)\n", 2258 | "List()\n", 2259 | "1\n", 2260 | "List(2, 3)\n", 2261 | "1\n", 2262 | "1\n", 2263 | "1\n" 2264 | ] 2265 | } 2266 | ], 2267 | "source": [ 2268 | "// Множества\n", 2269 | "println(Set(1,2) ++ Set(1,3,4)) // Возращает Set(1, 2, 3, 4)\n", 2270 | "println(Set(1,2) & Set(1,3,4)) // Возращает пересечение Set(1)\n", 2271 | "println(Set(1,2).map(_ + 1)) // Вернёт Set(2,3)\n", 2272 | "println(Set(1,2).filter(_ % 2 == 0)) // Вернёт Set(2)\n", 2273 | "\n", 2274 | "// Списки\n", 2275 | "println(List(1,2) ++ List(1,3,4)) // List(1, 2, 1, 3, 4)\n", 2276 | "println(List(1,2) ::: List(1,3,4)) // List(1, 2, 1, 3, 4)\n", 2277 | "\n", 2278 | "// MAP FILTER REDUCE <- как залог машинного обучения\n", 2279 | "println(List(1,2).apply(0)) // 1\n", 2280 | "println(List(1,2)(0)) // 1; Тоже самое, что и apply\n", 2281 | "println(1 :: List(2,3,4)) // Добавит в начало списка List(1, 2, 3, 4)\n", 2282 | "println(1::2::3::Nil) // Так же можно сделать список с помощью такого синтаксиса\n", 2283 | "println(Nil) // Nil - это пустой список\n", 2284 | "println(List(1,2,3).head) // Вернёт первый элемент\n", 2285 | "println(List(1,2,3).tail) // Кроме первого element List(2,3)\n", 2286 | "\n", 2287 | "// Словари\n", 2288 | "println(Map(1 -> \"1\").apply(1)) // Достать с помощью apply\n", 2289 | "println(Map(1 -> \"1\")(1)) // ^\n", 2290 | "println(Map(1 -> \"1\").get(1).get) // сначала достанет опцию, а потом вернёт \"1\"" 2291 | ] 2292 | }, 2293 | { 2294 | "cell_type": "code", 2295 | "execution_count": 90, 2296 | "metadata": { 2297 | "collapsed": false 2298 | }, 2299 | "outputs": [ 2300 | { 2301 | "data": { 2302 | "text/plain": [ 2303 | "\u001b[36mlist\u001b[39m: \u001b[32mList\u001b[39m[\u001b[32mInt\u001b[39m] = \u001b[33mList\u001b[39m(\u001b[32m1\u001b[39m, \u001b[32m2\u001b[39m, \u001b[32m3\u001b[39m, \u001b[32m4\u001b[39m)\n", 2304 | "\u001b[36mres89_1\u001b[39m: \u001b[32mInt\u001b[39m = \u001b[32m14\u001b[39m\n", 2305 | "\u001b[36mres89_2\u001b[39m: \u001b[32mInt\u001b[39m = \u001b[32m10\u001b[39m" 2306 | ] 2307 | }, 2308 | "execution_count": 90, 2309 | "metadata": {}, 2310 | "output_type": "execute_result" 2311 | } 2312 | ], 2313 | "source": [ 2314 | "val list = List(1,2,3,4)\n", 2315 | "list.foldLeft(4) (_ + _)\n", 2316 | "list.reduceLeft(_ + _)" 2317 | ] 2318 | }, 2319 | { 2320 | "cell_type": "code", 2321 | "execution_count": 91, 2322 | "metadata": { 2323 | "collapsed": false 2324 | }, 2325 | "outputs": [ 2326 | { 2327 | "data": { 2328 | "text/plain": [ 2329 | "\u001b[36mres90\u001b[39m: \u001b[32mInt\u001b[39m = \u001b[32m10\u001b[39m" 2330 | ] 2331 | }, 2332 | "execution_count": 91, 2333 | "metadata": {}, 2334 | "output_type": "execute_result" 2335 | } 2336 | ], 2337 | "source": [ 2338 | "(0 /: list) (_ + _)" 2339 | ] 2340 | }, 2341 | { 2342 | "cell_type": "markdown", 2343 | "metadata": {}, 2344 | "source": [ 2345 | "Питонисты, возрадуйтесь! list comprehensions" 2346 | ] 2347 | }, 2348 | { 2349 | "cell_type": "code", 2350 | "execution_count": 95, 2351 | "metadata": { 2352 | "collapsed": false 2353 | }, 2354 | "outputs": [ 2355 | { 2356 | "data": { 2357 | "text/plain": [ 2358 | "\u001b[36mres\u001b[39m: \u001b[32mList\u001b[39m[(\u001b[32mInt\u001b[39m, \u001b[32mInt\u001b[39m)] = \u001b[33mList\u001b[39m((\u001b[32m1\u001b[39m, \u001b[32m1\u001b[39m), (\u001b[32m2\u001b[39m, \u001b[32m2\u001b[39m))" 2359 | ] 2360 | }, 2361 | "execution_count": 95, 2362 | "metadata": {}, 2363 | "output_type": "execute_result" 2364 | } 2365 | ], 2366 | "source": [ 2367 | "val res = for(i <- List(1,2,3);\n", 2368 | " j <- List(i);\n", 2369 | " if i + j < 5\n", 2370 | " ) yield (i,j)" 2371 | ] 2372 | }, 2373 | { 2374 | "cell_type": "markdown", 2375 | "metadata": {}, 2376 | "source": [ 2377 | "Работа с текстами" 2378 | ] 2379 | }, 2380 | { 2381 | "cell_type": "code", 2382 | "execution_count": 96, 2383 | "metadata": { 2384 | "collapsed": false 2385 | }, 2386 | "outputs": [ 2387 | { 2388 | "data": { 2389 | "text/plain": [ 2390 | "defined \u001b[32mfunction\u001b[39m \u001b[36mf\u001b[39m" 2391 | ] 2392 | }, 2393 | "execution_count": 96, 2394 | "metadata": {}, 2395 | "output_type": "execute_result" 2396 | } 2397 | ], 2398 | "source": [ 2399 | "// Строки\n", 2400 | "def f(s:String) = \n", 2401 | " s match {\n", 2402 | " case \"Только функция\" => println(\"Это как словарь\")\n", 2403 | " case \"Это как словарь\" => println(\"Только функция\")\n", 2404 | " case _ => \"Что вообще происходит\"\n", 2405 | " }" 2406 | ] 2407 | }, 2408 | { 2409 | "cell_type": "code", 2410 | "execution_count": 99, 2411 | "metadata": { 2412 | "collapsed": false 2413 | }, 2414 | "outputs": [ 2415 | { 2416 | "name": "stdout", 2417 | "output_type": "stream", 2418 | "text": [ 2419 | "Это как словарь\n", 2420 | "Только функция\n" 2421 | ] 2422 | }, 2423 | { 2424 | "data": { 2425 | "text/plain": [ 2426 | "\u001b[36mres98_0\u001b[39m: \u001b[32mAny\u001b[39m = ()\n", 2427 | "\u001b[36mres98_1\u001b[39m: \u001b[32mAny\u001b[39m = ()\n", 2428 | "\u001b[36mres98_2\u001b[39m: \u001b[32mAny\u001b[39m = Что вообще происходит" 2429 | ] 2430 | }, 2431 | "execution_count": 99, 2432 | "metadata": {}, 2433 | "output_type": "execute_result" 2434 | } 2435 | ], 2436 | "source": [ 2437 | "f(\"Только функция\")\n", 2438 | "f(\"Это как словарь\")\n", 2439 | "f(\"Обманка\")" 2440 | ] 2441 | }, 2442 | { 2443 | "cell_type": "code", 2444 | "execution_count": 104, 2445 | "metadata": { 2446 | "collapsed": false 2447 | }, 2448 | "outputs": [ 2449 | { 2450 | "data": { 2451 | "text/plain": [ 2452 | "defined \u001b[32mfunction\u001b[39m \u001b[36mf\u001b[39m\n", 2453 | "\u001b[36mres103_1\u001b[39m: \u001b[32mString\u001b[39m = \u001b[32m\"Вот\"\u001b[39m\n", 2454 | "\u001b[36mres103_2\u001b[39m: \u001b[32mString\u001b[39m = \u001b[32m\"Что(2 999)\"\u001b[39m\n", 2455 | "\u001b[36mres103_3\u001b[39m: \u001b[32mString\u001b[39m = \u001b[32m\"Происходит 5\"\u001b[39m\n", 2456 | "\u001b[36mres103_4\u001b[39m: \u001b[32mString\u001b[39m = \u001b[32m\"Когда 1 и 2\"\u001b[39m\n", 2457 | "\u001b[36mres103_5\u001b[39m: \u001b[32mString\u001b[39m = \u001b[32m\"Ты 5\"\u001b[39m\n", 2458 | "\u001b[36mres103_6\u001b[39m: \u001b[32mString\u001b[39m = \u001b[32m\"Scala!\"\u001b[39m" 2459 | ] 2460 | }, 2461 | "execution_count": 104, 2462 | "metadata": {}, 2463 | "output_type": "execute_result" 2464 | } 2465 | ], 2466 | "source": [ 2467 | "def f(x:Any) : String = {\n", 2468 | " x match {\n", 2469 | " case (5, _) => \"Вот\"\n", 2470 | " case (a, b) => s\"Что($a $b)\"\n", 2471 | " case 5::_ => \"Происходит 5\"\n", 2472 | " case List(1, 2, _*) => \"Когда 1 и 2\"\n", 2473 | " case a : Int => s\"Ты $a\"\n", 2474 | " case _ => \"Scala!\"\n", 2475 | " }\n", 2476 | "}\n", 2477 | "\n", 2478 | "f((5, 1))\n", 2479 | "f((2, 999))\n", 2480 | "f(List(5, 6, 7))\n", 2481 | "f(List(1, 2, 3))\n", 2482 | "f(5)\n", 2483 | "f(12.3)" 2484 | ] 2485 | }, 2486 | { 2487 | "cell_type": "code", 2488 | "execution_count": 105, 2489 | "metadata": { 2490 | "collapsed": false 2491 | }, 2492 | "outputs": [ 2493 | { 2494 | "data": { 2495 | "text/plain": [ 2496 | "defined \u001b[32mfunction\u001b[39m \u001b[36mf\u001b[39m\n", 2497 | "\u001b[36mres104_1\u001b[39m: \u001b[32mString\u001b[39m = \u001b[32m\"+\"\u001b[39m\n", 2498 | "\u001b[36mres104_2\u001b[39m: \u001b[32mString\u001b[39m = \u001b[32m\"-\"\u001b[39m\n", 2499 | "\u001b[36mres104_3\u001b[39m: \u001b[32mString\u001b[39m = \u001b[32m\"ROCk\"\u001b[39m\n", 2500 | "\u001b[36mres104_4\u001b[39m: \u001b[32mString\u001b[39m = \u001b[32m\"Kk\"\u001b[39m" 2501 | ] 2502 | }, 2503 | "execution_count": 105, 2504 | "metadata": {}, 2505 | "output_type": "execute_result" 2506 | } 2507 | ], 2508 | "source": [ 2509 | "def f(x : Any):String = {\n", 2510 | " x match {\n", 2511 | " case i:Int if (i >= 0) => \"+\"\n", 2512 | " case i:Int if (i < 0) => \"-\"\n", 2513 | " case s:String if(s contains \"scala\") => \"ROCk\"\n", 2514 | " case _ => \"Kk\"\n", 2515 | " }\n", 2516 | "}\n", 2517 | "f(1)\n", 2518 | "f(-5)\n", 2519 | "f(\"scala - это\")\n", 2520 | "f(\"\")" 2521 | ] 2522 | }, 2523 | { 2524 | "cell_type": "code", 2525 | "execution_count": 106, 2526 | "metadata": { 2527 | "collapsed": false 2528 | }, 2529 | "outputs": [ 2530 | { 2531 | "name": "stdout", 2532 | "output_type": "stream", 2533 | "text": [ 2534 | "X:Shh!\n" 2535 | ] 2536 | }, 2537 | { 2538 | "data": { 2539 | "text/plain": [ 2540 | "defined \u001b[32mclass\u001b[39m \u001b[36mXFile\u001b[39m\n", 2541 | "defined \u001b[32mclass\u001b[39m \u001b[36mYFile\u001b[39m\n", 2542 | "\u001b[36mx\u001b[39m: \u001b[32mAny\u001b[39m = XFile(Secret)" 2543 | ] 2544 | }, 2545 | "execution_count": 106, 2546 | "metadata": {}, 2547 | "output_type": "execute_result" 2548 | } 2549 | ], 2550 | "source": [ 2551 | "// case class не могут содержать параметров, они однослойны =)\n", 2552 | "case class XFile(file: String);\n", 2553 | "case class YFile(file: String);\n", 2554 | "\n", 2555 | "// В отличии от других классов, мы не должны писать new\n", 2556 | "val x:Any = XFile(\"Secret\")\n", 2557 | "\n", 2558 | "// А вот теперь мы можем посмотреть, что происходит\n", 2559 | "x match {\n", 2560 | " case XFile(\"Secret\") => println(\"X:Shh!\")\n", 2561 | " case YFile(\"Secret\") => println(\"Y:Shh!\")\n", 2562 | " case XFile(_) => println(\"What did X say?\")\n", 2563 | " case YFile(_) => println(\"What did Y say?\")\n", 2564 | " case _ => println(\"Say What?\")\n", 2565 | "}" 2566 | ] 2567 | }, 2568 | { 2569 | "cell_type": "markdown", 2570 | "metadata": {}, 2571 | "source": [ 2572 | "## Extractors\n", 2573 | "Extractors - это такой тип объектов, у котрых есть функция unapply. " 2574 | ] 2575 | }, 2576 | { 2577 | "cell_type": "code", 2578 | "execution_count": 110, 2579 | "metadata": { 2580 | "collapsed": false 2581 | }, 2582 | "outputs": [ 2583 | { 2584 | "name": "stdout", 2585 | "output_type": "stream", 2586 | "text": [ 2587 | "tvorog@tvorog.me\n", 2588 | "tvorog | tvorog.me\n" 2589 | ] 2590 | }, 2591 | { 2592 | "data": { 2593 | "text/plain": [ 2594 | "defined \u001b[32mobject\u001b[39m \u001b[36mEmailExtractor\u001b[39m" 2595 | ] 2596 | }, 2597 | "execution_count": 110, 2598 | "metadata": {}, 2599 | "output_type": "execute_result" 2600 | } 2601 | ], 2602 | "source": [ 2603 | "object EmailExtractor {\n", 2604 | " def unapply(s : String):Option[Array[String]] = {\n", 2605 | " val parts = s.split(\"@\")\n", 2606 | " if(parts.length == 2) Some(parts) else None\n", 2607 | " }\n", 2608 | "\n", 2609 | " def apply(l : Array[String]) = l.mkString(\"@\")\n", 2610 | "}\n", 2611 | "println(EmailExtractor.apply(Array(\"tvorog\", \"tvorog.me\")))\n", 2612 | "println(EmailExtractor.unapply(\"tvorog@tvorog.me\").get.mkString(\" | \"))" 2613 | ] 2614 | }, 2615 | { 2616 | "cell_type": "code", 2617 | "execution_count": 117, 2618 | "metadata": { 2619 | "collapsed": false 2620 | }, 2621 | "outputs": [ 2622 | { 2623 | "name": "stdout", 2624 | "output_type": "stream", 2625 | "text": [ 2626 | "Email типа tvorog | tvorog.me\n" 2627 | ] 2628 | }, 2629 | { 2630 | "data": { 2631 | "text/plain": [ 2632 | "\u001b[36mx\u001b[39m: \u001b[32mString\u001b[39m = \u001b[32m\"tvorog@tvorog.me\"\u001b[39m" 2633 | ] 2634 | }, 2635 | "execution_count": 117, 2636 | "metadata": {}, 2637 | "output_type": "execute_result" 2638 | } 2639 | ], 2640 | "source": [ 2641 | "val x = \"tvorog@tvorog.me\"\n", 2642 | "\n", 2643 | "x match {\n", 2644 | " case EmailExtractor(Array(\"1\",\"2\")) => println(\"Email типа 1@2\")\n", 2645 | "\n", 2646 | " case EmailExtractor(Array(u, d)) => println(s\"Email типа $u | $d\")\n", 2647 | "\n", 2648 | " case _ => println(\"Didn't match anything\")\n", 2649 | "}" 2650 | ] 2651 | }, 2652 | { 2653 | "cell_type": "markdown", 2654 | "metadata": {}, 2655 | "source": [ 2656 | "## Регулярки" 2657 | ] 2658 | }, 2659 | { 2660 | "cell_type": "code", 2661 | "execution_count": 118, 2662 | "metadata": { 2663 | "collapsed": false 2664 | }, 2665 | "outputs": [ 2666 | { 2667 | "name": "stdout", 2668 | "output_type": "stream", 2669 | "text": [ 2670 | "123 and 456\n" 2671 | ] 2672 | }, 2673 | { 2674 | "data": { 2675 | "text/plain": [ 2676 | "\u001b[36mregEx\u001b[39m: \u001b[32mutil\u001b[39m.\u001b[32mmatching\u001b[39m.\u001b[32mRegex\u001b[39m = \\d+" 2677 | ] 2678 | }, 2679 | "execution_count": 118, 2680 | "metadata": {}, 2681 | "output_type": "execute_result" 2682 | } 2683 | ], 2684 | "source": [ 2685 | "//Все регулярки лежат в util.matching.Regex\n", 2686 | "\n", 2687 | "val regEx = \"\"\"\\d+\"\"\".r\n", 2688 | "\n", 2689 | "println ((regEx findAllIn \"123 abcxyz 456\").mkString(\" and \"))" 2690 | ] 2691 | }, 2692 | { 2693 | "cell_type": "code", 2694 | "execution_count": 120, 2695 | "metadata": { 2696 | "collapsed": false 2697 | }, 2698 | "outputs": [ 2699 | { 2700 | "name": "stdout", 2701 | "output_type": "stream", 2702 | "text": [ 2703 | "group 1=123 group2= xyz group3=456\n" 2704 | ] 2705 | }, 2706 | { 2707 | "data": { 2708 | "text/plain": [ 2709 | "\u001b[36mpattern\u001b[39m: \u001b[32mutil\u001b[39m.\u001b[32mmatching\u001b[39m.\u001b[32mRegex\u001b[39m = (\\d+)(\\D*)(\\d+)" 2710 | ] 2711 | }, 2712 | "execution_count": 120, 2713 | "metadata": {}, 2714 | "output_type": "execute_result" 2715 | } 2716 | ], 2717 | "source": [ 2718 | "val pattern = \"\"\"(\\d+)(\\D*)(\\d+)\"\"\".r\n", 2719 | "\n", 2720 | "\"123 xyz 456\" match{\n", 2721 | " case pattern(x, y, z) => println(s\"group 1=$x group2=$y group3=$z\")\n", 2722 | " case _ => println(\"Не совпадают\")\n", 2723 | "}" 2724 | ] 2725 | }, 2726 | { 2727 | "cell_type": "markdown", 2728 | "metadata": {}, 2729 | "source": [ 2730 | "## Ловим ошибки" 2731 | ] 2732 | }, 2733 | { 2734 | "cell_type": "code", 2735 | "execution_count": 122, 2736 | "metadata": { 2737 | "collapsed": false 2738 | }, 2739 | "outputs": [ 2740 | { 2741 | "name": "stdout", 2742 | "output_type": "stream", 2743 | "text": [ 2744 | "ERROR\n", 2745 | "Прямо как в Java!\n" 2746 | ] 2747 | } 2748 | ], 2749 | "source": [ 2750 | "try {\n", 2751 | " throw new IllegalArgumentException(\"ERROR\")\n", 2752 | "} catch {\n", 2753 | " // Для того, чтобы поймать конкретную ошибку - нужно использовать case\n", 2754 | " case e: NumberFormatException => println(e.getMessage)\n", 2755 | " case e: IllegalArgumentException => println(e.getMessage)\n", 2756 | " case _: Throwable => println(\"Random Error\")\n", 2757 | "} finally {\n", 2758 | " println(\"Прямо как в Java!\")\n", 2759 | "}" 2760 | ] 2761 | }, 2762 | { 2763 | "cell_type": "markdown", 2764 | "metadata": {}, 2765 | "source": [ 2766 | "## Ленивые вычесления" 2767 | ] 2768 | }, 2769 | { 2770 | "cell_type": "code", 2771 | "execution_count": 124, 2772 | "metadata": { 2773 | "collapsed": false 2774 | }, 2775 | "outputs": [ 2776 | { 2777 | "name": "stdout", 2778 | "output_type": "stream", 2779 | "text": [ 2780 | "Не выполнит f при присвоении\n", 2781 | "Выполняю ...\n" 2782 | ] 2783 | }, 2784 | { 2785 | "data": { 2786 | "text/plain": [ 2787 | "defined \u001b[32mfunction\u001b[39m \u001b[36mf\u001b[39m\n", 2788 | "\u001b[36mlazyX\u001b[39m: \u001b[32mInt\u001b[39m = \u001b[32m\u001b[39m\n", 2789 | "\u001b[36mx\u001b[39m: \u001b[32mInt\u001b[39m = \u001b[32m10\u001b[39m" 2790 | ] 2791 | }, 2792 | "execution_count": 124, 2793 | "metadata": {}, 2794 | "output_type": "execute_result" 2795 | } 2796 | ], 2797 | "source": [ 2798 | "def f():Int = {\n", 2799 | " println(\"Выполняю ...\")\n", 2800 | " return 5\n", 2801 | "}\n", 2802 | "\n", 2803 | "lazy val lazyX = f\n", 2804 | "println(\"Не выполнит f при присвоении\")\n", 2805 | "\n", 2806 | "// А вот теперь самое время её выполнить\n", 2807 | "val x = lazyX + 5" 2808 | ] 2809 | }, 2810 | { 2811 | "cell_type": "code", 2812 | "execution_count": 127, 2813 | "metadata": { 2814 | "collapsed": false 2815 | }, 2816 | "outputs": [ 2817 | { 2818 | "name": "stdout", 2819 | "output_type": "stream", 2820 | "text": [ 2821 | "======== Актив =========\n", 2822 | "1\n", 2823 | "2\n", 2824 | "3\n", 2825 | "======== Пассив =========\n", 2826 | "1\n" 2827 | ] 2828 | }, 2829 | { 2830 | "data": { 2831 | "text/plain": [ 2832 | "defined \u001b[32mfunction\u001b[39m \u001b[36mpred\u001b[39m\n", 2833 | "\u001b[36mres126_2\u001b[39m: \u001b[32mInt\u001b[39m = \u001b[32m1\u001b[39m\n", 2834 | "\u001b[36mv\u001b[39m: \u001b[32mInt\u001b[39m = \u001b[32m1\u001b[39m" 2835 | ] 2836 | }, 2837 | "execution_count": 127, 2838 | "metadata": {}, 2839 | "output_type": "execute_result" 2840 | } 2841 | ], 2842 | "source": [ 2843 | "def pred(s:Int):Boolean = {\n", 2844 | " println(s\"${s}\")\n", 2845 | " s == 1\n", 2846 | "}\n", 2847 | "\n", 2848 | "println(\"======== Актив =========\")\n", 2849 | "\n", 2850 | "// Для каждого элемента будет считать \n", 2851 | "Vector(1,2,3).filter(pred).head \n", 2852 | "\n", 2853 | "println(\"======== Пассив =========\")\n", 2854 | "\n", 2855 | "// \"view\" делает коллекцию ленивой. Вызовется только 1 раз\n", 2856 | "val v = Vector(1,2,3).view.filter(pred).head" 2857 | ] 2858 | }, 2859 | { 2860 | "cell_type": "code", 2861 | "execution_count": 128, 2862 | "metadata": { 2863 | "collapsed": false 2864 | }, 2865 | "outputs": [ 2866 | { 2867 | "name": "stdout", 2868 | "output_type": "stream", 2869 | "text": [ 2870 | "0\n", 2871 | "Stream(0, ?)\n", 2872 | "Stream(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)\n", 2873 | "List(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)\n" 2874 | ] 2875 | }, 2876 | { 2877 | "data": { 2878 | "text/plain": [ 2879 | "defined \u001b[32mfunction\u001b[39m \u001b[36minfStream\u001b[39m\n", 2880 | "\u001b[36mstr\u001b[39m: \u001b[32mStream\u001b[39m[\u001b[32mInt\u001b[39m] = \u001b[33mStream\u001b[39m(\n", 2881 | " \u001b[32m0\u001b[39m,\n", 2882 | " \u001b[32m1\u001b[39m,\n", 2883 | " \u001b[32m2\u001b[39m,\n", 2884 | " \u001b[32m3\u001b[39m,\n", 2885 | " \u001b[32m4\u001b[39m,\n", 2886 | " \u001b[32m5\u001b[39m,\n", 2887 | " \u001b[32m6\u001b[39m,\n", 2888 | " \u001b[32m7\u001b[39m,\n", 2889 | " \u001b[32m8\u001b[39m,\n", 2890 | " \u001b[32m9\u001b[39m,\n", 2891 | " \u001b[32m10\u001b[39m,\n", 2892 | "\u001b[33m...\u001b[39m" 2893 | ] 2894 | }, 2895 | "execution_count": 128, 2896 | "metadata": {}, 2897 | "output_type": "execute_result" 2898 | } 2899 | ], 2900 | "source": [ 2901 | "// Scala streams - очень похожи на генераторы в Python\n", 2902 | "def infStream(from:Int): Stream[Int] = {\n", 2903 | " // #:: создаёт stream для первого элемента\n", 2904 | " from #:: infStream(from + 1)\n", 2905 | "}\n", 2906 | "\n", 2907 | "val str = infStream(0)\n", 2908 | "\n", 2909 | "println(str.head) // 0\n", 2910 | "println(str.take(10)) //Stream[0, ]\n", 2911 | "println(str.take(10).force) //Stream[0, ..., 10]\n", 2912 | "println(str.take(10).toList) //List[0, ..., 10]\n" 2913 | ] 2914 | }, 2915 | { 2916 | "cell_type": "markdown", 2917 | "metadata": {}, 2918 | "source": [ 2919 | "## Многопоточность" 2920 | ] 2921 | }, 2922 | { 2923 | "cell_type": "code", 2924 | "execution_count": 129, 2925 | "metadata": { 2926 | "collapsed": false 2927 | }, 2928 | "outputs": [ 2929 | { 2930 | "name": "stdout", 2931 | "output_type": "stream", 2932 | "text": [ 2933 | "ParVector(2, 4, 6)\n" 2934 | ] 2935 | }, 2936 | { 2937 | "data": { 2938 | "text/plain": [ 2939 | "\u001b[36mp\u001b[39m: \u001b[32mcollection\u001b[39m.\u001b[32mparallel\u001b[39m.\u001b[32mimmutable\u001b[39m.\u001b[32mParSeq\u001b[39m[\u001b[32mInt\u001b[39m] = ParVector(1, 2, 3)" 2940 | ] 2941 | }, 2942 | "execution_count": 129, 2943 | "metadata": {}, 2944 | "output_type": "execute_result" 2945 | } 2946 | ], 2947 | "source": [ 2948 | "// ParVector запускает множество операций параллельно\n", 2949 | "val p = List(1,2,3).par\n", 2950 | "\n", 2951 | "println(p.map(_ * 2))" 2952 | ] 2953 | }, 2954 | { 2955 | "cell_type": "code", 2956 | "execution_count": null, 2957 | "metadata": { 2958 | "collapsed": true 2959 | }, 2960 | "outputs": [], 2961 | "source": [] 2962 | } 2963 | ], 2964 | "metadata": { 2965 | "kernelspec": { 2966 | "display_name": "Scala", 2967 | "language": "scala", 2968 | "name": "scala" 2969 | }, 2970 | "language_info": { 2971 | "codemirror_mode": "text/x-scala", 2972 | "file_extension": ".scala", 2973 | "mimetype": "text/x-scala", 2974 | "name": "scala211", 2975 | "nbconvert_exporter": "script", 2976 | "pygments_lexer": "scala", 2977 | "version": "2.11.11" 2978 | } 2979 | }, 2980 | "nbformat": 4, 2981 | "nbformat_minor": 2 2982 | } 2983 | -------------------------------------------------------------------------------- /day2/monads.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Функторы и монады \n", 8 | "
\n", 9 | "![](http://imgs.xkcd.com/comics/hypotheticals.png)\n", 10 | "
" 11 | ] 12 | }, 13 | { 14 | "cell_type": "markdown", 15 | "metadata": {}, 16 | "source": [ 17 | "### Функторы и с чем их едят" 18 | ] 19 | }, 20 | { 21 | "cell_type": "markdown", 22 | "metadata": {}, 23 | "source": [ 24 | "## Что такое ковариантный функтор\n", 25 | "\n", 26 | ">С точки зрения «синтаксического подхода», ковариантным функтором является всякий тип (назовем его X) имеющий type parameter (назовем его T) с методом, который имеет следующую сигнатуру (назовем его map)\n", 27 | "\n", 28 | "```\n", 29 | "trait X[T] {\n", 30 | " def map(f: T => R): X[R]\n", 31 | "}\n", 32 | "```\n", 33 | "
\n", 34 | "«Синтаксический подход» хорош тем, что он позволяет свести в общую схему многие категориальные конструкции\n", 35 | "
\n", 36 | "```\n", 37 | "trait X[T] {\n", 38 | " // ковариант\n", 39 | " def map[R](f: T => R): X[R]\n", 40 | "\n", 41 | " // контрвариант\n", 42 | " def contramap[R](f: R => T): X[R]\n", 43 | "\n", 44 | " // инвариант\n", 45 | " def xmap[R](f: (T => R, R => T)): X[R]\n", 46 | "\n", 47 | " // апликативный функтор\n", 48 | " def apply[R](f: X[T => R]): X[R]\n", 49 | "\n", 50 | " // монада\n", 51 | " def flatMap[R](f: T => X[R]): X[R]\n", 52 | "\n", 53 | " // комонада\n", 54 | " def coflatMap[R](f: X[T] => R): X[R]\n", 55 | "}\n", 56 | "```" 57 | ] 58 | }, 59 | { 60 | "cell_type": "markdown", 61 | "metadata": {}, 62 | "source": [ 63 | "\n", 64 | "| функтор | аргументы |\n", 65 | "|---|---|\n", 66 | "|ковариант| A => B |\n", 67 | "|контрвариант| B => A |\n", 68 | "|exponential| (A => B, B => A) |\n", 69 | "|апликативный| F[A => B] |\n", 70 | "|монада| A => F[B] |\n", 71 | "|комонада| F[A] => B |" 72 | ] 73 | }, 74 | { 75 | "cell_type": "markdown", 76 | "metadata": {}, 77 | "source": [ 78 | "Функтор - это контейнер. Он может хранить либо ничего, либо само значение\n", 79 | "

\n", 80 | "![](https://hsto.org/storage2/be0/182/2de/be01822de6f660845c952b2b4fa7edb6.png)\n", 81 | "
" 82 | ] 83 | }, 84 | { 85 | "cell_type": "markdown", 86 | "metadata": {}, 87 | "source": [ 88 | "Примеры ковариантных функторов из стандартной библиотеки scala" 89 | ] 90 | }, 91 | { 92 | "cell_type": "markdown", 93 | "metadata": {}, 94 | "source": [ 95 | "## Option" 96 | ] 97 | }, 98 | { 99 | "cell_type": "code", 100 | "execution_count": 1, 101 | "metadata": { 102 | "collapsed": false 103 | }, 104 | "outputs": [ 105 | { 106 | "data": { 107 | "text/plain": [ 108 | "\u001b[36mres0\u001b[39m: \u001b[32mOption\u001b[39m.type = scala.Option$@61a71e63" 109 | ] 110 | }, 111 | "execution_count": 1, 112 | "metadata": {}, 113 | "output_type": "execute_result" 114 | } 115 | ], 116 | "source": [ 117 | "// Наш первый пациент\n", 118 | "Option" 119 | ] 120 | }, 121 | { 122 | "cell_type": "markdown", 123 | "metadata": {}, 124 | "source": [ 125 | "Одна из первых монад, которую знают многие программисты - это Option. Так же известная как Maybe монада в Haskell и Optional в Java 8. Вы можете думать об этой монаде, как о коллекции, которая состоит из одного элемента. Но при этом она может либо содержать его, либо не содержать. Таким образом вы можете оборачивать результат в эту монаду. Даже тот результат, который может зафейлиться. Если результат не зафейлится, он вернёт значение и это значение вернётся обёрнутой в монаду. В противном случае там будет лежать None. Мы можем изменять монаду Option с помощью функции map." 126 | ] 127 | }, 128 | { 129 | "cell_type": "code", 130 | "execution_count": 2, 131 | "metadata": { 132 | "collapsed": false 133 | }, 134 | "outputs": [ 135 | { 136 | "data": { 137 | "text/plain": [ 138 | "\u001b[36mthree\u001b[39m: \u001b[32mOption\u001b[39m[\u001b[32mInt\u001b[39m] = \u001b[33mSome\u001b[39m(\u001b[32m3\u001b[39m)" 139 | ] 140 | }, 141 | "execution_count": 2, 142 | "metadata": {}, 143 | "output_type": "execute_result" 144 | } 145 | ], 146 | "source": [ 147 | "val three = Option(3)" 148 | ] 149 | }, 150 | { 151 | "cell_type": "code", 152 | "execution_count": 3, 153 | "metadata": { 154 | "collapsed": false 155 | }, 156 | "outputs": [ 157 | { 158 | "data": { 159 | "text/plain": [ 160 | "\u001b[36mtwelve\u001b[39m: \u001b[32mOption\u001b[39m[\u001b[32mInt\u001b[39m] = \u001b[33mSome\u001b[39m(\u001b[32m12\u001b[39m)" 161 | ] 162 | }, 163 | "execution_count": 3, 164 | "metadata": {}, 165 | "output_type": "execute_result" 166 | } 167 | ], 168 | "source": [ 169 | "val twelve = three map (_ * 4)" 170 | ] 171 | }, 172 | { 173 | "cell_type": "markdown", 174 | "metadata": {}, 175 | "source": [ 176 | "Но когда мы захотим положить несколько значений в эту монаду, у нас получится Option в Option\n", 177 | "\n", 178 | "```\n", 179 | "Option[Option[Int]]\n", 180 | "```" 181 | ] 182 | }, 183 | { 184 | "cell_type": "code", 185 | "execution_count": 4, 186 | "metadata": { 187 | "collapsed": false 188 | }, 189 | "outputs": [ 190 | { 191 | "data": { 192 | "text/plain": [ 193 | "\u001b[36mfour\u001b[39m: \u001b[32mOption\u001b[39m[\u001b[32mInt\u001b[39m] = \u001b[33mSome\u001b[39m(\u001b[32m4\u001b[39m)" 194 | ] 195 | }, 196 | "execution_count": 4, 197 | "metadata": {}, 198 | "output_type": "execute_result" 199 | } 200 | ], 201 | "source": [ 202 | "val four = Option(4)" 203 | ] 204 | }, 205 | { 206 | "cell_type": "code", 207 | "execution_count": 5, 208 | "metadata": { 209 | "collapsed": false 210 | }, 211 | "outputs": [ 212 | { 213 | "data": { 214 | "text/plain": [ 215 | "\u001b[36mtwelveB\u001b[39m: \u001b[32mOption\u001b[39m[\u001b[32mOption\u001b[39m[\u001b[32mInt\u001b[39m]] = \u001b[33mSome\u001b[39m(\u001b[33mSome\u001b[39m(\u001b[32m12\u001b[39m))" 216 | ] 217 | }, 218 | "execution_count": 5, 219 | "metadata": {}, 220 | "output_type": "execute_result" 221 | } 222 | ], 223 | "source": [ 224 | "val twelveB = three map (i => four map (i * _))" 225 | ] 226 | }, 227 | { 228 | "cell_type": "markdown", 229 | "metadata": {}, 230 | "source": [ 231 | "^ тут мы получили Option в Option, так сказать, монада на монаде. Конечно, это не то, что мы хотим, поэтому давайте попробуем использовать flatMap" 232 | ] 233 | }, 234 | { 235 | "cell_type": "markdown", 236 | "metadata": {}, 237 | "source": [ 238 | "![](https://hsto.org/storage2/983/73b/546/98373b54695813ce070a7fc782ca8a35.png)" 239 | ] 240 | }, 241 | { 242 | "cell_type": "code", 243 | "execution_count": 6, 244 | "metadata": { 245 | "collapsed": false 246 | }, 247 | "outputs": [ 248 | { 249 | "data": { 250 | "text/plain": [ 251 | "\u001b[36mtwelveC\u001b[39m: \u001b[32mOption\u001b[39m[\u001b[32mInt\u001b[39m] = \u001b[33mSome\u001b[39m(\u001b[32m12\u001b[39m)" 252 | ] 253 | }, 254 | "execution_count": 6, 255 | "metadata": {}, 256 | "output_type": "execute_result" 257 | } 258 | ], 259 | "source": [ 260 | "val twelveC = three flatMap (i => four map (i * _))" 261 | ] 262 | }, 263 | { 264 | "cell_type": "markdown", 265 | "metadata": {}, 266 | "source": [ 267 | "flatMap — парень с улицы, flatMap знает толк в контекстах. Уж он-то в курсе, как применить функцию к упакованному в контекст значению." 268 | ] 269 | }, 270 | { 271 | "cell_type": "code", 272 | "execution_count": 7, 273 | "metadata": { 274 | "collapsed": false 275 | }, 276 | "outputs": [ 277 | { 278 | "data": { 279 | "text/plain": [ 280 | "\u001b[36mtwelveD\u001b[39m: \u001b[32mOption\u001b[39m[\u001b[32mInt\u001b[39m] = \u001b[33mSome\u001b[39m(\u001b[32m12\u001b[39m)" 281 | ] 282 | }, 283 | "execution_count": 7, 284 | "metadata": {}, 285 | "output_type": "execute_result" 286 | } 287 | ], 288 | "source": [ 289 | "val twelveD = for {\n", 290 | " i <- three\n", 291 | " j <- four\n", 292 | "} yield (i * j)" 293 | ] 294 | }, 295 | { 296 | "cell_type": "markdown", 297 | "metadata": {}, 298 | "source": [ 299 | "Не забудем о том, что монада заботится о том, что наше значение может быть и пустым" 300 | ] 301 | }, 302 | { 303 | "cell_type": "code", 304 | "execution_count": 8, 305 | "metadata": { 306 | "collapsed": false 307 | }, 308 | "outputs": [ 309 | { 310 | "data": { 311 | "text/plain": [ 312 | "\u001b[36moops\u001b[39m: \u001b[32mOption\u001b[39m[\u001b[32mInt\u001b[39m] = None" 313 | ] 314 | }, 315 | "execution_count": 8, 316 | "metadata": {}, 317 | "output_type": "execute_result" 318 | } 319 | ], 320 | "source": [ 321 | "val oops: Option[Int] = None" 322 | ] 323 | }, 324 | { 325 | "cell_type": "markdown", 326 | "metadata": {}, 327 | "source": [ 328 | "![](https://hsto.org/storage2/788/3ad/937/7883ad93713ea4406c129d54f83659d8.png)" 329 | ] 330 | }, 331 | { 332 | "cell_type": "code", 333 | "execution_count": 9, 334 | "metadata": { 335 | "collapsed": false 336 | }, 337 | "outputs": [ 338 | { 339 | "data": { 340 | "text/plain": [ 341 | "\u001b[36moopsB\u001b[39m: \u001b[32mOption\u001b[39m[\u001b[32mInt\u001b[39m] = None" 342 | ] 343 | }, 344 | "execution_count": 9, 345 | "metadata": {}, 346 | "output_type": "execute_result" 347 | } 348 | ], 349 | "source": [ 350 | "val oopsB = for {\n", 351 | " i <- three\n", 352 | " j <- oops\n", 353 | "} yield (i * j)" 354 | ] 355 | }, 356 | { 357 | "cell_type": "code", 358 | "execution_count": 10, 359 | "metadata": { 360 | "collapsed": false 361 | }, 362 | "outputs": [ 363 | { 364 | "data": { 365 | "text/plain": [ 366 | "\u001b[36moopsC\u001b[39m: \u001b[32mOption\u001b[39m[\u001b[32mInt\u001b[39m] = None" 367 | ] 368 | }, 369 | "execution_count": 10, 370 | "metadata": {}, 371 | "output_type": "execute_result" 372 | } 373 | ], 374 | "source": [ 375 | "val oopsC = for {\n", 376 | " i <- oops\n", 377 | " j <- four\n", 378 | "} yield (i * j)" 379 | ] 380 | }, 381 | { 382 | "cell_type": "markdown", 383 | "metadata": {}, 384 | "source": [ 385 | "![](https://hsto.org/storage2/238/88c/8ed/23888c8ed4ae153e5c4d62321fec63c1.png)\n", 386 | "

Билл О'Рейли ничегошеньки не смыслит в функторе Maybe

" 387 | ] 388 | }, 389 | { 390 | "cell_type": "markdown", 391 | "metadata": {}, 392 | "source": [ 393 | "H1: Option — «как бы контейнер» на один элемент, где может что-то лежит (Some), а может и нет (None)" 394 | ] 395 | }, 396 | { 397 | "cell_type": "markdown", 398 | "metadata": {}, 399 | "source": [ 400 | "## List" 401 | ] 402 | }, 403 | { 404 | "cell_type": "code", 405 | "execution_count": 11, 406 | "metadata": { 407 | "collapsed": false 408 | }, 409 | "outputs": [ 410 | { 411 | "data": { 412 | "text/plain": [ 413 | "\u001b[36mres10\u001b[39m: \u001b[32mList\u001b[39m.type = scala.collection.immutable.List$@5e63475" 414 | ] 415 | }, 416 | "execution_count": 11, 417 | "metadata": {}, 418 | "output_type": "execute_result" 419 | } 420 | ], 421 | "source": [ 422 | "// Наш второй пациент\n", 423 | "List" 424 | ] 425 | }, 426 | { 427 | "cell_type": "markdown", 428 | "metadata": {}, 429 | "source": [ 430 | "А вот ещё один пример: что происходит, когда вы применяете функцию к списку?" 431 | ] 432 | }, 433 | { 434 | "cell_type": "markdown", 435 | "metadata": {}, 436 | "source": [ 437 | "![](https://hsto.org/storage2/5ba/e29/3d1/5bae293d123881aa5920d3e7e9e1d039.png)" 438 | ] 439 | }, 440 | { 441 | "cell_type": "markdown", 442 | "metadata": {}, 443 | "source": [ 444 | "Списки тоже функторы!\n", 445 | "\n", 446 | "H2: List — контейнер, в котором может быть 0...N элементов" 447 | ] 448 | }, 449 | { 450 | "cell_type": "markdown", 451 | "metadata": {}, 452 | "source": [ 453 | "## Future" 454 | ] 455 | }, 456 | { 457 | "cell_type": "code", 458 | "execution_count": 12, 459 | "metadata": { 460 | "collapsed": false 461 | }, 462 | "outputs": [ 463 | { 464 | "data": { 465 | "text/plain": [ 466 | "\u001b[32mimport \u001b[39m\u001b[36mscala.concurrent.duration._\n", 467 | "\u001b[39m\n", 468 | "\u001b[32mimport \u001b[39m\u001b[36mscala.concurrent.{Future,ExecutionContext,Await}\n", 469 | "\u001b[39m\n", 470 | "\u001b[32mimport \u001b[39m\u001b[36mExecutionContext.Implicits.global\u001b[39m" 471 | ] 472 | }, 473 | "execution_count": 12, 474 | "metadata": {}, 475 | "output_type": "execute_result" 476 | } 477 | ], 478 | "source": [ 479 | "import scala.concurrent.duration._\n", 480 | "import scala.concurrent.{Future,ExecutionContext,Await}\n", 481 | "import ExecutionContext.Implicits.global" 482 | ] 483 | }, 484 | { 485 | "cell_type": "code", 486 | "execution_count": 13, 487 | "metadata": { 488 | "collapsed": false 489 | }, 490 | "outputs": [ 491 | { 492 | "data": { 493 | "text/plain": [ 494 | "\u001b[36mres12\u001b[39m: \u001b[32mFuture\u001b[39m.type = scala.concurrent.Future$@ad4eb67" 495 | ] 496 | }, 497 | "execution_count": 13, 498 | "metadata": {}, 499 | "output_type": "execute_result" 500 | } 501 | ], 502 | "source": [ 503 | "// Третий на подходе\n", 504 | "Future" 505 | ] 506 | }, 507 | { 508 | "cell_type": "markdown", 509 | "metadata": {}, 510 | "source": [ 511 | "Существует монада для параллельного вычесления и асинхронности. Future монада существует для обёртки медленных вычислений, для того чтобы засунуть их в другой поток. Если вы зовёте Future монаду - она возращается тут же, позволяя вызывать поток, пока дополнительные потоки делают вычисления. Т.е. когда мы вызываем Future - она ещё не содержит значение, но через какое-то время оно (возможно) там появится." 512 | ] 513 | }, 514 | { 515 | "cell_type": "markdown", 516 | "metadata": {}, 517 | "source": [ 518 | "Создадим 2 монады Future, каждая из которых будет спать 10 секунд. В главном потоке просуммируем f1 И f2. " 519 | ] 520 | }, 521 | { 522 | "cell_type": "code", 523 | "execution_count": 14, 524 | "metadata": { 525 | "collapsed": false 526 | }, 527 | "outputs": [ 528 | { 529 | "data": { 530 | "text/plain": [ 531 | "\u001b[36mf1\u001b[39m: \u001b[32mFuture\u001b[39m[\u001b[32mInt\u001b[39m] = Future()" 532 | ] 533 | }, 534 | "execution_count": 14, 535 | "metadata": {}, 536 | "output_type": "execute_result" 537 | } 538 | ], 539 | "source": [ 540 | "val f1=Future{\n", 541 | " Thread.sleep(10000)\n", 542 | " 1 }" 543 | ] 544 | }, 545 | { 546 | "cell_type": "code", 547 | "execution_count": 15, 548 | "metadata": { 549 | "collapsed": false 550 | }, 551 | "outputs": [ 552 | { 553 | "data": { 554 | "text/plain": [ 555 | "\u001b[36mf2\u001b[39m: \u001b[32mFuture\u001b[39m[\u001b[32mInt\u001b[39m] = Future()" 556 | ] 557 | }, 558 | "execution_count": 15, 559 | "metadata": {}, 560 | "output_type": "execute_result" 561 | } 562 | ], 563 | "source": [ 564 | "val f2=Future{\n", 565 | " Thread.sleep(10000)\n", 566 | " 2 }" 567 | ] 568 | }, 569 | { 570 | "cell_type": "markdown", 571 | "metadata": {}, 572 | "source": [ 573 | "Заметим, что f1 и f2 выполняться вместе за 10 секунд в разных потоках." 574 | ] 575 | }, 576 | { 577 | "cell_type": "code", 578 | "execution_count": 16, 579 | "metadata": { 580 | "collapsed": false 581 | }, 582 | "outputs": [ 583 | { 584 | "data": { 585 | "text/plain": [ 586 | "\u001b[36mf3\u001b[39m: \u001b[32mFuture\u001b[39m[\u001b[32mInt\u001b[39m] = Future()" 587 | ] 588 | }, 589 | "execution_count": 16, 590 | "metadata": {}, 591 | "output_type": "execute_result" 592 | } 593 | ], 594 | "source": [ 595 | "val f3=for {\n", 596 | " v1 <- f1\n", 597 | " v2 <- f2\n", 598 | " } yield (v1+v2)" 599 | ] 600 | }, 601 | { 602 | "cell_type": "code", 603 | "execution_count": 17, 604 | "metadata": { 605 | "collapsed": false 606 | }, 607 | "outputs": [ 608 | { 609 | "name": "stdout", 610 | "output_type": "stream", 611 | "text": [ 612 | "3\n" 613 | ] 614 | } 615 | ], 616 | "source": [ 617 | "println(Await.result(f3, 30.seconds))" 618 | ] 619 | }, 620 | { 621 | "cell_type": "markdown", 622 | "metadata": {}, 623 | "source": [ 624 | "H3: Future — «как бы контейнер» на один элемент, где может что-то уже лежит, может будет лежать, или уже лежит исключение, или будет лежать исключение или никогда ничего лежать не будет." 625 | ] 626 | }, 627 | { 628 | "cell_type": "markdown", 629 | "metadata": {}, 630 | "source": [ 631 | "## Try" 632 | ] 633 | }, 634 | { 635 | "cell_type": "code", 636 | "execution_count": 20, 637 | "metadata": { 638 | "collapsed": true 639 | }, 640 | "outputs": [ 641 | { 642 | "data": { 643 | "text/plain": [ 644 | "\u001b[32mimport \u001b[39m\u001b[36mscala.util.Try\u001b[39m" 645 | ] 646 | }, 647 | "execution_count": 20, 648 | "metadata": {}, 649 | "output_type": "execute_result" 650 | } 651 | ], 652 | "source": [ 653 | "import scala.util.Try" 654 | ] 655 | }, 656 | { 657 | "cell_type": "code", 658 | "execution_count": 22, 659 | "metadata": { 660 | "collapsed": false 661 | }, 662 | "outputs": [ 663 | { 664 | "data": { 665 | "text/plain": [ 666 | "\u001b[36mres21\u001b[39m: \u001b[32mTry\u001b[39m.type = scala.util.Try$@120f1e89" 667 | ] 668 | }, 669 | "execution_count": 22, 670 | "metadata": {}, 671 | "output_type": "execute_result" 672 | } 673 | ], 674 | "source": [ 675 | "// Ох, сколько больных развелось\n", 676 | "Try" 677 | ] 678 | }, 679 | { 680 | "cell_type": "markdown", 681 | "metadata": {}, 682 | "source": [ 683 | "Try монада существует для того, чтобы не оборачивать ошибки с помощью Either. Об Either поговорим чуть попозже, потому что это BiFunctor. Основная идея в том, что у вас лежит либо элемент, либо ошибка." 684 | ] 685 | }, 686 | { 687 | "cell_type": "code", 688 | "execution_count": 27, 689 | "metadata": { 690 | "collapsed": false 691 | }, 692 | "outputs": [ 693 | { 694 | "data": { 695 | "text/plain": [ 696 | "defined \u001b[32mfunction\u001b[39m \u001b[36mf\u001b[39m" 697 | ] 698 | }, 699 | "execution_count": 27, 700 | "metadata": {}, 701 | "output_type": "execute_result" 702 | } 703 | ], 704 | "source": [ 705 | "// Создадим функцию, которая будет возвращать монаду\n", 706 | "def f(x: Int, y: Int): Try[Int] = Try(x / y)" 707 | ] 708 | }, 709 | { 710 | "cell_type": "code", 711 | "execution_count": 28, 712 | "metadata": { 713 | "collapsed": false 714 | }, 715 | "outputs": [ 716 | { 717 | "data": { 718 | "text/plain": [ 719 | "\u001b[36mres27\u001b[39m: \u001b[32mTry\u001b[39m[\u001b[32mInt\u001b[39m] = \u001b[33mSuccess\u001b[39m(\u001b[32m1\u001b[39m)" 720 | ] 721 | }, 722 | "execution_count": 28, 723 | "metadata": {}, 724 | "output_type": "execute_result" 725 | } 726 | ], 727 | "source": [ 728 | "f(1, 1)" 729 | ] 730 | }, 731 | { 732 | "cell_type": "code", 733 | "execution_count": 29, 734 | "metadata": { 735 | "collapsed": false 736 | }, 737 | "outputs": [ 738 | { 739 | "data": { 740 | "text/plain": [ 741 | "\u001b[36mres28\u001b[39m: \u001b[32mTry\u001b[39m[\u001b[32mInt\u001b[39m] = \u001b[33mFailure\u001b[39m(java.lang.ArithmeticException: / by zero)" 742 | ] 743 | }, 744 | "execution_count": 29, 745 | "metadata": {}, 746 | "output_type": "execute_result" 747 | } 748 | ], 749 | "source": [ 750 | "f(1, 0)" 751 | ] 752 | }, 753 | { 754 | "cell_type": "markdown", 755 | "metadata": {}, 756 | "source": [ 757 | "Монада, как и было сказанно выше принимает 2 значения. Либо ```Success``` либо ```Failure```" 758 | ] 759 | }, 760 | { 761 | "cell_type": "code", 762 | "execution_count": 32, 763 | "metadata": { 764 | "collapsed": false 765 | }, 766 | "outputs": [ 767 | { 768 | "data": { 769 | "text/plain": [ 770 | "\u001b[36mres31\u001b[39m: \u001b[32mBoolean\u001b[39m = \u001b[32mtrue\u001b[39m" 771 | ] 772 | }, 773 | "execution_count": 32, 774 | "metadata": {}, 775 | "output_type": "execute_result" 776 | } 777 | ], 778 | "source": [ 779 | "// Узнаем, всё ли хорошо\n", 780 | "f(1, 1).isSuccess" 781 | ] 782 | }, 783 | { 784 | "cell_type": "markdown", 785 | "metadata": {}, 786 | "source": [ 787 | "Ковариантный функтор — это не просто наличие метода с определенной сигнатурой, это также выполнение двух правил. Математики тут обычно отсылают к теории категорий, и говорят, что эти правила — следствие того, что функтор — это [гомоморфизм категорий](https://ru.wikipedia.org/wiki/%D0%A4%D1%83%D0%BD%D0%BA%D1%82%D0%BE%D1%80_(%D0%BC%D0%B0%D1%82%D0%B5%D0%BC%D0%B0%D1%82%D0%B8%D0%BA%D0%B0)), то есть отображение категории в категорию, сохраняющее их структуру (а частью структуры категории являются единичный элемент-стрелка (правило Identity Law) и правила композиции стрелок (правило Composition law)). " 788 | ] 789 | }, 790 | { 791 | "cell_type": "markdown", 792 | "metadata": {}, 793 | "source": [ 794 | "## Правила ковариантного функтора" 795 | ] 796 | }, 797 | { 798 | "cell_type": "markdown", 799 | "metadata": {}, 800 | "source": [ 801 | "### Identity Law\n", 802 | "\n", 803 | "Для любого ковариантного функтора 'fun' должно тождественно выполняться следующее правило IdentityLaw.case0(fun) — то же самое что и IdentityLaw.case1(fun)." 804 | ] 805 | }, 806 | { 807 | "cell_type": "markdown", 808 | "metadata": {}, 809 | "source": [ 810 | "### Composition Law\n", 811 | "\n", 812 | "Для любого ковариантного функтора 'fun[T]' и любых функций 'f: ' и 'g' должно тождественно выполняться следующее правило CompositionLaw.case0(fun) — то же самое что и CompositionLaw.case1(fun)." 813 | ] 814 | }, 815 | { 816 | "cell_type": "markdown", 817 | "metadata": {}, 818 | "source": [ 819 | "То есть произвольный функтор-контейнер, который последовательно отображают функцией 'f' и потом функцией 'g' эквивалентен тому, что мы строим новую функцию-композицию функций f и g (f andThen g) и отображаем один раз." 820 | ] 821 | }, 822 | { 823 | "cell_type": "markdown", 824 | "metadata": {}, 825 | "source": [ 826 | "\n", 827 | "## Ковариантный функтор: используем для оптимизации" 828 | ] 829 | }, 830 | { 831 | "cell_type": "markdown", 832 | "metadata": {}, 833 | "source": [ 834 | "Давайте рассмотрим пример, демонстрирующий пользу от аксиом ковариантного функтора.\n", 835 | "\n", 836 | "В качестве отображений рассмотрим линейные функции над целыми числами" 837 | ] 838 | }, 839 | { 840 | "cell_type": "code", 841 | "execution_count": 35, 842 | "metadata": { 843 | "collapsed": false 844 | }, 845 | "outputs": [ 846 | { 847 | "data": { 848 | "text/plain": [ 849 | "defined \u001b[32mclass\u001b[39m \u001b[36mLinFun\u001b[39m" 850 | ] 851 | }, 852 | "execution_count": 35, 853 | "metadata": {}, 854 | "output_type": "execute_result" 855 | } 856 | ], 857 | "source": [ 858 | "case class LinFun(a: Int, b: Int) {\n", 859 | " def apply(k: Int): Int = a * k + b\n", 860 | " def andThen[A](that: LinFun): LinFun = LinFun(this.a * that.a, that.a * this.b + that.b)\n", 861 | "}" 862 | ] 863 | }, 864 | { 865 | "cell_type": "markdown", 866 | "metadata": {}, 867 | "source": [ 868 | "Вместо самых общих функций вида T=>R я буду использовать их подмножество — линейные функции над Int, так как в отличии от общего вида я умею строить композиции линейных функций в явном виде.\n", 869 | "\n", 870 | "В качестве функтора рассмотрю рекурсивный контейнер типа односвязный список целых чисел (Int)" 871 | ] 872 | }, 873 | { 874 | "cell_type": "code", 875 | "execution_count": 39, 876 | "metadata": { 877 | "collapsed": false 878 | }, 879 | "outputs": [ 880 | { 881 | "data": { 882 | "text/plain": [ 883 | "\u001b[36mres38\u001b[39m: \u001b[32mInt\u001b[39m = \u001b[32m13\u001b[39m" 884 | ] 885 | }, 886 | "execution_count": 39, 887 | "metadata": {}, 888 | "output_type": "execute_result" 889 | } 890 | ], 891 | "source": [ 892 | "LinFun(1, 3).apply(10)" 893 | ] 894 | }, 895 | { 896 | "cell_type": "code", 897 | "execution_count": 40, 898 | "metadata": { 899 | "collapsed": true 900 | }, 901 | "outputs": [ 902 | { 903 | "data": { 904 | "text/plain": [ 905 | "defined \u001b[32mtrait\u001b[39m \u001b[36mIntSeq\u001b[39m\n", 906 | "defined \u001b[32mclass\u001b[39m \u001b[36mNode\u001b[39m\n", 907 | "defined \u001b[32mobject\u001b[39m \u001b[36mLast\u001b[39m" 908 | ] 909 | }, 910 | "execution_count": 40, 911 | "metadata": {}, 912 | "output_type": "execute_result" 913 | } 914 | ], 915 | "source": [ 916 | "sealed trait IntSeq {\n", 917 | " def map(f: LinFun): IntSeq\n", 918 | "}\n", 919 | "case class Node(value: Int, tail: IntSeq) extends IntSeq {\n", 920 | " override def map(f: LinFun): IntSeq = Node(f(value), tail.map(f))\n", 921 | "}\n", 922 | "case object Last extends IntSeq {\n", 923 | " override def map(f: LinFun): IntSeq = Last\n", 924 | "}" 925 | ] 926 | }, 927 | { 928 | "cell_type": "markdown", 929 | "metadata": {}, 930 | "source": [ 931 | "А теперь — демонстрация" 932 | ] 933 | }, 934 | { 935 | "cell_type": "code", 936 | "execution_count": 44, 937 | "metadata": { 938 | "collapsed": true 939 | }, 940 | "outputs": [ 941 | { 942 | "data": { 943 | "text/plain": [ 944 | "\u001b[36mseq\u001b[39m: \u001b[32mNode\u001b[39m = Node(0,Node(1,Node(2,Node(3,Last))))\n", 945 | "\u001b[36mf\u001b[39m: \u001b[32mLinFun\u001b[39m = \u001b[33mLinFun\u001b[39m(\u001b[32m2\u001b[39m, \u001b[32m3\u001b[39m)\n", 946 | "\u001b[36mg\u001b[39m: \u001b[32mLinFun\u001b[39m = \u001b[33mLinFun\u001b[39m(\u001b[32m4\u001b[39m, \u001b[32m5\u001b[39m)" 947 | ] 948 | }, 949 | "execution_count": 44, 950 | "metadata": {}, 951 | "output_type": "execute_result" 952 | } 953 | ], 954 | "source": [ 955 | "val seq = Node(0, Node(1, Node(2, Node(3, Last))))\n", 956 | "val f = LinFun(2, 3) // k => 2 * k + 3\n", 957 | "val g = LinFun(4, 5) // k => 4 * k + 5" 958 | ] 959 | }, 960 | { 961 | "cell_type": "code", 962 | "execution_count": 45, 963 | "metadata": { 964 | "collapsed": false 965 | }, 966 | "outputs": [ 967 | { 968 | "data": { 969 | "text/plain": [ 970 | "\u001b[36mres0\u001b[39m: \u001b[32mIntSeq\u001b[39m = Node(17,Node(25,Node(33,Node(41,Last))))" 971 | ] 972 | }, 973 | "execution_count": 45, 974 | "metadata": {}, 975 | "output_type": "execute_result" 976 | } 977 | ], 978 | "source": [ 979 | "val res0 = (seq map f) map g // slow version" 980 | ] 981 | }, 982 | { 983 | "cell_type": "code", 984 | "execution_count": 46, 985 | "metadata": { 986 | "collapsed": false 987 | }, 988 | "outputs": [ 989 | { 990 | "data": { 991 | "text/plain": [ 992 | "\u001b[36mres1\u001b[39m: \u001b[32mIntSeq\u001b[39m = Node(17,Node(25,Node(33,Node(41,Last))))" 993 | ] 994 | }, 995 | "execution_count": 46, 996 | "metadata": {}, 997 | "output_type": "execute_result" 998 | } 999 | ], 1000 | "source": [ 1001 | "val res1 = seq map (f andThen g) // fast version" 1002 | ] 1003 | }, 1004 | { 1005 | "cell_type": "markdown", 1006 | "metadata": {}, 1007 | "source": [ 1008 | "Мы можем либо \n", 1009 | "\n", 1010 | "1. ДВА раза перебрать все элементы списка (ДВА раза пройтись по памяти)\n", 1011 | "2. и ДВА раза выполнить арифметические операции (* и +)\n", 1012 | "\n", 1013 | "либо построить композицию f andThen g и\n", 1014 | "\n", 1015 | "1. ОДИН раз перебирать все элементы списка\n", 1016 | "2. и ОДИН раз выполнить арифметические операции\n" 1017 | ] 1018 | }, 1019 | { 1020 | "cell_type": "markdown", 1021 | "metadata": {}, 1022 | "source": [ 1023 | "# Что такое контравариантный функтор\n", 1024 | "\n", 1025 | "Напомню, что ковариантным функтором называется всякий класс X, который имеет метод с определенной сигнатурой (условно называемый map) и подчиняющийся определенным правилам (Identity Law, Composition Law).\n", 1026 | "\n", 1027 | "```\n", 1028 | "trait X[T] {\n", 1029 | " def map[R](f: T => R): X[R]\n", 1030 | "}\n", 1031 | "```\n" 1032 | ] 1033 | }, 1034 | { 1035 | "cell_type": "markdown", 1036 | "metadata": {}, 1037 | "source": [ 1038 | "В свою очередь контравариантным функтором называется всякий класс X, который имеет метод (условно называемый contramap) с определенной сигнатурой и подчиняющийся определенным правилам (они тоже называются Identity Law, Composition Law)\n", 1039 | "\n", 1040 | "```\n", 1041 | "trait X[T] {\n", 1042 | " def contramap[R](f: R => T): X[R]\n", 1043 | "}\n", 1044 | "```" 1045 | ] 1046 | }, 1047 | { 1048 | "cell_type": "markdown", 1049 | "metadata": {}, 1050 | "source": [ 1051 | "В этом месте недоуменный читатель может остановиться. Постойте, но если у нас есть контейнер, содержащий T и мы получаем функцию f: T => R, то понятно каким образом мы получаем контейнер с R. Передаем функцию контейнеру, тот погружает функцию внутрь себя и не извлекая элемент применяет к нему функцию. Однако совершенно непонятно, как, имея контейнер с T и получив функцию f: R => T, применить ее в «обратном порядке»?!\n", 1052 | "\n", 1053 | "В математике в общем виде не у всякой функции есть обратная и нет общего способа найти обратную даже когда она существует. В программировании же нам необходимо действовать конструктивно (не просто работать с существованием, единственность,… но строить и исполнять конструкции) — надо каким-то образом по функции f: R => T построить функцию g: T => R что бы применить ее к содержимому контейнера!\n", 1054 | "\n", 1055 | "И вот тут оказывается, что наша метафора (ковариантный функтор ~ контейнер) не работает. Давайте разберем почему.\n", 1056 | "\n", 1057 | "Всякий контейнер предполагает две операции\n", 1058 | "put — поместить элемент в контейнер\n", 1059 | "get — извлечь элемент из контейнера\n", 1060 | "\n", 1061 | "однако у рассмотренных примеров (Option, Try, Future, List, Parser) в той или иной мере есть метод get, но нет метода put! В Option/Try/Future элемент попадает в конструкторе (или в методе apply от companion object) или же в результате какого-то действия. В Parser вообще нельзя попасть, так как Parser[T] — «перерабатывает» строки в T. Parser[T] — это источник T, а не хранилище!" 1062 | ] 1063 | }, 1064 | { 1065 | "cell_type": "markdown", 1066 | "metadata": {}, 1067 | "source": [ 1068 | "\n", 1069 | "Ковариантный функтор — это половина контейнера. Та часть, которая отвечает за извлечение данных." 1070 | ] 1071 | }, 1072 | { 1073 | "cell_type": "markdown", 1074 | "metadata": {}, 1075 | "source": [ 1076 | "## Примеры контравариантных функторов\n" 1077 | ] 1078 | }, 1079 | { 1080 | "cell_type": "markdown", 1081 | "metadata": {}, 1082 | "source": [ 1083 | "Для поиска примеров контравариантных функторов в стандартной библиотеке Scala нам надо забыть про метафору контейнера и искать тип с одним type parameter, который только принимает данные в виде аргументов, но не возвращает в виде результата функции." 1084 | ] 1085 | }, 1086 | { 1087 | "cell_type": "code", 1088 | "execution_count": 1, 1089 | "metadata": { 1090 | "collapsed": false 1091 | }, 1092 | "outputs": [ 1093 | { 1094 | "data": { 1095 | "text/plain": [ 1096 | "\u001b[32mimport \u001b[39m\u001b[36mscala.math.Ordering._\u001b[39m" 1097 | ] 1098 | }, 1099 | "execution_count": 1, 1100 | "metadata": {}, 1101 | "output_type": "execute_result" 1102 | } 1103 | ], 1104 | "source": [ 1105 | "import scala.math.Ordering._" 1106 | ] 1107 | }, 1108 | { 1109 | "cell_type": "code", 1110 | "execution_count": 7, 1111 | "metadata": { 1112 | "collapsed": false 1113 | }, 1114 | "outputs": [ 1115 | { 1116 | "data": { 1117 | "text/plain": [ 1118 | "\u001b[32mimport \u001b[39m\u001b[36mscala.math.Equiv\u001b[39m" 1119 | ] 1120 | }, 1121 | "execution_count": 7, 1122 | "metadata": {}, 1123 | "output_type": "execute_result" 1124 | } 1125 | ], 1126 | "source": [ 1127 | "import scala.math.Equiv" 1128 | ] 1129 | }, 1130 | { 1131 | "cell_type": "markdown", 1132 | "metadata": {}, 1133 | "source": [ 1134 | "## Ordering" 1135 | ] 1136 | }, 1137 | { 1138 | "cell_type": "code", 1139 | "execution_count": 2, 1140 | "metadata": { 1141 | "collapsed": false 1142 | }, 1143 | "outputs": [ 1144 | { 1145 | "data": { 1146 | "text/plain": [ 1147 | "\u001b[36mstrX\u001b[39m: \u001b[32mOrdering\u001b[39m[\u001b[32mString\u001b[39m] = scala.math.Ordering$String$@296c9cef" 1148 | ] 1149 | }, 1150 | "execution_count": 2, 1151 | "metadata": {}, 1152 | "output_type": "execute_result" 1153 | } 1154 | ], 1155 | "source": [ 1156 | "val strX: Ordering[String] = String" 1157 | ] 1158 | }, 1159 | { 1160 | "cell_type": "code", 1161 | "execution_count": 3, 1162 | "metadata": { 1163 | "collapsed": false 1164 | }, 1165 | "outputs": [ 1166 | { 1167 | "data": { 1168 | "text/plain": [ 1169 | "\u001b[36mf\u001b[39m: \u001b[32mInt\u001b[39m => \u001b[32mString\u001b[39m = " 1170 | ] 1171 | }, 1172 | "execution_count": 3, 1173 | "metadata": {}, 1174 | "output_type": "execute_result" 1175 | } 1176 | ], 1177 | "source": [ 1178 | "val f: (Int => String) = _.toString" 1179 | ] 1180 | }, 1181 | { 1182 | "cell_type": "code", 1183 | "execution_count": 4, 1184 | "metadata": { 1185 | "collapsed": false 1186 | }, 1187 | "outputs": [ 1188 | { 1189 | "data": { 1190 | "text/plain": [ 1191 | "\u001b[36mintX\u001b[39m: \u001b[32mOrdering\u001b[39m[\u001b[32mInt\u001b[39m] = scala.math.Ordering$$anon$5@32f7355d" 1192 | ] 1193 | }, 1194 | "execution_count": 4, 1195 | "metadata": {}, 1196 | "output_type": "execute_result" 1197 | } 1198 | ], 1199 | "source": [ 1200 | "val intX: Ordering[Int] = strX on f" 1201 | ] 1202 | }, 1203 | { 1204 | "cell_type": "markdown", 1205 | "metadata": {}, 1206 | "source": [ 1207 | "## Equiv" 1208 | ] 1209 | }, 1210 | { 1211 | "cell_type": "code", 1212 | "execution_count": 8, 1213 | "metadata": { 1214 | "collapsed": true 1215 | }, 1216 | "outputs": [ 1217 | { 1218 | "data": { 1219 | "text/plain": [ 1220 | "\u001b[32mimport \u001b[39m\u001b[36mjava.lang.String.CASE_INSENSITIVE_ORDER\n", 1221 | "\u001b[39m\n", 1222 | "\u001b[32mimport \u001b[39m\u001b[36mscala.math.Equiv.{fromFunction, fromComparator}\u001b[39m" 1223 | ] 1224 | }, 1225 | "execution_count": 8, 1226 | "metadata": {}, 1227 | "output_type": "execute_result" 1228 | } 1229 | ], 1230 | "source": [ 1231 | "import java.lang.String.CASE_INSENSITIVE_ORDER\n", 1232 | "import scala.math.Equiv.{fromFunction, fromComparator}" 1233 | ] 1234 | }, 1235 | { 1236 | "cell_type": "code", 1237 | "execution_count": 9, 1238 | "metadata": { 1239 | "collapsed": true 1240 | }, 1241 | "outputs": [ 1242 | { 1243 | "data": { 1244 | "text/plain": [ 1245 | "\u001b[36mstrX\u001b[39m: \u001b[32mEquiv\u001b[39m[\u001b[32mString\u001b[39m] = scala.math.Equiv$$anon$3@25e0feed\n", 1246 | "\u001b[36mf\u001b[39m: \u001b[32mInt\u001b[39m => \u001b[32mString\u001b[39m = \n", 1247 | "\u001b[36mintX\u001b[39m: \u001b[32mEquiv\u001b[39m[\u001b[32mInt\u001b[39m] = scala.math.Equiv$$anon$4@274f015a" 1248 | ] 1249 | }, 1250 | "execution_count": 9, 1251 | "metadata": {}, 1252 | "output_type": "execute_result" 1253 | } 1254 | ], 1255 | "source": [ 1256 | "val strX: Equiv[String] = fromComparator(CASE_INSENSITIVE_ORDER)\n", 1257 | "val f: (Int => String) = _.toString\n", 1258 | "val intX: Equiv[Int] = fromFunction((x, y) => strX.equiv(f(x), f(y)))" 1259 | ] 1260 | }, 1261 | { 1262 | "cell_type": "markdown", 1263 | "metadata": {}, 1264 | "source": [ 1265 | "Как и в случае с ковариантным функтором, контравариантному функтору кроме метода с сигнатурой необходимо следовать двум правилам." 1266 | ] 1267 | }, 1268 | { 1269 | "cell_type": "markdown", 1270 | "metadata": {}, 1271 | "source": [ 1272 | "Первое правило (Identity Law) гласит: для всякого контравариантного функтора fun должно выполняться IdentityLaw.case0(fun) тождественно равно IdentityLaw.case1(fun)" 1273 | ] 1274 | }, 1275 | { 1276 | "cell_type": "markdown", 1277 | "metadata": {}, 1278 | "source": [ 1279 | "```object IdentityLaw {\n", 1280 | " def case0[T](fun: Contravariant[T]): Contravariant[T] = identity(fun) \n", 1281 | " def case1[T](fun: Contravariant[T]): Contravariant[T] = fun.contramap(identity)\n", 1282 | "}```" 1283 | ] 1284 | }, 1285 | { 1286 | "cell_type": "markdown", 1287 | "metadata": {}, 1288 | "source": [ 1289 | "\n", 1290 | "То есть отображение контравариантного функтора единичной функцией не меняет его." 1291 | ] 1292 | }, 1293 | { 1294 | "cell_type": "markdown", 1295 | "metadata": {}, 1296 | "source": [ 1297 | "Второе правило (Composition Law) гласит: для всякого контравариантного функтора fun[T] и произвольной пары функций f: Q => R и g: R => T пары должно быть IdentityLaw.case0(fun) тождественно равно IdentityLaw.case1(fun)" 1298 | ] 1299 | }, 1300 | { 1301 | "cell_type": "markdown", 1302 | "metadata": {}, 1303 | "source": [ 1304 | "```object CompositionLaw {\n", 1305 | " def case0[Q, R, T](fun: Contravariant[T], f: Q => R, g: R => T): Contravariant[Q] =\n", 1306 | " (fun contramap g) contramap f\n", 1307 | " def case1[Q, R, T](fun: Contravariant[T], f: Q => R, g: R => T): Contravariant[Q] =\n", 1308 | " fun contramap (f andThen g)\n", 1309 | "}```" 1310 | ] 1311 | }, 1312 | { 1313 | "cell_type": "markdown", 1314 | "metadata": {}, 1315 | "source": [ 1316 | "То есть отображение контравариантного функтора последовательно парой функций эквивалентно единичному отображению композицией функций (инвертированной).\n" 1317 | ] 1318 | }, 1319 | { 1320 | "cell_type": "markdown", 1321 | "metadata": {}, 1322 | "source": [ 1323 | "\n", 1324 | "Понятия ко- и контра-вариантного функтора являются только стартовой точкой для серьезного изучения применения абстракций из теории категорий в функциональном программировании (в терминах Scala — переход к использованию библиотек Scalaz, Cats). \n", 1325 | "\n", 1326 | "Дальнейшие шаги включают:\n", 1327 | "1. Изучение композиций ко- и контра- вариантных функторов (BiFunctor, ProFunctor, Exponential (Invariant) Functor)\n", 1328 | "2. Изучение более специализированных конструкций (Applicative Functor, Arrow, Monad), которые уже действительно составляют новую парадигму работы с вычислениями, вводом-выводом, обработкой ошибок, мутирующим состоянием. Укажу хотя бы на то, что всякая монада является ковариантным функтором." 1329 | ] 1330 | }, 1331 | { 1332 | "cell_type": "markdown", 1333 | "metadata": {}, 1334 | "source": [ 1335 | "Литература для создания тетрадки\n", 1336 | "\n", 1337 | "1. [Functors and things using Scala](http://blog.tmorris.net/posts/functors-and-things-using-scala/index.html)\n", 1338 | "2. [Функторы, аппликативные функторы и монады в картинках](https://habrahabr.ru/post/183150/)\n", 1339 | "3. [First steps with monads in Scala](https://darrenjw.wordpress.com/2016/04/15/first-steps-with-monads-in-scala/)\n", 1340 | "4. [FP на Scala: Что такое функтор?](https://habrahabr.ru/company/golovachcourses/blog/266905/)\n", 1341 | "5. [Scala's Either, Try and the M word](https://mauricio.github.io/2014/02/17/scala-either-try-and-the-m-word.html)\n", 1342 | "\n", 1343 | "

[Если вы классный](http://homepages.inf.ed.ac.uk/wadler/papers/marktoberdorf/baastad.pdf)

\n", 1344 | "\n", 1345 | "

[Очень-очень классный](https://bartoszmilewski.com/2014/10/28/category-theory-for-programmers-the-preface/)

\n" 1346 | ] 1347 | } 1348 | ], 1349 | "metadata": { 1350 | "kernelspec": { 1351 | "display_name": "Scala", 1352 | "language": "scala", 1353 | "name": "scala" 1354 | }, 1355 | "language_info": { 1356 | "codemirror_mode": "text/x-scala", 1357 | "file_extension": ".scala", 1358 | "mimetype": "text/x-scala", 1359 | "name": "scala211", 1360 | "nbconvert_exporter": "script", 1361 | "pygments_lexer": "scala", 1362 | "version": "2.11.11" 1363 | } 1364 | }, 1365 | "nbformat": 4, 1366 | "nbformat_minor": 2 1367 | } 1368 | -------------------------------------------------------------------------------- /day3/akka.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": { 7 | "collapsed": false, 8 | "scrolled": true 9 | }, 10 | "outputs": [ 11 | { 12 | "data": { 13 | "text/plain": [ 14 | "\u001b[32mimport \u001b[39m\u001b[36m$ivy.$ \u001b[39m" 15 | ] 16 | }, 17 | "execution_count": 1, 18 | "metadata": {}, 19 | "output_type": "execute_result" 20 | } 21 | ], 22 | "source": [ 23 | "// Скачаем Akka\n", 24 | "import $ivy.`com.typesafe.akka:akka-actor_2.11:2.5.3`" 25 | ] 26 | }, 27 | { 28 | "cell_type": "markdown", 29 | "metadata": {}, 30 | "source": [ 31 | "# Akka и с чем его едят\n", 32 | "\n", 33 | "В акторной модели – которая была изобретена в 1973 году Карлом Хьюиттом и др. — акторы представляют собой «фундаментальные единицы вычислений, реализующие обработку, хранение и коммуникацию». " 34 | ] 35 | }, 36 | { 37 | "cell_type": "markdown", 38 | "metadata": {}, 39 | "source": [ 40 | "![](http://vignette2.wikia.nocookie.net/wikies/images/7/73/%D0%9C%D0%B8%D0%BD%D1%8C%D0%BE%D0%BD%D1%8B%D0%A4%D0%BE%D0%BD.jpg/revision/latest?cb=20150703140704&path-prefix=ru)" 41 | ] 42 | }, 43 | { 44 | "cell_type": "markdown", 45 | "metadata": {}, 46 | "source": [ 47 | "Если не вдаваться в подробности, то разработка на акторах исходит из философии, что все круг акторы. Так же как и ООП исходит из философии, что все круг объекты. Принципиальные отличия же состоят в том, что акторы выполняются параллельно. В то время как ООП код выполняется последовательно и для параллельного исполнения надо делать дополнительные и далеко не всегда простые действия. А так же акторы взаимодействуют между собой не через вызовы методов у объектов, как в ООП, а через отправку сообщений. В акторе есть очередь этих сообщений (mailbox). Сообщения обрабатываются строго по очереди." 48 | ] 49 | }, 50 | { 51 | "cell_type": "markdown", 52 | "metadata": { 53 | "collapsed": true 54 | }, 55 | "source": [ 56 | "Кроме того, необходимо отметить, что отправка сообщения актору и обработка этого сообщения актором — это две отдельных операции, которые, скорее всего, происходят в разных потоках. Разумеется, Akka обеспечивает необходимую синхронизацию, чтобы гарантировать, что любые изменения состояния будут видимы всем потокам. \n" 57 | ] 58 | }, 59 | { 60 | "cell_type": "code", 61 | "execution_count": 8, 62 | "metadata": { 63 | "collapsed": false 64 | }, 65 | "outputs": [ 66 | { 67 | "data": { 68 | "text/plain": [ 69 | "\u001b[32mimport \u001b[39m\u001b[36makka.actor._\u001b[39m" 70 | ] 71 | }, 72 | "execution_count": 8, 73 | "metadata": {}, 74 | "output_type": "execute_result" 75 | } 76 | ], 77 | "source": [ 78 | "import akka.actor._" 79 | ] 80 | }, 81 | { 82 | "cell_type": "code", 83 | "execution_count": 3, 84 | "metadata": { 85 | "collapsed": false 86 | }, 87 | "outputs": [ 88 | { 89 | "data": { 90 | "text/plain": [ 91 | "defined \u001b[32mclass\u001b[39m \u001b[36mPubSubMediator\u001b[39m" 92 | ] 93 | }, 94 | "execution_count": 3, 95 | "metadata": {}, 96 | "output_type": "execute_result" 97 | } 98 | ], 99 | "source": [ 100 | "class PubSubMediator extends Actor {\n", 101 | " override def receive = Actor.emptyBehavior\n", 102 | "}" 103 | ] 104 | }, 105 | { 106 | "cell_type": "markdown", 107 | "metadata": {}, 108 | "source": [ 109 | "Метод receive возвращает так называемое исходное поведение актора. Это просто частично вычислимая функция, используемая Akka для обработки сообщений, отправляемых актору." 110 | ] 111 | }, 112 | { 113 | "cell_type": "markdown", 114 | "metadata": {}, 115 | "source": [ 116 | "При создании акторной системы, Akka — на внутреннем уровне использующая множество так называемых «системных акторов» — создает три актора: это «корневой страж» (root guardian), расположенный в корне акторной иерархии, а также системный и пользовательский стражи. Пользовательский страж — зачастую именуемый просто «страж» — является родительским элементом для всех создаваемых нами акторов верхнего уровня (в данном контексте имеется в виду «наивысший уровень, к которому мы имеем доступ»).\n" 117 | ] 118 | }, 119 | { 120 | "cell_type": "code", 121 | "execution_count": 4, 122 | "metadata": { 123 | "collapsed": false 124 | }, 125 | "outputs": [ 126 | { 127 | "data": { 128 | "text/plain": [ 129 | "\u001b[36msystem\u001b[39m: \u001b[32mActorSystem\u001b[39m = akka://pub-sub-mediator-spec-system" 130 | ] 131 | }, 132 | "execution_count": 4, 133 | "metadata": {}, 134 | "output_type": "execute_result" 135 | } 136 | ], 137 | "source": [ 138 | "// Создадим систему акторов\n", 139 | "val system = ActorSystem(\"pub-sub-mediator-spec-system\")" 140 | ] 141 | }, 142 | { 143 | "cell_type": "markdown", 144 | "metadata": {}, 145 | "source": [ 146 | "А зачем мы вообще создаем ActorSystem? Почему бы просто не создавать акторы? Последнее невозможно, поскольку при непосредственном вызове конструктора актора система выбросит исключение. Вместо этого нам придется использовать фабричный метод, предоставляемый — вы угадали — ActorSystem для создания актора верхнего уровня:" 147 | ] 148 | }, 149 | { 150 | "cell_type": "code", 151 | "execution_count": 5, 152 | "metadata": { 153 | "collapsed": false 154 | }, 155 | "outputs": [ 156 | { 157 | "data": { 158 | "text/plain": [ 159 | "\u001b[36mres4\u001b[39m: \u001b[32mActorRef\u001b[39m = Actor[akka://pub-sub-mediator-spec-system/user/pub-sub-mediator#-8146321]" 160 | ] 161 | }, 162 | "execution_count": 5, 163 | "metadata": {}, 164 | "output_type": "execute_result" 165 | } 166 | ], 167 | "source": [ 168 | "system.actorOf(Props(new PubSubMediator), \"pub-sub-mediator\")" 169 | ] 170 | }, 171 | { 172 | "cell_type": "code", 173 | "execution_count": 6, 174 | "metadata": { 175 | "collapsed": false 176 | }, 177 | "outputs": [ 178 | { 179 | "data": { 180 | "text/plain": [ 181 | "defined \u001b[32mobject\u001b[39m \u001b[36mPubSubMediator\u001b[39m" 182 | ] 183 | }, 184 | "execution_count": 6, 185 | "metadata": {}, 186 | "output_type": "execute_result" 187 | } 188 | ], 189 | "source": [ 190 | "object PubSubMediator {\n", 191 | " \n", 192 | " final val Name = \"pub-sub-mediator\"\n", 193 | " \n", 194 | " def props: Props = Props(new PubSubMediator)\n", 195 | "}" 196 | ] 197 | }, 198 | { 199 | "cell_type": "markdown", 200 | "metadata": {}, 201 | "source": [ 202 | "А что за такая штуковина Props? Это просто конфигурационный объект для актора. Он принимает конструктор как параметр, передаваемый по имени (то есть, лениво) и может содержать другую важную информацию – например, о маршрутизации или развертывании. " 203 | ] 204 | }, 205 | { 206 | "cell_type": "code", 207 | "execution_count": 10, 208 | "metadata": { 209 | "collapsed": false 210 | }, 211 | "outputs": [ 212 | { 213 | "ename": "", 214 | "evalue": "", 215 | "output_type": "error", 216 | "traceback": [ 217 | "\u001b[31makka.actor.InvalidActorNameException: actor name [pub-sub-mediator] is not unique!\u001b[39m", 218 | " akka.actor.dungeon.ChildrenContainer$NormalChildrenContainer.reserve(\u001b[32mChildrenContainer.scala\u001b[39m:\u001b[32m129\u001b[39m)", 219 | " akka.actor.dungeon.Children$class.reserveChild(\u001b[32mChildren.scala\u001b[39m:\u001b[32m134\u001b[39m)", 220 | " akka.actor.ActorCell.reserveChild(\u001b[32mActorCell.scala\u001b[39m:\u001b[32m370\u001b[39m)", 221 | " akka.actor.dungeon.Children$class.makeChild(\u001b[32mChildren.scala\u001b[39m:\u001b[32m272\u001b[39m)", 222 | " akka.actor.dungeon.Children$class.attachChild(\u001b[32mChildren.scala\u001b[39m:\u001b[32m48\u001b[39m)", 223 | " akka.actor.ActorCell.attachChild(\u001b[32mActorCell.scala\u001b[39m:\u001b[32m370\u001b[39m)", 224 | " akka.actor.ActorSystemImpl.actorOf(\u001b[32mActorSystem.scala\u001b[39m:\u001b[32m717\u001b[39m)", 225 | " $sess.cmd9Wrapper$Helper.(\u001b[32mcmd9.sc\u001b[39m:\u001b[32m1\u001b[39m)", 226 | " $sess.cmd9Wrapper.(\u001b[32mcmd9.sc\u001b[39m:\u001b[32m223\u001b[39m)", 227 | " $sess.cmd9$.(\u001b[32mcmd9.sc\u001b[39m:\u001b[32m189\u001b[39m)", 228 | " $sess.cmd9$.(\u001b[32mcmd9.sc\u001b[39m:\u001b[32m-1\u001b[39m)" 229 | ] 230 | } 231 | ], 232 | "source": [ 233 | "// Если мы захотим создать актор с таким же именем\n", 234 | "// Мы этого не сможем сделать\n", 235 | "// Ибо у каждого актора должно быть уникальное имя\n", 236 | "system.actorOf(PubSubMediator.props, PubSubMediator.Name)" 237 | ] 238 | } 239 | ], 240 | "metadata": { 241 | "kernelspec": { 242 | "display_name": "Scala", 243 | "language": "scala", 244 | "name": "scala" 245 | }, 246 | "language_info": { 247 | "codemirror_mode": "text/x-scala", 248 | "file_extension": ".scala", 249 | "mimetype": "text/x-scala", 250 | "name": "scala211", 251 | "nbconvert_exporter": "script", 252 | "pygments_lexer": "scala", 253 | "version": "2.11.11" 254 | } 255 | }, 256 | "nbformat": 4, 257 | "nbformat_minor": 2 258 | } 259 | -------------------------------------------------------------------------------- /little-projects/Bank.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 35, 6 | "metadata": {}, 7 | "outputs": [ 8 | { 9 | "data": { 10 | "text/plain": [ 11 | "\u001b[32mimport \u001b[39m\u001b[36mscala.collection.mutable.ListBuffer\n", 12 | "\u001b[39m\n", 13 | "\u001b[32mimport \u001b[39m\u001b[36mscala.collection.mutable.Map\n", 14 | "\u001b[39m\n", 15 | "\u001b[32mimport \u001b[39m\u001b[36mscala.util.Random\n", 16 | "\u001b[39m\n", 17 | "\u001b[32mimport \u001b[39m\u001b[36mjava.util.Calendar\u001b[39m" 18 | ] 19 | }, 20 | "execution_count": 35, 21 | "metadata": {}, 22 | "output_type": "execute_result" 23 | } 24 | ], 25 | "source": [ 26 | "// Зависимости\n", 27 | "import scala.collection.mutable.ListBuffer\n", 28 | "import scala.collection.mutable.Map\n", 29 | "import scala.util.Random\n", 30 | "import java.util.Calendar" 31 | ] 32 | }, 33 | { 34 | "cell_type": "code", 35 | "execution_count": 36, 36 | "metadata": {}, 37 | "outputs": [ 38 | { 39 | "data": { 40 | "text/plain": [ 41 | "defined \u001b[32mclass\u001b[39m \u001b[36mAccountType\u001b[39m\n", 42 | "defined \u001b[32mclass\u001b[39m \u001b[36mHelpers\u001b[39m\n", 43 | "defined \u001b[32mclass\u001b[39m \u001b[36mBank\u001b[39m\n", 44 | "defined \u001b[32mclass\u001b[39m \u001b[36mTransaction\u001b[39m\n", 45 | "defined \u001b[32mclass\u001b[39m \u001b[36mCustomer\u001b[39m\n", 46 | "defined \u001b[32mclass\u001b[39m \u001b[36mAccount\u001b[39m\n", 47 | "defined \u001b[32mclass\u001b[39m \u001b[36mContribution\u001b[39m\n", 48 | "defined \u001b[32mclass\u001b[39m \u001b[36mCredit\u001b[39m" 49 | ] 50 | }, 51 | "execution_count": 36, 52 | "metadata": {}, 53 | "output_type": "execute_result" 54 | } 55 | ], 56 | "source": [ 57 | "case class AccountType(val name:String, val credit_percent:Double, val deposit_percent:Double, \n", 58 | " val giveaway_percent:Double, val contribution_percent:Double)\n", 59 | "\n", 60 | "\n", 61 | "class Helpers{\n", 62 | " def printTransactionInfo(trans:Transaction){ \n", 63 | " println(\"type: \" + trans.kind + \" amount: \" + trans.amount + \" date: \" + trans.datetime.getTime)\n", 64 | " }\n", 65 | " \n", 66 | " def printContributionInfo(contr:Contribution){\n", 67 | " println(\"amount: \" + contr.amount + \" years: \" + contr.years + \" start date: \" + contr.startTime.getTime + \" percent: \" + contr.account.accountType.contribution_percent)\n", 68 | " }\n", 69 | " \n", 70 | " def printCreditInfo(credit:Credit){\n", 71 | " println(\"amount: \" + credit.amount + \" months: \" + credit.months + \" start date: \" + credit.startTime.getTime + \" percent: \" + credit.account.accountType.credit_percent)\n", 72 | " }\n", 73 | " \n", 74 | " def printContributionsList(allcontr:ListBuffer[Contribution]){\n", 75 | " println(\"Contributions:\")\n", 76 | " for(i <- allcontr)\n", 77 | " printContributionInfo(i)\n", 78 | " }\n", 79 | " def printCreditList(allcred:ListBuffer[Credit]){\n", 80 | " println(\"Credits:\")\n", 81 | " for(i <- allcred)\n", 82 | " printCreditInfo(i)\n", 83 | " }\n", 84 | " \n", 85 | " def printTransactionsList(alltrans:ListBuffer[Transaction]){\n", 86 | " println(\"Transactions:\")\n", 87 | " for(i <- alltrans)\n", 88 | " printTransactionInfo(i)\n", 89 | " }\n", 90 | "\n", 91 | " def printAccountInfo(account:Account){\n", 92 | " print (\"balance: \" + account.balance + \" Type: \" + account.accountType.name + \"\\n\")\n", 93 | " printTransactionsList(account.transactions)\n", 94 | " printContributionsList(account.contributions)\n", 95 | " printCreditList(account.credits)\n", 96 | " }\n", 97 | " def printCustomerInfo(user:Customer){\n", 98 | " print(\"name: \" + user.name + \"\\nAccounts:\\n\")\n", 99 | " for(i <- user.accounts){\n", 100 | " printAccountInfo(i)\n", 101 | " print(\"\\n\")\n", 102 | " }\n", 103 | " }\n", 104 | "}\n", 105 | "class Bank {\n", 106 | " // Клиенты банка\n", 107 | " var customers = new ListBuffer[Customer]\n", 108 | "\n", 109 | " // Добавить клиента\n", 110 | " def addCustomer(customer: Customer) { customers += customer }\n", 111 | " \n", 112 | " //типы аккаунтов, у разных типов разные проценты на депозиты, переводы, кредиты и вклады\n", 113 | " var accTypes:Map[String, AccountType] = Map(\"basic\" -> new AccountType(\"basic\", 1.2, 0.9, 0.9, 1.10),\n", 114 | " \"VIP\" -> new AccountType(\"VIP\", 1.1, 0.95, 0.95, 1.20),\n", 115 | " \"premier\" -> new AccountType(\"premier\", 1.05,0.99, 0.99,1.30)) \n", 116 | " def getAccType(accType:String):AccountType={\n", 117 | " return accTypes(accType)\n", 118 | " }\n", 119 | " def getAllUsers():ListBuffer[Customer]={\n", 120 | " return customers\n", 121 | " }\n", 122 | " \n", 123 | " //симуляция работы банка\n", 124 | " def work()={\n", 125 | " var help = new Helpers()\n", 126 | " var flag = true\n", 127 | " for(user <- customers){\n", 128 | " for(account <- user.accounts){\n", 129 | " for(contribution <- account.contributions){\n", 130 | " contribution.startTime = Calendar.getInstance\n", 131 | " }\n", 132 | " for(credit <- account.credits){\n", 133 | " credit.startTime = Calendar.getInstance\n", 134 | " }\n", 135 | " }\n", 136 | " }\n", 137 | " var iteration = 1\n", 138 | " while(flag == true){\n", 139 | " flag = false\n", 140 | " for(user <- customers){\n", 141 | " for(account <- user.accounts){\n", 142 | " for(contribution <- account.contributions){\n", 143 | " if(iteration%12 == 0){\n", 144 | " println(\"Contrbutions\")\n", 145 | " help.printContributionInfo(contribution)\n", 146 | " contribution.upgrade()\n", 147 | " }\n", 148 | " flag = true\n", 149 | " }\n", 150 | " for(credit <- account.credits){\n", 151 | " println(\"credits\")\n", 152 | " help.printCreditInfo(credit)\n", 153 | " credit.upgrade()\n", 154 | " flag = true\n", 155 | " }\n", 156 | " }\n", 157 | " }\n", 158 | " if(flag == true){\n", 159 | " println(\"Прошел месяц....\")\n", 160 | " Thread.sleep(1000)\n", 161 | " }\n", 162 | " iteration+=1\n", 163 | " }\n", 164 | " }\n", 165 | " \n", 166 | " def block_account(account:Account)=account.blocked = true\n", 167 | " \n", 168 | " def unblock_account(account:Account)=account.blocked = false\n", 169 | " \n", 170 | " //оплатить весь долг по кредиту(менеджер)\n", 171 | " def pay_for_credit(credit:Credit){\n", 172 | " credit.payAll()\n", 173 | " }\n", 174 | " \n", 175 | " //вывести деньги из вклада(менеджер)\n", 176 | " def get_contribution_back(contribution:Contribution){\n", 177 | " contribution.getMoneyBack()\n", 178 | " }\n", 179 | "}\n", 180 | "\n", 181 | "class Transaction(val kind:String, val amount:Double){\n", 182 | " val datetime = Calendar.getInstance()\n", 183 | "}\n", 184 | "\n", 185 | "// Пользователи\n", 186 | "\n", 187 | "class Customer(val name: String) {\n", 188 | "\n", 189 | " // Аккаунты пользователя\n", 190 | " val accounts: ListBuffer[Account] = ListBuffer()\n", 191 | " // Создать новый счёт\n", 192 | " def openAccount(account: Account): Customer = {\n", 193 | " accounts += account\n", 194 | " this\n", 195 | " }\n", 196 | "\n", 197 | " def get_all_transactions(account:Account):ListBuffer[Transaction] = {\n", 198 | " return account.transactions\n", 199 | " } \n", 200 | " \n", 201 | " def delete_account(account:Account)={\n", 202 | " accounts -= account\n", 203 | " }\n", 204 | " \n", 205 | " //перевод средств на другой счет\n", 206 | " def give_money(from_account:Account, to_account:Account, sum:Double) = {\n", 207 | " if(from_account.balance < sum)\n", 208 | " throw new IllegalArgumentException(\"Не достаточно денег на счете\")\n", 209 | " else{\n", 210 | " from_account.balance -= sum\n", 211 | " to_account.balance += sum*from_account.accountType.giveaway_percent\n", 212 | " }\n", 213 | " from_account.transactions.append(new Transaction(\"giveaway\", -sum))\n", 214 | " to_account.transactions.append(new Transaction(\"addition\", sum*from_account.accountType.giveaway_percent))\n", 215 | " }\n", 216 | "}\n", 217 | "\n", 218 | "class Account(val accountType:AccountType) {\n", 219 | " // Баланс аккаунта\n", 220 | " var balance = 0.0\n", 221 | " val contributions: ListBuffer[Contribution] = ListBuffer()\n", 222 | " val credits: ListBuffer[Credit] = ListBuffer()\n", 223 | " val transactions:ListBuffer[Transaction] = ListBuffer()\n", 224 | " // Uid аккаунта\n", 225 | " val uid = java.util.UUID.randomUUID.toString\n", 226 | " var blocked = false\n", 227 | "\n", 228 | " // Добавление денег на аккаунт\n", 229 | " def deposit(amount: Double) {\n", 230 | " if(blocked)\n", 231 | " println(\"Аккаунт заблокирован, невозможно произвести операцию\")\n", 232 | " else if (amount <= 0)\n", 233 | " throw new IllegalArgumentException(\"У вас должно быть больше денег чем 0\")\n", 234 | " else\n", 235 | " // Добавить денег\n", 236 | " balance += amount*accountType.deposit_percent\n", 237 | " transactions.append(new Transaction(\"deposit\", amount*accountType.deposit_percent))\n", 238 | " }\n", 239 | " \n", 240 | " //вывод средств со счета\n", 241 | " def remove_money(amount: Double){\n", 242 | " if(blocked)\n", 243 | " println(\"Аккаунт заблокирован, невозможно произвести операцию\")\n", 244 | " if(amount > balance)\n", 245 | " throw new IllegalArgumentException(\"Не достаточно денег на счете\")\n", 246 | " else{\n", 247 | " balance -= amount\n", 248 | " transactions.append(new Transaction(\"windraw\", -amount))\n", 249 | " }\n", 250 | " }\n", 251 | " \n", 252 | " \n", 253 | " def new_contribution(amount:Double, years:Int)={\n", 254 | " if(blocked)\n", 255 | " println(\"Аккаунт заблокирован, невозможно произвести операцию\")\n", 256 | " if(amount > balance)\n", 257 | " throw new IllegalArgumentException(\"Не достаточно денег на счете\")\n", 258 | " else{\n", 259 | " balance -= amount\n", 260 | " contributions.append(new Contribution(amount, years, this))\n", 261 | " transactions.append(new Transaction(\"contribution\", -amount))\n", 262 | " }\n", 263 | " }\n", 264 | " \n", 265 | " def new_credit(amount:Double, years:Int){\n", 266 | " if(blocked)\n", 267 | " println(\"Аккаунт заблокирован, невозможно произвести операцию\")\n", 268 | " balance+=amount\n", 269 | " credits.append(new Credit(amount, years, this))\n", 270 | " transactions.append(new Transaction(\"credit\", amount))\n", 271 | " }\n", 272 | " //оплатить весь долг по кредиту(клиент)\n", 273 | " def pay_for_credit(credit:Credit){\n", 274 | " credit.payAll()\n", 275 | " }\n", 276 | " \n", 277 | " //вывести деньги из вклада(клиент)\n", 278 | " def get_contribution_back(contribution:Contribution){\n", 279 | " contribution.getMoneyBack()\n", 280 | " }\n", 281 | "}\n", 282 | "\n", 283 | "class Contribution(var amount:Double, var years:Int, val account:Account){\n", 284 | " var startTime = Calendar.getInstance()\n", 285 | " //обновление вклада(каждый месяц)\n", 286 | " def upgrade() = {\n", 287 | " if(years==0){\n", 288 | " getMoneyBack()\n", 289 | " }\n", 290 | " else\n", 291 | " amount*=account.accountType.contribution_percent\n", 292 | " years-=1\n", 293 | " }\n", 294 | " //забрать все деньги из вклада\n", 295 | " def getMoneyBack(){\n", 296 | " account.balance += amount\n", 297 | " account.contributions -= this\n", 298 | " account.transactions.append(new Transaction(\"from contribution\", amount))\n", 299 | " }\n", 300 | "}\n", 301 | "\n", 302 | "class Credit (var amount:Double, var years:Int, val account:Account){\n", 303 | " var months = years*12\n", 304 | " var startTime = Calendar.getInstance()\n", 305 | " val sumToPay:Double = amount*account.accountType.credit_percent/months\n", 306 | " \n", 307 | " //обновление кредита(каждый месяц)\n", 308 | " def upgrade(){\n", 309 | " if(months==0){\n", 310 | " account.credits -= this\n", 311 | " }\n", 312 | " else\n", 313 | " {\n", 314 | " if(sumToPay > account.balance)\n", 315 | " print(\"Теперь вы должны банку денег\")\n", 316 | " account.balance -= sumToPay\n", 317 | " account.transactions.append(new Transaction(\"credit pay\", -sumToPay))\n", 318 | " }\n", 319 | " months-=1\n", 320 | " }\n", 321 | " \n", 322 | " //заплатить весь долг за кредит\n", 323 | " def payAll(){\n", 324 | " if(account.balance < sumToPay*months)\n", 325 | " print(\"Не достаточно средств на счете, чтобы оплатить кредит\")\n", 326 | " else{\n", 327 | " account.balance -= sumToPay*months\n", 328 | " account.credits -= this\n", 329 | " account.transactions.append(new Transaction(\"credit pay\", -sumToPay*months))\n", 330 | " }\n", 331 | " }\n", 332 | "}" 333 | ] 334 | }, 335 | { 336 | "cell_type": "code", 337 | "execution_count": 37, 338 | "metadata": { 339 | "scrolled": true 340 | }, 341 | "outputs": [ 342 | { 343 | "data": { 344 | "text/plain": [ 345 | "\u001b[36mbank\u001b[39m: \u001b[32mBank\u001b[39m = $sess.cmd35Wrapper$Helper$Bank@16a0f564" 346 | ] 347 | }, 348 | "execution_count": 37, 349 | "metadata": {}, 350 | "output_type": "execute_result" 351 | } 352 | ], 353 | "source": [ 354 | "val bank = new Bank" 355 | ] 356 | }, 357 | { 358 | "cell_type": "code", 359 | "execution_count": 38, 360 | "metadata": {}, 361 | "outputs": [ 362 | { 363 | "data": { 364 | "text/plain": [ 365 | "\u001b[36mhelp\u001b[39m: \u001b[32mHelpers\u001b[39m = $sess.cmd35Wrapper$Helper$Helpers@43c5cba2\n", 366 | "\u001b[36muser\u001b[39m: \u001b[32mCustomer\u001b[39m = $sess.cmd35Wrapper$Helper$Customer@437163f2\n", 367 | "\u001b[36maccount\u001b[39m: \u001b[32mAccount\u001b[39m = $sess.cmd35Wrapper$Helper$Account@492f6796\n", 368 | "\u001b[36mres37_4\u001b[39m: \u001b[32mCustomer\u001b[39m = $sess.cmd35Wrapper$Helper$Customer@437163f2\n", 369 | "\u001b[36maccount2\u001b[39m: \u001b[32mAccount\u001b[39m = $sess.cmd35Wrapper$Helper$Account@48097be0\n", 370 | "\u001b[36mres37_6\u001b[39m: \u001b[32mCustomer\u001b[39m = $sess.cmd35Wrapper$Helper$Customer@437163f2" 371 | ] 372 | }, 373 | "execution_count": 38, 374 | "metadata": {}, 375 | "output_type": "execute_result" 376 | } 377 | ], 378 | "source": [ 379 | "var help = new Helpers //объект класса - помощник по выводу\n", 380 | "var user = new Customer(\"Даня Ололоев\")\n", 381 | "bank.addCustomer(user)\n", 382 | "var account = new Account(bank.getAccType(\"basic\"))\n", 383 | "user.openAccount(account) \n", 384 | "var account2 = new Account(bank.getAccType(\"VIP\"))\n", 385 | "user.openAccount(account2)" 386 | ] 387 | }, 388 | { 389 | "cell_type": "code", 390 | "execution_count": 39, 391 | "metadata": { 392 | "collapsed": true 393 | }, 394 | "outputs": [], 395 | "source": [ 396 | "account.deposit(400)\n", 397 | "account2.deposit(400)" 398 | ] 399 | }, 400 | { 401 | "cell_type": "code", 402 | "execution_count": 40, 403 | "metadata": {}, 404 | "outputs": [ 405 | { 406 | "name": "stdout", 407 | "output_type": "stream", 408 | "text": [ 409 | "name: Даня Ололоев\n", 410 | "Accounts:\n", 411 | "balance: 360.0 Type: basic\n", 412 | "Transactions:\n", 413 | "type: deposit amount: 360.0 date: Mon Jun 19 10:02:39 MSK 2017\n", 414 | "Contributions:\n", 415 | "Credits:\n", 416 | "\n", 417 | "balance: 380.0 Type: VIP\n", 418 | "Transactions:\n", 419 | "type: deposit amount: 380.0 date: Mon Jun 19 10:02:39 MSK 2017\n", 420 | "Contributions:\n", 421 | "Credits:\n", 422 | "\n" 423 | ] 424 | } 425 | ], 426 | "source": [ 427 | "help.printCustomerInfo(user)" 428 | ] 429 | }, 430 | { 431 | "cell_type": "code", 432 | "execution_count": 41, 433 | "metadata": { 434 | "collapsed": true 435 | }, 436 | "outputs": [], 437 | "source": [ 438 | "bank.block_account(account)" 439 | ] 440 | }, 441 | { 442 | "cell_type": "code", 443 | "execution_count": 42, 444 | "metadata": {}, 445 | "outputs": [ 446 | { 447 | "name": "stdout", 448 | "output_type": "stream", 449 | "text": [ 450 | "Аккаунт заблокирован, невозможно произвести операцию\n" 451 | ] 452 | } 453 | ], 454 | "source": [ 455 | "account.deposit(400)" 456 | ] 457 | }, 458 | { 459 | "cell_type": "code", 460 | "execution_count": 43, 461 | "metadata": { 462 | "collapsed": true 463 | }, 464 | "outputs": [], 465 | "source": [ 466 | "bank.unblock_account(account)" 467 | ] 468 | }, 469 | { 470 | "cell_type": "code", 471 | "execution_count": 44, 472 | "metadata": { 473 | "collapsed": true 474 | }, 475 | "outputs": [], 476 | "source": [ 477 | "user.give_money(account, account2, 100)" 478 | ] 479 | }, 480 | { 481 | "cell_type": "code", 482 | "execution_count": 45, 483 | "metadata": {}, 484 | "outputs": [ 485 | { 486 | "name": "stdout", 487 | "output_type": "stream", 488 | "text": [ 489 | "name: Даня Ололоев\n", 490 | "Accounts:\n", 491 | "balance: 260.0 Type: basic\n", 492 | "Transactions:\n", 493 | "type: deposit amount: 360.0 date: Mon Jun 19 10:02:39 MSK 2017\n", 494 | "type: deposit amount: 360.0 date: Mon Jun 19 10:02:41 MSK 2017\n", 495 | "type: giveaway amount: -100.0 date: Mon Jun 19 10:02:42 MSK 2017\n", 496 | "Contributions:\n", 497 | "Credits:\n", 498 | "\n", 499 | "balance: 470.0 Type: VIP\n", 500 | "Transactions:\n", 501 | "type: deposit amount: 380.0 date: Mon Jun 19 10:02:39 MSK 2017\n", 502 | "type: addition amount: 90.0 date: Mon Jun 19 10:02:42 MSK 2017\n", 503 | "Contributions:\n", 504 | "Credits:\n", 505 | "\n" 506 | ] 507 | } 508 | ], 509 | "source": [ 510 | "help.printCustomerInfo(user)" 511 | ] 512 | }, 513 | { 514 | "cell_type": "code", 515 | "execution_count": 46, 516 | "metadata": { 517 | "collapsed": true 518 | }, 519 | "outputs": [], 520 | "source": [ 521 | "account2.remove_money(80)" 522 | ] 523 | }, 524 | { 525 | "cell_type": "code", 526 | "execution_count": 47, 527 | "metadata": { 528 | "collapsed": true 529 | }, 530 | "outputs": [], 531 | "source": [ 532 | "account2.new_credit(100, 2)\n", 533 | "account2.new_contribution(100, 3)" 534 | ] 535 | }, 536 | { 537 | "cell_type": "code", 538 | "execution_count": 48, 539 | "metadata": {}, 540 | "outputs": [ 541 | { 542 | "name": "stdout", 543 | "output_type": "stream", 544 | "text": [ 545 | "name: Даня Ололоев\n", 546 | "Accounts:\n", 547 | "balance: 260.0 Type: basic\n", 548 | "Transactions:\n", 549 | "type: deposit amount: 360.0 date: Mon Jun 19 10:02:39 MSK 2017\n", 550 | "type: deposit amount: 360.0 date: Mon Jun 19 10:02:41 MSK 2017\n", 551 | "type: giveaway amount: -100.0 date: Mon Jun 19 10:02:42 MSK 2017\n", 552 | "Contributions:\n", 553 | "Credits:\n", 554 | "\n", 555 | "balance: 390.0 Type: VIP\n", 556 | "Transactions:\n", 557 | "type: deposit amount: 380.0 date: Mon Jun 19 10:02:39 MSK 2017\n", 558 | "type: addition amount: 90.0 date: Mon Jun 19 10:02:42 MSK 2017\n", 559 | "type: windraw amount: -80.0 date: Mon Jun 19 10:02:43 MSK 2017\n", 560 | "type: credit amount: 100.0 date: Mon Jun 19 10:02:43 MSK 2017\n", 561 | "type: contribution amount: -100.0 date: Mon Jun 19 10:02:43 MSK 2017\n", 562 | "Contributions:\n", 563 | "amount: 100.0 years: 3 start date: Mon Jun 19 10:02:43 MSK 2017 percent: 1.2\n", 564 | "Credits:\n", 565 | "amount: 100.0 months: 24 start date: Mon Jun 19 10:02:43 MSK 2017 percent: 1.1\n", 566 | "\n" 567 | ] 568 | } 569 | ], 570 | "source": [ 571 | "help.printCustomerInfo(user)" 572 | ] 573 | }, 574 | { 575 | "cell_type": "code", 576 | "execution_count": 49, 577 | "metadata": {}, 578 | "outputs": [], 579 | "source": [ 580 | "bank.pay_for_credit(account2.credits(0)) //сразу отдаем весь долг по кредиту\n", 581 | "bank.get_contribution_back(account2.contributions(0)) //забираем деньги из вклада" 582 | ] 583 | }, 584 | { 585 | "cell_type": "code", 586 | "execution_count": 50, 587 | "metadata": { 588 | "scrolled": false 589 | }, 590 | "outputs": [ 591 | { 592 | "name": "stdout", 593 | "output_type": "stream", 594 | "text": [ 595 | "name: Даня Ололоев\n", 596 | "Accounts:\n", 597 | "balance: 260.0 Type: basic\n", 598 | "Transactions:\n", 599 | "type: deposit amount: 360.0 date: Mon Jun 19 10:02:39 MSK 2017\n", 600 | "type: deposit amount: 360.0 date: Mon Jun 19 10:02:41 MSK 2017\n", 601 | "type: giveaway amount: -100.0 date: Mon Jun 19 10:02:42 MSK 2017\n", 602 | "Contributions:\n", 603 | "Credits:\n", 604 | "\n", 605 | "balance: 380.0 Type: VIP\n", 606 | "Transactions:\n", 607 | "type: deposit amount: 380.0 date: Mon Jun 19 10:02:39 MSK 2017\n", 608 | "type: addition amount: 90.0 date: Mon Jun 19 10:02:42 MSK 2017\n", 609 | "type: windraw amount: -80.0 date: Mon Jun 19 10:02:43 MSK 2017\n", 610 | "type: credit amount: 100.0 date: Mon Jun 19 10:02:43 MSK 2017\n", 611 | "type: contribution amount: -100.0 date: Mon Jun 19 10:02:43 MSK 2017\n", 612 | "type: credit pay amount: -110.00000000000001 date: Mon Jun 19 10:02:44 MSK 2017\n", 613 | "type: from contribution amount: 100.0 date: Mon Jun 19 10:02:44 MSK 2017\n", 614 | "Contributions:\n", 615 | "Credits:\n", 616 | "\n" 617 | ] 618 | } 619 | ], 620 | "source": [ 621 | "help.printCustomerInfo(user)" 622 | ] 623 | }, 624 | { 625 | "cell_type": "code", 626 | "execution_count": 51, 627 | "metadata": { 628 | "collapsed": true 629 | }, 630 | "outputs": [], 631 | "source": [ 632 | "account2.new_credit(100, 2)\n", 633 | "account2.new_contribution(100, 3)" 634 | ] 635 | }, 636 | { 637 | "cell_type": "code", 638 | "execution_count": 52, 639 | "metadata": {}, 640 | "outputs": [ 641 | { 642 | "name": "stdout", 643 | "output_type": "stream", 644 | "text": [ 645 | "credits\n", 646 | "amount: 100.0 months: 24 start date: Mon Jun 19 10:02:45 MSK 2017 percent: 1.1\n", 647 | "Прошел месяц....\n", 648 | "credits\n", 649 | "amount: 100.0 months: 23 start date: Mon Jun 19 10:02:45 MSK 2017 percent: 1.1\n", 650 | "Прошел месяц....\n", 651 | "credits\n", 652 | "amount: 100.0 months: 22 start date: Mon Jun 19 10:02:45 MSK 2017 percent: 1.1\n", 653 | "Прошел месяц....\n", 654 | "credits\n", 655 | "amount: 100.0 months: 21 start date: Mon Jun 19 10:02:45 MSK 2017 percent: 1.1\n", 656 | "Прошел месяц....\n", 657 | "credits\n", 658 | "amount: 100.0 months: 20 start date: Mon Jun 19 10:02:45 MSK 2017 percent: 1.1\n", 659 | "Прошел месяц....\n", 660 | "credits\n", 661 | "amount: 100.0 months: 19 start date: Mon Jun 19 10:02:45 MSK 2017 percent: 1.1\n", 662 | "Прошел месяц....\n", 663 | "credits\n", 664 | "amount: 100.0 months: 18 start date: Mon Jun 19 10:02:45 MSK 2017 percent: 1.1\n", 665 | "Прошел месяц....\n", 666 | "credits\n", 667 | "amount: 100.0 months: 17 start date: Mon Jun 19 10:02:45 MSK 2017 percent: 1.1\n", 668 | "Прошел месяц....\n", 669 | "credits\n", 670 | "amount: 100.0 months: 16 start date: Mon Jun 19 10:02:45 MSK 2017 percent: 1.1\n", 671 | "Прошел месяц....\n", 672 | "credits\n", 673 | "amount: 100.0 months: 15 start date: Mon Jun 19 10:02:45 MSK 2017 percent: 1.1\n", 674 | "Прошел месяц....\n", 675 | "credits\n", 676 | "amount: 100.0 months: 14 start date: Mon Jun 19 10:02:45 MSK 2017 percent: 1.1\n", 677 | "Прошел месяц....\n", 678 | "Contrbutions\n", 679 | "amount: 100.0 years: 3 start date: Mon Jun 19 10:02:45 MSK 2017 percent: 1.2\n", 680 | "credits\n", 681 | "amount: 100.0 months: 13 start date: Mon Jun 19 10:02:45 MSK 2017 percent: 1.1\n", 682 | "Прошел месяц....\n", 683 | "credits\n", 684 | "amount: 100.0 months: 12 start date: Mon Jun 19 10:02:45 MSK 2017 percent: 1.1\n", 685 | "Прошел месяц....\n", 686 | "credits\n", 687 | "amount: 100.0 months: 11 start date: Mon Jun 19 10:02:45 MSK 2017 percent: 1.1\n", 688 | "Прошел месяц....\n", 689 | "credits\n", 690 | "amount: 100.0 months: 10 start date: Mon Jun 19 10:02:45 MSK 2017 percent: 1.1\n", 691 | "Прошел месяц....\n", 692 | "credits\n", 693 | "amount: 100.0 months: 9 start date: Mon Jun 19 10:02:45 MSK 2017 percent: 1.1\n", 694 | "Прошел месяц....\n", 695 | "credits\n", 696 | "amount: 100.0 months: 8 start date: Mon Jun 19 10:02:45 MSK 2017 percent: 1.1\n", 697 | "Прошел месяц....\n", 698 | "credits\n", 699 | "amount: 100.0 months: 7 start date: Mon Jun 19 10:02:45 MSK 2017 percent: 1.1\n", 700 | "Прошел месяц....\n", 701 | "credits\n", 702 | "amount: 100.0 months: 6 start date: Mon Jun 19 10:02:45 MSK 2017 percent: 1.1\n", 703 | "Прошел месяц....\n", 704 | "credits\n", 705 | "amount: 100.0 months: 5 start date: Mon Jun 19 10:02:45 MSK 2017 percent: 1.1\n", 706 | "Прошел месяц....\n", 707 | "credits\n", 708 | "amount: 100.0 months: 4 start date: Mon Jun 19 10:02:45 MSK 2017 percent: 1.1\n", 709 | "Прошел месяц....\n", 710 | "credits\n", 711 | "amount: 100.0 months: 3 start date: Mon Jun 19 10:02:45 MSK 2017 percent: 1.1\n", 712 | "Прошел месяц....\n", 713 | "credits\n", 714 | "amount: 100.0 months: 2 start date: Mon Jun 19 10:02:45 MSK 2017 percent: 1.1\n", 715 | "Прошел месяц....\n", 716 | "Contrbutions\n", 717 | "amount: 120.0 years: 2 start date: Mon Jun 19 10:02:45 MSK 2017 percent: 1.2\n", 718 | "credits\n", 719 | "amount: 100.0 months: 1 start date: Mon Jun 19 10:02:45 MSK 2017 percent: 1.1\n", 720 | "Прошел месяц....\n", 721 | "credits\n", 722 | "amount: 100.0 months: 0 start date: Mon Jun 19 10:02:45 MSK 2017 percent: 1.1\n", 723 | "Прошел месяц....\n", 724 | "Прошел месяц....\n", 725 | "Прошел месяц....\n", 726 | "Прошел месяц....\n", 727 | "Прошел месяц....\n", 728 | "Прошел месяц....\n", 729 | "Прошел месяц....\n", 730 | "Прошел месяц....\n", 731 | "Прошел месяц....\n", 732 | "Прошел месяц....\n", 733 | "Прошел месяц....\n", 734 | "Contrbutions\n", 735 | "amount: 144.0 years: 1 start date: Mon Jun 19 10:02:45 MSK 2017 percent: 1.2\n", 736 | "Прошел месяц....\n", 737 | "Прошел месяц....\n", 738 | "Прошел месяц....\n", 739 | "Прошел месяц....\n", 740 | "Прошел месяц....\n", 741 | "Прошел месяц....\n", 742 | "Прошел месяц....\n", 743 | "Прошел месяц....\n", 744 | "Прошел месяц....\n", 745 | "Прошел месяц....\n", 746 | "Прошел месяц....\n", 747 | "Прошел месяц....\n", 748 | "Contrbutions\n", 749 | "amount: 172.79999999999998 years: 0 start date: Mon Jun 19 10:02:45 MSK 2017 percent: 1.2\n", 750 | "Прошел месяц....\n" 751 | ] 752 | } 753 | ], 754 | "source": [ 755 | "bank.work //симулятор работы банка\n", 756 | " //кредит отдаётся каждый месяц (сумма зависит от суммы кредита, процентной ставки и срока)\n", 757 | " //вклад пополняется каждый год, начисление на счет происходит только после закрытия вклада" 758 | ] 759 | }, 760 | { 761 | "cell_type": "code", 762 | "execution_count": 53, 763 | "metadata": {}, 764 | "outputs": [ 765 | { 766 | "name": "stdout", 767 | "output_type": "stream", 768 | "text": [ 769 | "name: Даня Ололоев\n", 770 | "Accounts:\n", 771 | "balance: 260.0 Type: basic\n", 772 | "Transactions:\n", 773 | "type: deposit amount: 360.0 date: Mon Jun 19 10:02:39 MSK 2017\n", 774 | "type: deposit amount: 360.0 date: Mon Jun 19 10:02:41 MSK 2017\n", 775 | "type: giveaway amount: -100.0 date: Mon Jun 19 10:02:42 MSK 2017\n", 776 | "Contributions:\n", 777 | "Credits:\n", 778 | "\n", 779 | "balance: 442.8000000000004 Type: VIP\n", 780 | "Transactions:\n", 781 | "type: deposit amount: 380.0 date: Mon Jun 19 10:02:39 MSK 2017\n", 782 | "type: addition amount: 90.0 date: Mon Jun 19 10:02:42 MSK 2017\n", 783 | "type: windraw amount: -80.0 date: Mon Jun 19 10:02:43 MSK 2017\n", 784 | "type: credit amount: 100.0 date: Mon Jun 19 10:02:43 MSK 2017\n", 785 | "type: contribution amount: -100.0 date: Mon Jun 19 10:02:43 MSK 2017\n", 786 | "type: credit pay amount: -110.00000000000001 date: Mon Jun 19 10:02:44 MSK 2017\n", 787 | "type: from contribution amount: 100.0 date: Mon Jun 19 10:02:44 MSK 2017\n", 788 | "type: credit amount: 100.0 date: Mon Jun 19 10:02:44 MSK 2017\n", 789 | "type: contribution amount: -100.0 date: Mon Jun 19 10:02:44 MSK 2017\n", 790 | "type: credit pay amount: -4.583333333333334 date: Mon Jun 19 10:02:45 MSK 2017\n", 791 | "type: credit pay amount: -4.583333333333334 date: Mon Jun 19 10:02:46 MSK 2017\n", 792 | "type: credit pay amount: -4.583333333333334 date: Mon Jun 19 10:02:47 MSK 2017\n", 793 | "type: credit pay amount: -4.583333333333334 date: Mon Jun 19 10:02:48 MSK 2017\n", 794 | "type: credit pay amount: -4.583333333333334 date: Mon Jun 19 10:02:49 MSK 2017\n", 795 | "type: credit pay amount: -4.583333333333334 date: Mon Jun 19 10:02:50 MSK 2017\n", 796 | "type: credit pay amount: -4.583333333333334 date: Mon Jun 19 10:02:51 MSK 2017\n", 797 | "type: credit pay amount: -4.583333333333334 date: Mon Jun 19 10:02:52 MSK 2017\n", 798 | "type: credit pay amount: -4.583333333333334 date: Mon Jun 19 10:02:53 MSK 2017\n", 799 | "type: credit pay amount: -4.583333333333334 date: Mon Jun 19 10:02:54 MSK 2017\n", 800 | "type: credit pay amount: -4.583333333333334 date: Mon Jun 19 10:02:55 MSK 2017\n", 801 | "type: credit pay amount: -4.583333333333334 date: Mon Jun 19 10:02:56 MSK 2017\n", 802 | "type: credit pay amount: -4.583333333333334 date: Mon Jun 19 10:02:57 MSK 2017\n", 803 | "type: credit pay amount: -4.583333333333334 date: Mon Jun 19 10:02:58 MSK 2017\n", 804 | "type: credit pay amount: -4.583333333333334 date: Mon Jun 19 10:02:59 MSK 2017\n", 805 | "type: credit pay amount: -4.583333333333334 date: Mon Jun 19 10:03:00 MSK 2017\n", 806 | "type: credit pay amount: -4.583333333333334 date: Mon Jun 19 10:03:01 MSK 2017\n", 807 | "type: credit pay amount: -4.583333333333334 date: Mon Jun 19 10:03:02 MSK 2017\n", 808 | "type: credit pay amount: -4.583333333333334 date: Mon Jun 19 10:03:03 MSK 2017\n", 809 | "type: credit pay amount: -4.583333333333334 date: Mon Jun 19 10:03:04 MSK 2017\n", 810 | "type: credit pay amount: -4.583333333333334 date: Mon Jun 19 10:03:05 MSK 2017\n", 811 | "type: credit pay amount: -4.583333333333334 date: Mon Jun 19 10:03:06 MSK 2017\n", 812 | "type: credit pay amount: -4.583333333333334 date: Mon Jun 19 10:03:07 MSK 2017\n", 813 | "type: credit pay amount: -4.583333333333334 date: Mon Jun 19 10:03:08 MSK 2017\n", 814 | "type: from contribution amount: 172.79999999999998 date: Mon Jun 19 10:03:32 MSK 2017\n", 815 | "Contributions:\n", 816 | "Credits:\n", 817 | "\n" 818 | ] 819 | } 820 | ], 821 | "source": [ 822 | "help.printCustomerInfo(user)" 823 | ] 824 | }, 825 | { 826 | "cell_type": "code", 827 | "execution_count": 54, 828 | "metadata": {}, 829 | "outputs": [ 830 | { 831 | "data": { 832 | "text/plain": [ 833 | "\u001b[36mres53\u001b[39m: \u001b[32mListBuffer\u001b[39m[\u001b[32mAccount\u001b[39m] = \u001b[33mListBuffer\u001b[39m($sess.cmd35Wrapper$Helper$Account@492f6796)" 834 | ] 835 | }, 836 | "execution_count": 54, 837 | "metadata": {}, 838 | "output_type": "execute_result" 839 | } 840 | ], 841 | "source": [ 842 | "user.delete_account(account2)" 843 | ] 844 | }, 845 | { 846 | "cell_type": "code", 847 | "execution_count": 55, 848 | "metadata": {}, 849 | "outputs": [ 850 | { 851 | "name": "stdout", 852 | "output_type": "stream", 853 | "text": [ 854 | "name: Даня Ололоев\n", 855 | "Accounts:\n", 856 | "balance: 260.0 Type: basic\n", 857 | "Transactions:\n", 858 | "type: deposit amount: 360.0 date: Mon Jun 19 10:02:39 MSK 2017\n", 859 | "type: deposit amount: 360.0 date: Mon Jun 19 10:02:41 MSK 2017\n", 860 | "type: giveaway amount: -100.0 date: Mon Jun 19 10:02:42 MSK 2017\n", 861 | "Contributions:\n", 862 | "Credits:\n", 863 | "\n" 864 | ] 865 | } 866 | ], 867 | "source": [ 868 | "help.printCustomerInfo(user)" 869 | ] 870 | }, 871 | { 872 | "cell_type": "code", 873 | "execution_count": 56, 874 | "metadata": {}, 875 | "outputs": [ 876 | { 877 | "data": { 878 | "text/plain": [ 879 | "\u001b[36mres55\u001b[39m: \u001b[32mListBuffer\u001b[39m[\u001b[32mCustomer\u001b[39m] = \u001b[33mListBuffer\u001b[39m($sess.cmd35Wrapper$Helper$Customer@437163f2)" 880 | ] 881 | }, 882 | "execution_count": 56, 883 | "metadata": {}, 884 | "output_type": "execute_result" 885 | } 886 | ], 887 | "source": [ 888 | "bank.getAllUsers()//API банка, через user-ов можно получить их счета и переводить на них деньги" 889 | ] 890 | }, 891 | { 892 | "cell_type": "code", 893 | "execution_count": null, 894 | "metadata": { 895 | "collapsed": true 896 | }, 897 | "outputs": [], 898 | "source": [] 899 | }, 900 | { 901 | "cell_type": "code", 902 | "execution_count": null, 903 | "metadata": { 904 | "collapsed": true 905 | }, 906 | "outputs": [], 907 | "source": [] 908 | } 909 | ], 910 | "metadata": { 911 | "kernelspec": { 912 | "display_name": "Scala", 913 | "language": "scala", 914 | "name": "scala" 915 | }, 916 | "language_info": { 917 | "codemirror_mode": "text/x-scala", 918 | "file_extension": ".scala", 919 | "mimetype": "text/x-scala", 920 | "name": "scala211", 921 | "nbconvert_exporter": "script", 922 | "pygments_lexer": "scala", 923 | "version": "2.11.11" 924 | } 925 | }, 926 | "nbformat": 4, 927 | "nbformat_minor": 2 928 | } 929 | --------------------------------------------------------------------------------