This commit is contained in:
Alex Gorelov 2018-03-15 14:30:00 +00:00 committed by GitHub
commit 71758031a8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 194 additions and 204 deletions

154
README.md
View file

@ -1,48 +1,43 @@
# Clojure Koans # Clojure Koans
The Clojure Koans are a fun way to get started with Clojure - no experience Для того чтобы приступить к решению Clojure коанов, следуйте инструкциям ниже.
assumed or required. Follow the instructions below to start making tests pass!
## Getting Started ## Установка
I recommend starting from a cloned or forked repo. This way you'll be able to Прежде всего клонируйте репозиторий или создайте свой форк. Далее вы можете создать отдельную ветку
track your progress in Git. You might want to create your own branch - that way чтобы избежать конфликтов при обновлении коанов.
if you pull back the latest koans from master, it'll be a bit easier to manage
the inevitable conflicts if we make changes to exercises you've already
completed.
You have a few options for installation: Способы установки зависимостей:
- Install the dependencies for the koans (such as Clojure) on your machine - Установите все зависимости локально
- Use Vagrant and the configuration in this repository - Используйте Vagrant
- Use Docker - Используйте Docker
Instructions for each option are below! Инструкции для каждого для реализации каждого способа ниже.
### Installation on Your Machine ### Локальная установка
The only things you'll need to run the Clojure Koans are: Вам необходимо:
- JDK (I suggest version 8, but anything 6 or above should work fine) - JDK (от 6 до 8 версии)
- [Leiningen](http://github.com/technomancy/leiningen), a build tool for Clojure - [Leiningen](http://github.com/technomancy/leiningen), инструмент сборки для Clojure
Once you've cloned this repo and installed the dependencies, you can run: После этого выполните в клонированной папке:
``` ```
lein repl lein repl
``` ```
to make sure all the dependencies get downloaded properly (and then `(exit)` Leiningen скачает все зависимости, затем наберите `(exit)` чтобы выйти.
when you want to quit). See below for details on the REPL.
### Installation with Vagrant ### Установка, используя Vagrant
Make sure you have [Vagrant](https://www.vagrantup.com/) and Установите [Vagrant](https://www.vagrantup.com/) и
[VirtualBox](https://www.virtualbox.org) installed. [VirtualBox](https://www.virtualbox.org).
In the root directory of the project, execute: В корневой директории выполните:
``` ```
vagrant up vagrant up
@ -52,39 +47,38 @@ lein koan run
``` ```
### Installation with Docker ### Установка, используя Docker
Once you've got [Docker](https://www.docker.com/) installed, you're basically Установите [Docker](https://www.docker.com/), затем выполните:
all set. You can run these commands to get started:
To run koans: для запуска коанов:
``` ```
docker run --rm -it -v $(pwd):/app -w /app clojure lein koan run docker run --rm -it -v $(pwd):/app -w /app clojure lein koan run
``` ```
To start up a REPL: для запуска REPL:
``` ```
docker run --rm -it -v $(pwd):/app -w /app clojure lein repl docker run --rm -it -v $(pwd):/app -w /app clojure lein repl
``` ```
## Running the Koans ## Запуск коанов
Run the koans via: Команда:
`lein koan run` `lein koan run`
If want to run directly from a REPL, once you are inside the `lein repl` prompt you can run the koans with Для запуска из REPL:
`(exec "run")` `(exec "run")`
Either way, it's an auto-runner, so as you save your files with the correct В любом случае программа запустится и будет ожидать сохранения файла с коанами
answers, it will advance you to the next koan or file (conveniently, all files и даст вам знать правильно ли было решение или нет.
are prefixed with the sequence that you should follow). Каждый коан сопровождён указаниями и направляющими вопросами.
You'll see something like this: Пример:
Now meditate on /home/colin/Projects/clojure-koans/src/koans/01_equalities.clj:3 Now meditate on /home/colin/Projects/clojure-koans/src/koans/01_equalities.clj:3
--------------------- ---------------------
@ -92,36 +86,33 @@ You'll see something like this:
We shall contemplate truth by testing reality, via equality. We shall contemplate truth by testing reality, via equality.
(= __ true) (= __ true)
The output is telling you that you have a failing test in the file named Программа сообщает вам о том, что в файле `01_equalities.clj`, строка 3 тест не пройден
`01_equalities.clj`, on line 3. So you need to open that file up and make и коан не решён. Подумайте и внесите изменения!
it pass! You'll always be filling in the blanks to make tests pass. Вам всегда будет предложено заполнить пустое место, обозначенное символами подчёркивания.
Sometimes there could be several correct answers (or even an infinite number): Иногда способов решения несколько, некоторые тесты успешно пройдут даже при замене символов подчёркивания
any of them will work in these cases. Some tests will pass even if you replace на пробел.
the blanks with whitespace (or nothing) instead of the expected answer. Make sure
you give one correct expression to replace each blank.
The koans differ from normal TDD in that the tests are already written for you, Коаны отличаются от TDD, т.к. тесты уже написаны за вас.
so you'll have to pay close attention to the failure messages, because up until Следите за сообщениями о непройденном тесте — они будут появляться вплоть до решения всех коанов.
the very end, making a test pass means that the next failure message comes Соответственно при прохождении одного коана, вы увидите собщение об ошибке при прохождении следующего,
up. ещё не решённого вами коана. Вы решаете следующий и так далее, пока не решите последний.
While it might be easy (especially at first) to fill in the blanks making Постарайтесь обдумывать ваше решение и вполне понимать почему правильный ответ именно таков.
things pass, you should work thoughtfully, making sure you understand why the Наслаждайтесь вашим путём к Clojure-просветлению!
answer is what it is. Enjoy your path to Clojure enlightenment!
## Trying more things out ## Используйте REPL
It's very useful to try things out in a REPL (Read-Evaluate-Print Loop) Помимо коанов, практикуйтесь и читайте документацию используя интерактивную командную строку:
whenever you get stuck or curious. Run:
``` ```
lein repl lein repl
``` ```
and you'll be able to type expressions in, and see what output they produce. Вводите выражения и программа будет сразу выводить результат — это очень удобно и
ускоряет изучение языка.
Here are some interesting commands you might try, once you're in a running REPL: Попробуйте ввести эти команды:
```clojure ```clojure
(find-doc "vec") (find-doc "vec")
@ -129,55 +120,54 @@ Here are some interesting commands you might try, once you're in a running REPL:
(doc vec) (doc vec)
``` ```
And if those still don't make sense: И эти:
```clojure ```clojure
(doc doc) (doc doc)
(doc find-doc) (doc find-doc)
``` ```
will show you what those commands mean. Для окончания работы с REPL используйте `CTRL-d`, `(exit)`, или `(quit)`.
You can exit the REPL with `CTRL-d`, `(exit)`, or `(quit)`.
## Contributing ## Развитие
Patches are encouraged! Make sure the answer sheet still passes Убедитесь, что (`lein koan test`) пройдены и присылайте патчи в pull request.
(`lein koan test`), and send a pull request.
The file ideaboard.txt has lots of good ideas for new koans to start, or things Файл ideaboard.txt содержит различные идеи для реализации новых или изменения текущих коанов.
to add to existing koans. So write some fun exercises, add your answers to Ответы на упражнения пишите в `resources/koans.clj`!
`resources/koans.clj`, and we'll get them in there!
Please follow the guidelines in Следуйте эти рекомендациям
http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html for http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html.
commmit messages, and put your code in a feature branch (not master) before Для упрощения оценки ваших патчей, — сохраняйте код в feature ветку (не master) перед pull request.
making the pull request. This makes patches easier to review.
Feel free to contact me (Colin Jones / trptcolin) on Github or elsewhere if you Если у вас остались вопросы или нужны рекомендации,
have any questions or want more direction before you start pitching in. связывайтесь со мной (Colin Jones / trptcolin) через Github или иным способом.
## Contributors ## Участники
https://github.com/functional-koans/clojure-koans/contributors https://github.com/functional-koans/clojure-koans/contributors
## Credits ### Перевод на русский язык
These exercises were started by [Aaron Bedra](http://github.com/abedra) of [Alex Gorelov](https://github.com/brannx)
[Relevance, Inc.](http://github.com/relevance) in early 2010, as a learning
tool for newcomers to functional programming. Aaron's macro-fu makes these
koans clear and fun to use and improve upon, and without Relevance's
initiative, this project would not exist.
Using the [koans](http://en.wikipedia.org/wiki/koan) metaphor as a tool for ## Благодарность
learning a programming language started with the
[Ruby Koans](http://rubykoans.com) by [EdgeCase](http://github.com/edgecase). Эти упражнения создавались [Aaron Bedra](http://github.com/abedra)
[Relevance, Inc.](http://github.com/relevance) в начале 2010 как инструмент
для изучения функционального программирования для новичков.
Макрос-фу Аарона делали эти коаны доступными для использования и изучения языка,
а также для их дальнейшей разработки и улучшения.
Без инициативы со стороны Relevance Inc. этот проект не был бы осуществлён.
Использование впервые [коанов](http://en.wikipedia.org/wiki/koan) в качестве метафоры
для обучающих упражнений было заслугой [Ruby Koans](http://rubykoans.com) от [EdgeCase](http://github.com/edgecase).
## License ## Лицензия
The use and distribution terms for this software are covered by the The use and distribution terms for this software are covered by the
Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)

View file

@ -2,38 +2,38 @@
(:require [koan-engine.core :refer :all])) (:require [koan-engine.core :refer :all]))
(meditations (meditations
"We shall contemplate truth by testing reality, via equality" "Критерием истины является тест на равенство"
(= __ true) (= __ true)
"To understand reality, we must compare our expectations against reality" "Проверять истинность нужно сравнением исходного с предположением"
(= __ (+ 1 1)) (= __ (+ 1 1))
"You can test equality of many things" "Тестировать на равенство можно многое"
(= (+ 3 4) 7 (+ 2 __)) (= (+ 3 4) 7 (+ 2 __))
"Some things may appear different, but be the same" "Что-то может показаться отличным, но оставаться равным"
(= __ (= 2 2/1)) (= __ (= 2 2/1))
"You cannot generally float to heavens of integers" "Целое не равно дробному"
(= __ (= 2 2.0)) (= __ (= 2 2.0))
"But a looser equality is also possible" "Хотя может быть равнозначно"
(= __ (== 2.0 2)) (= __ (== 2.0 2))
"Something is not equal to nothing" "Ничто не равно чему-либо"
(= __ (not (= 1 nil))) (= __ (not (= 1 nil)))
"Strings, and keywords, and symbols: oh my!" "Строки, ключи, символы!!!"
(= __ (= "hello" :hello 'hello)) (= __ (= "hello" :hello 'hello))
"Make a keyword with your keyboard" "Создавайте ключевые слова используя обычные"
(= :hello (keyword __)) (= :hello (keyword __))
"Symbolism is all around us" "Кругом символизм"
(= 'hello (symbol __)) (= 'hello (symbol __))
"What could be equivalent to nothing?" "Так чему же равно ничто?"
(= __ nil) (= __ nil)
"When things cannot be equal, they must be different" "Разное не равно"
(not= :fill-in-the-blank __)) (not= :fill-in-the-blank __))

View file

@ -3,68 +3,68 @@
[clojure.string :as string])) [clojure.string :as string]))
(meditations (meditations
"A string is nothing more than text surrounded by double quotes" "Строка — это текст, обрамлённый двойными кавычками"
(= __ "hello") (= __ "hello")
"But double quotes are just magic on top of something deeper" "Но это лишь вершина айсберга"
(= __ (str 'world)) (= __ (str 'world))
"You can do more than create strings, you can put them together" "Создавая одну строку можно объединением нескольких"
(= "Cool right?" (str __ __)) (= "Cool right?" (str __ __))
"You can even get certain characters" "Можно получить символьный литерал"
(= \C (get "Characters" __)) (= \C (get "Characters" __))
"Or even count the characters" "Сосчитать сколько их"
(= __ (count "Hello World")) (= __ (count "Hello World"))
"But strings and characters are not the same" "Но он — не строка"
(= __ (= \c "c")) (= __ (= \c "c"))
"What if you only wanted to get part of a string?" "А что если нужна лишь часть строки?"
(= "World" (subs "Hello World" __ __)) (= "World" (subs "Hello World" __ __))
"How about joining together elements in a list?" "Объединяем элементы в строку"
(= __ (string/join '(1 2 3))) (= __ (string/join '(1 2 3)))
"What if you wanted to separate them out?" "Объединяем, но разделяя между собой"
(= "1, 2, 3" (string/join __ '(1 2 3))) (= "1, 2, 3" (string/join __ '(1 2 3)))
"Maybe you want to separate out all your lines" "Можно разделить построчно"
(= [__ __ __] (string/split-lines "1\n2\n3")) (= [__ __ __] (string/split-lines "1\n2\n3"))
"You may want to make sure your words are backwards" "Можно инвертировать"
(= __ (string/reverse "hello")) (= __ (string/reverse "hello"))
"Maybe you want to find the index of the first occurrence of a substring" "Можно найти индекс первого совпадения"
(= 0 (string/index-of "hello world" __)) (= 0 (string/index-of "hello world" __))
"Or maybe the last index of the same" "Или последнего"
(= __ (string/last-index-of "hello world, hello" "hello")) (= __ (string/last-index-of "hello world, hello" "hello"))
"But when something doesn't exist, nothing is found" "А если ничто не совпало, то что мы получим?"
(= __ (string/index-of "hello world" "bob")) (= __ (string/index-of "hello world" "bob"))
"Sometimes you don't want whitespace cluttering the front and back" "Иногда неплохо бы избавиться от пробелов"
(= __ (string/trim " \nhello world \t \n")) (= __ (string/trim " \nhello world \t \n"))
"You can check if something is a char" "Тест на символьный литерал"
(= __ (char? \c)) (= __ (char? \c))
"But it may not be" "Тут точно не пройдёт"
(= __ (char? "a")) (= __ (char? "a"))
"But chars aren't strings" "«Чары» — они не строки"
(= __ (string? \b)) (= __ (string? \b))
"Strings are strings" "А строки — строки"
(= true (string? __)) (= true (string? __))
"Some strings may be blank" "Иногда и пустые"
(= __ (string/blank? "")) (= __ (string/blank? ""))
"Even if at first glance they aren't" "Хотя на первый взгляд и не скажешь"
(= __ (string/blank? " \n \t ")) (= __ (string/blank? " \n \t "))
"However, most strings aren't blank" "Всё же большинство строк не пусты"
(= __ (string/blank? "hello?\nare you out there?"))) (= __ (string/blank? "hello?\nare you out there?")))

View file

@ -2,43 +2,43 @@
(:require [koan-engine.core :refer :all])) (:require [koan-engine.core :refer :all]))
(meditations (meditations
"Lists can be expressed by function or a quoted form" "Списки создаются фукцией или кавычкой"
(= '(__ __ __ __ __) (list 1 2 3 4 5)) (= '(__ __ __ __ __) (list 1 2 3 4 5))
"They are Clojure seqs (sequences), so they allow access to the first" "Они являются Clojure seqs (последовательностями); можно получить первый элемент"
(= __ (first '(1 2 3 4 5))) (= __ (first '(1 2 3 4 5)))
"As well as the rest" "И остальные, кроме первого"
(= __ (rest '(1 2 3 4 5))) (= __ (rest '(1 2 3 4 5)))
"Count your blessings" "Сосчитай словечки"
(= __ (count '(dracula dooku chocula))) (= __ (count '(dracula dooku chocula)))
"Before they are gone" "Ну, если они есть…"
(= __ (count '())) (= __ (count '()))
"The rest, when nothing is left, is empty" "Когда ничего кроме списка не осталось, что получаем?"
(= __ (rest '(100))) (= __ (rest '(100)))
"Construction by adding an element to the front is easy" "Создаём новый список добавляя элемент в начало списка"
(= __ (cons :a '(:b :c :d :e))) (= __ (cons :a '(:b :c :d :e)))
"Conjoining an element to a list isn't hard either" "Соединяем список и элемент — получаем новый список"
(= __ (conj '(:a :b :c :d) :e)) (= __ (conj '(:a :b :c :d) :e))
"You can use a list like a stack to get the first element" "Список — он как стек, берём с вершины"
(= __ (peek '(:a :b :c :d :e))) (= __ (peek '(:a :b :c :d :e)))
"Or the others" "Или всё остальное"
(= __ (pop '(:a :b :c :d :e))) (= __ (pop '(:a :b :c :d :e)))
"But watch out if you try to pop nothing" "А когда остального то и нет! Исключение!"
(= __ (try (= __ (try
(pop '()) (pop '())
(catch IllegalStateException e (catch IllegalStateException e
"No dice!"))) "No dice!")))
"The rest of nothing isn't so strict" "Но не для этой функции. Раз элементов нет, вернёт хоть список"
(= __ (try (= __ (try
(rest '()) (rest '())
(catch IllegalStateException e (catch IllegalStateException e

View file

@ -2,32 +2,32 @@
(:require [koan-engine.core :refer :all])) (:require [koan-engine.core :refer :all]))
(meditations (meditations
"You can use vectors in clojure as array-like structures" "Векторы в Clojure похожи на массивы"
(= __ (count [42])) (= __ (count [42]))
"You can create a vector from a list" "Можно их содать из списка"
(= __ (vec '(1))) (= __ (vec '(1)))
"Or from some elements" "Или из ничего"
(= __ (vector nil nil)) (= __ (vector nil nil))
"But you can populate it with any number of elements at once" "Число элементов — ваше дело"
(= [1 __] (vec '(1 2))) (= [1 __] (vec '(1 2)))
"Conjoining to a vector is different than to a list" "Добавляем элемент, помним что вектор «похож» на массив"
(= __ (conj [111 222] 333)) (= __ (conj [111 222] 333))
"You can get the first element of a vector like so" "Получаем первый элемент"
(= __ (first [:peanut :butter :and :jelly])) (= __ (first [:peanut :butter :and :jelly]))
"And the last in a similar fashion" "Последний элемент"
(= __ (last [:peanut :butter :and :jelly])) (= __ (last [:peanut :butter :and :jelly]))
"Or any index if you wish" "Да какой угодно элемент"
(= __ (nth [:peanut :butter :and :jelly] 3)) (= __ (nth [:peanut :butter :and :jelly] 3))
"You can also slice a vector" "Нарезаем вектор"
(= __ (subvec [:peanut :butter :and :jelly] 1 3)) (= __ (subvec [:peanut :butter :and :jelly] 1 3))
"Equality with collections is in terms of values" "Коллекции сравниваются по их элементам"
(= (list 1 2 3) (vector 1 2 __))) (= (list 1 2 3) (vector 1 2 __)))

View file

@ -3,20 +3,20 @@
[clojure.set :as set])) [clojure.set :as set]))
(meditations (meditations
"You can create a set by converting another collection" "Создаём множество из другой коллекции"
(= #{3} (set __)) (= #{3} (set __))
"Counting them is like counting other collections" "Считаем как обычно"
(= __ (count #{1 2 3})) (= __ (count #{1 2 3}))
"Remember that a set is a *mathematical* set" "Множество — оно математическое"
(= __ (set '(1 1 2 2 3 3 4 4 5 5))) (= __ (set '(1 1 2 2 3 3 4 4 5 5)))
"You can ask clojure for the union of two sets" "Объединение"
(= __ (set/union #{1 2 3 4} #{2 3 5})) (= __ (set/union #{1 2 3 4} #{2 3 5}))
"And also the intersection" "Пересечение"
(= __ (set/intersection #{1 2 3 4} #{2 3 5})) (= __ (set/intersection #{1 2 3 4} #{2 3 5}))
"But don't forget about the difference" "Разность"
(= __ (set/difference #{1 2 3 4 5} #{2 3 5}))) (= __ (set/difference #{1 2 3 4 5} #{2 3 5})))

View file

@ -2,60 +2,60 @@
(:require [koan-engine.core :refer :all])) (:require [koan-engine.core :refer :all]))
(meditations (meditations
"Don't get lost when creating a map" "Не потеряйтесь при создании хэш-карты"
(= {:a 1 :b 2} (hash-map :a 1 __ __)) (= {:a 1 :b 2} (hash-map :a 1 __ __))
"A value must be supplied for each key" "Каждому ключу — значение"
(= {:a 1} (hash-map :a __)) (= {:a 1} (hash-map :a __))
"The size is the number of entries" "Размер определяется числом пар"
(= __ (count {:a 1 :b 2})) (= __ (count {:a 1 :b 2}))
"You can look up the value for a given key" "Узнать значение можно по ключу"
(= __ (get {:a 1 :b 2} :b)) (= __ (get {:a 1 :b 2} :b))
"Maps can be used as functions to do lookups" "Прямо как функции"
(= __ ({:a 1 :b 2} :a)) (= __ ({:a 1 :b 2} :a))
"And so can keywords" "И ключи тоже"
(= __ (:a {:a 1 :b 2})) (= __ (:a {:a 1 :b 2}))
"But map keys need not be keywords" "Ключи — не обязательно ключевые слова"
(= __ ({2010 "Vancouver" 2014 "Sochi" 2018 "PyeongChang"} 2014)) (= __ ({2010 "Vancouver" 2014 "Sochi" 2018 "PyeongChang"} 2014))
"You may not be able to find an entry for a key" "Иногда — ни ключа, ни значения"
(= __ (get {:a 1 :b 2} :c)) (= __ (get {:a 1 :b 2} :c))
"But you can provide your own default" "На такой случай можно задать что-нибудь на свой вкус"
(= __ (get {:a 1 :b 2} :c :key-not-found)) (= __ (get {:a 1 :b 2} :c :key-not-found))
"You can find out if a key is present" "Есть ли ключ?"
(= __ (contains? {:a nil :b nil} :b)) (= __ (contains? {:a nil :b nil} :b))
"Or if it is missing" "Или нет"
(= __ (contains? {:a nil :b nil} :c)) (= __ (contains? {:a nil :b nil} :c))
"Maps are immutable, but you can create a new and improved version" "Отображения неизменяемы — с новыми элементами только новые отображения"
(= {1 "January" 2 __} (assoc {1 "January"} 2 "February")) (= {1 "January" 2 __} (assoc {1 "January"} 2 "February"))
"You can also create a new version with an entry removed" "И при удалении элементов возвращается новое отображение"
(= {__ __} (dissoc {1 "January" 2 "February"} 2)) (= {__ __} (dissoc {1 "January" 2 "February"} 2))
"Create a new map by merging" "И при совмещении"
(= {:a 1 :b 2 __ __} (merge {:a 1 :b 2} {:c 3})) (= {:a 1 :b 2 __ __} (merge {:a 1 :b 2} {:c 3}))
"Specify how to handle entries with same keys when merging" "Можно указать как быть со значениями идентичных ключей"
(= {:a 1 :b __ :c 3} (merge-with + {:a 1 :b 1} {:b 1 :c 3})) (= {:a 1 :b __ :c 3} (merge-with + {:a 1 :b 1} {:b 1 :c 3}))
"Often you will need to get the keys, but the order is undependable" "Внутри ничего не сортируется. Сортировка по ключам"
(= (list __ __ __) (= (list __ __ __)
(sort (keys { 2014 "Sochi" 2018 "PyeongChang" 2010 "Vancouver"}))) (sort (keys { 2014 "Sochi" 2018 "PyeongChang" 2010 "Vancouver"})))
"You can get the values in a similar way" "По значениям"
(= (list __ __ __) (= (list __ __ __)
(sort (vals {2010 "Vancouver" 2014 "Sochi" 2018 "PyeongChang"}))) (sort (vals {2010 "Vancouver" 2014 "Sochi" 2018 "PyeongChang"})))
"You can even iterate over the map entries as a seq" "Ключ и значение идут друг за другом"
(= {:a __ :b __} (= {:a __ :b __}
(into {} (into {}
(map (map

View file

@ -7,34 +7,34 @@
(defn square [n] (* n n)) (defn square [n] (* n n))
(meditations (meditations
"Calling a function is like giving it a hug with parentheses" "Вызываем функцию «обнимая» её скобками"
(= __ (square 9)) (= __ (square 9))
"Functions are usually defined before they are used" "Сначала нужно её создать"
(= __ (multiply-by-ten 2)) (= __ (multiply-by-ten 2))
"But they can also be defined inline" "Или использовать анонимную"
(= __ ((fn [n] (* 5 n)) 2)) (= __ ((fn [n] (* 5 n)) 2))
"Or using an even shorter syntax" "Clojure упрощает жизнь и запись анонимных функций"
(= __ (#(* 15 %) 4)) (= __ (#(* 15 %) 4))
"Even anonymous functions may take multiple arguments" "Аргументов — сколько угодно!"
(= __ (#(+ %1 %2 %3) 4 5 6)) (= __ (#(+ %1 %2 %3) 4 5 6))
"Arguments can also be skipped" "Их даже можно не учитывать"
(= __ (#(str "AA" %2) "bb" "CC")) (= __ (#(str "AA" %2) "bb" "CC"))
"One function can beget another" "Функция может возвращать функцию"
(= 9 (((fn [] ___)) 4 5)) (= 9 (((fn [] ___)) 4 5))
"Functions can also take other functions as input" "Может принимать её в качестве аргумента"
(= 20 ((fn [f] (f 4 5)) (= 20 ((fn [f] (f 4 5))
___)) ___))
"Higher-order functions take function arguments" "Функции высшего порядка так и делают"
(= 25 (___ (= 25 (___
(fn [n] (* n n)))) (fn [n] (* n n))))
"But they are often better written using the names of functions" "Хотя, иногда неплохо создать функцию заранее, а не создавать анонимную"
(= 25 (___ square))) (= 25 (___ square)))

View file

@ -9,39 +9,39 @@
"is that even exercise?")) "is that even exercise?"))
(meditations (meditations
"You will face many decisions" "Нужно принимать решения"
(= __ (if (false? (= 4 5)) (= __ (if (false? (= 4 5))
:a :a
:b)) :b))
"Some of them leave you no alternative" "Иногда альтернативы нет"
(= __ (if (> 4 3) (= __ (if (> 4 3)
[])) []))
"And in such a situation you may have nothing" "И вы ничего не получаете"
(= __ (if (nil? 0) (= __ (if (nil? 0)
[:a :b :c])) [:a :b :c]))
"In others your alternative may be interesting" "Иногда выбор есть"
(= :glory (if (not (empty? ())) (= :glory (if (not (empty? ()))
:doom :doom
__)) __))
"You may have a multitude of possible paths" "И вариантов много"
(let [x 5] (let [x 5]
(= :your-road (cond (= x __) :road-not-taken (= :your-road (cond (= x __) :road-not-taken
(= x __) :another-road-not-taken (= x __) :another-road-not-taken
:else __))) :else __)))
"Or your fate may be sealed" "Получаем doom"
(= 'doom (if-not (zero? __) (= 'doom (if-not (zero? __)
'doom 'doom
'more-doom)) 'more-doom))
"In case of emergency, go fast" "Выбирать можно и так"
(= "pretty fast" (= "pretty fast"
(explain-exercise-velocity __)) (explain-exercise-velocity __))
"But admit it when you don't know what to do" "Можно задавать ответ по-умолчанию"
(= __ (= __
(explain-exercise-velocity :watching-tv))) (explain-exercise-velocity :watching-tv)))

View file

@ -2,34 +2,34 @@
(:require [koan-engine.core :refer :all])) (:require [koan-engine.core :refer :all]))
(meditations (meditations
"The map function relates a sequence to another" "Создаём номую последовательность изменяя данную"
(= [__ __ __] (map (fn [x] (* 4 x)) [1 2 3])) (= [__ __ __] (map (fn [x] (* 4 x)) [1 2 3]))
"You may create that mapping" "Изменяйте, создаваю свои функции"
(= [1 4 9 16 25] (map (fn [x] __) [1 2 3 4 5])) (= [1 4 9 16 25] (map (fn [x] __) [1 2 3 4 5]))
"Or use the names of existing functions" "Или используйте существующие"
(= __ (map nil? [:a :b nil :c :d])) (= __ (map nil? [:a :b nil :c :d]))
"A filter can be strong" "Такой фильтр не пропустит ничего"
(= __ (filter (fn [x] false) '(:anything :goes :here))) (= __ (filter (fn [x] false) '(:anything :goes :here)))
"Or very weak" "А такой?"
(= __ (filter (fn [x] true) '(:anything :goes :here))) (= __ (filter (fn [x] true) '(:anything :goes :here)))
"Or somewhere in between" "Какой фильтр здесь?"
(= [10 20 30] (filter (fn [x] __) [10 20 30 40 50 60 70 80])) (= [10 20 30] (filter (fn [x] __) [10 20 30 40 50 60 70 80]))
"Maps and filters may be combined" "Сначала фильтруем, потом изменяем полученное"
(= [10 20 30] (map (fn [x] __) (filter (fn [x] __) [1 2 3 4 5 6 7 8]))) (= [10 20 30] (map (fn [x] __) (filter (fn [x] __) [1 2 3 4 5 6 7 8])))
"Reducing can increase the result" "Уменьшаем объём, увеличиваем значение"
(= __ (reduce (fn [a b] (* a b)) [1 2 3 4])) (= __ (reduce (fn [a b] (* a b)) [1 2 3 4]))
"You can start somewhere else" "Можно указать начальное значение"
(= 2400 (reduce (fn [a b] (* a b)) __ [1 2 3 4])) (= 2400 (reduce (fn [a b] (* a b)) __ [1 2 3 4]))
"Numbers are not the only things one can reduce" "Не только числа"
(= "longest" (reduce (fn [a b] (= "longest" (reduce (fn [a b]
(if (< __ __) b a)) (if (< __ __) b a))
["which" "word" "is" "longest"]))) ["which" "word" "is" "longest"])))

View file

@ -15,28 +15,28 @@
(defmethod diet :default [a] __) (defmethod diet :default [a] __)
(meditations (meditations
"Some functions can be used in different ways - with no arguments" "Полиморфизм. Без аргументов."
(= __ (hello)) (= __ (hello))
"With one argument" "Один аргумент"
(= __ (hello "world")) (= __ (hello "world"))
"Or with many arguments" "Тысячи их"
(= __ (= __
(hello "Peter" "Paul" "Mary")) (hello "Peter" "Paul" "Mary"))
"Multimethods allow more complex dispatching" "Мультиметоды и диспетчеризация. Всё просто."
(= "Bambi eats veggies." (= "Bambi eats veggies."
(diet {:species "deer" :name "Bambi" :age 1 :eater :herbivore})) (diet {:species "deer" :name "Bambi" :age 1 :eater :herbivore}))
"Animals have different names" "Имена разные"
(= "Thumper eats veggies." (= "Thumper eats veggies."
(diet {:species "rabbit" :name "Thumper" :age 1 :eater :herbivore})) (diet {:species "rabbit" :name "Thumper" :age 1 :eater :herbivore}))
"Different methods are used depending on the dispatch function result" "Разные методы исходя из вывода"
(= "Simba eats animals." (= "Simba eats animals."
(diet {:species "lion" :name "Simba" :age 1 :eater :carnivore})) (diet {:species "lion" :name "Simba" :age 1 :eater :carnivore}))
"You may use a default method when no others match" "Традиционно, есть и метод по-умолчанию"
(= "I don't know what Rich Hickey eats." (= "I don't know what Rich Hickey eats."
(diet {:name "Rich Hickey"}))) (diet {:name "Rich Hickey"})))

View file

@ -2,27 +2,27 @@
(:require [koan-engine.core :refer :all])) (:require [koan-engine.core :refer :all]))
(meditations (meditations
"There are many ways to generate a sequence" "Создаём последовательность"
(= __ (range 1 5)) (= __ (range 1 5))
"The range starts at the beginning by default" "От нуля до …"
(= __ (range 5)) (= __ (range 5))
"Only take what you need when the sequence is large" "Ленивые вычисления — взять только то что надо"
(= [0 1 2 3 4 5 6 7 8 9] (= [0 1 2 3 4 5 6 7 8 9]
(take __ (range 100))) (take __ (range 100)))
"Or limit results by dropping what you don't need" "Не брать того что не нужно, да и не хочется"
(= [95 96 97 98 99] (= [95 96 97 98 99]
(drop __ (range 100))) (drop __ (range 100)))
"Iteration provides an infinite lazy sequence" "Если не указать сколько взять, можно переполнить стек. Такая функция."
(= __ (take 8 (iterate (fn [x] (* x 2)) 1))) (= __ (take 8 (iterate (fn [x] (* x 2)) 1)))
"Repetition is key" "Повтор"
(= [:a :a :a :a :a :a :a :a :a :a] (= [:a :a :a :a :a :a :a :a :a :a]
(repeat 10 __)) (repeat 10 __))
"Iteration can be used for repetition" "Результат идентичен"
(= (repeat 100 "hello") (= (repeat 100 "hello")
(take 100 (iterate ___ "hello")))) (take 100 (iterate ___ "hello"))))