summaryrefslogtreecommitdiffhomepage
path: root/ru-ru
diff options
context:
space:
mode:
Diffstat (limited to 'ru-ru')
-rw-r--r--ru-ru/go-ru.html.markdown170
-rw-r--r--ru-ru/haskell-ru.html.markdown546
-rw-r--r--ru-ru/julia-ru.html.markdown318
3 files changed, 805 insertions, 229 deletions
diff --git a/ru-ru/go-ru.html.markdown b/ru-ru/go-ru.html.markdown
index e9892952..ffda01b7 100644
--- a/ru-ru/go-ru.html.markdown
+++ b/ru-ru/go-ru.html.markdown
@@ -3,8 +3,12 @@ language: Go
filename: learngo-ru.go
contributors:
- ["Sonia Keys", "https://github.com/soniakeys"]
+ - ["Christopher Bess", "https://github.com/cbess"]
+ - ["Jesse Johnson", "https://github.com/holocronweaver"]
+ - ["Quint Guvernator", "https://github.com/qguv"]
translators:
- ["Artem Medeusheyev", "https://github.com/armed"]
+ - ["Valery Cherepanov", "https://github.com/qumeric"]
lang: ru-ru
---
@@ -31,8 +35,9 @@ package main
// Import предназначен для указания зависимостей этого файла.
import (
"fmt" // Пакет в стандартной библиотеке Go
- "net/http" // Да, это web server!
+ "net/http" // Да, это веб-сервер!
"strconv" // Конвертирование типов в строки и обратно
+ m "math" // Импортировать math под локальным именем m.
)
// Объявление функции. Main это специальная функция, служащая точкой входа для
@@ -40,7 +45,7 @@ import (
// скобки.
func main() {
// Println выводит строку в stdout.
- // В данном случае фигурирует вызов функции из пакета fmt.
+ // Данная функция находится в пакете fmt.
fmt.Println("Hello world!")
// Вызов другой функции из текущего пакета.
@@ -55,57 +60,57 @@ func beyondHello() {
// Краткое определение := позволяет объявить перменную с автоматической
// подстановкой типа из значения.
y := 4
- sum, prod := learnMultiple(x, y) // функция возвращает два значения
- fmt.Println("sum:", sum, "prod:", prod) // простой вывод
+ sum, prod := learnMultiple(x, y) // Функция возвращает два значения.
+ fmt.Println("sum:", sum, "prod:", prod) // Простой вывод.
learnTypes() // < y minutes, learn more!
}
// Функция имеющая входные параметры и возврат нескольких значений.
func learnMultiple(x, y int) (sum, prod int) {
- return x + y, x * y // возврат двух результатов
+ return x + y, x * y // Возврат двух значений.
}
// Некотрые встроенные типы и литералы.
func learnTypes() {
// Краткое определение переменной говорит само за себя.
- s := "Learn Go!" // тип string
+ s := "Learn Go!" // Тип string.
s2 := `"Чистый" строковой литерал
-может содержать переносы строк` // тоже тип данных string
+может содержать переносы строк` // Тоже тип данных string
- // символ не из ASCII. Исходный код Go в кодировке UTF-8.
- g := 'Σ' // тип rune, это алиас для типа uint32, содержит юникод символ
+ // Символ не из ASCII. Исходный код Go в кодировке UTF-8.
+ g := 'Σ' // тип rune, это алиас для типа uint32, содержит символ юникода.
- f := 3.14195 // float64, 64-х битное число с плавающей точкой (IEEE-754)
- c := 3 + 4i // complex128, внутри себя содержит два float64
+ f := 3.14195 // float64, 64-х битное число с плавающей точкой (IEEE-754).
+ c := 3 + 4i // complex128, внутри себя содержит два float64.
- // Синтаксис var с инициализациями
- var u uint = 7 // беззнаковое, но размер зависит от реализации, как и у int
+ // Синтаксис var с инициализациями.
+ var u uint = 7 // Беззнаковое, но размер зависит от реализации, как и у int.
var pi float32 = 22. / 7
// Синтаксис приведения типа с кратким определением
- n := byte('\n') // byte алиас для uint8
+ n := byte('\n') // byte – это алиас для uint8.
- // Массивы (Array) имеют фиксированный размер на момент компиляции.
- var a4 [4]int // массив из 4-х int, проинициализирован нулями
- a3 := [...]int{3, 1, 5} // массив из 3-х int, ручная инициализация
+ // Массивы имеют фиксированный размер на момент компиляции.
+ var a4 [4]int // массив из 4-х int, инициализирован нулями.
+ a3 := [...]int{3, 1, 5} // массив из 3-х int, ручная инициализация.
- // Slice имеют динамическую длину. И массивы и slice-ы имеют каждый свои
- // преимущества, но slice-ы используются гораздо чаще.
- s3 := []int{4, 5, 9} // по сравнению с a3 тут нет троеточия
- s4 := make([]int, 4) // выделение памяти для slice из 4-х int (нули)
- var d2 [][]float64 // только объявление, память не выделяется
- bs := []byte("a slice") // конвертирование строки в slice байтов
+ // Слайсы (slices) имеют динамическую длину. И массивы, и слайсы имеют свои
+ // преимущества, но слайсы используются гораздо чаще.
+ s3 := []int{4, 5, 9} // Сравните с a3. Тут нет троеточия.
+ s4 := make([]int, 4) // Выделение памяти для слайса из 4-х int (нули).
+ var d2 [][]float64 // Только объявление, память не выделяется.
+ bs := []byte("a slice") // Синтаксис приведения типов.
- p, q := learnMemory() // объявление p и q как указателей на int.
+ p, q := learnMemory() // Объявление p и q как указателей на int.
fmt.Println(*p, *q) // * извлекает указатель. Печатает два int-а.
- // Map как словарь или хеш теблица из других языков является ассоциативным
- // массивом с динамически изменяемым размером.
+ // Map, также как и словарь или хеш из некоторых других языков, является
+ // ассоциативным массивом с динамически изменяемым размером.
m := map[string]int{"three": 3, "four": 4}
m["one"] = 1
- delete(m, "three") // встроенная функция, удаляет элемент из map-а.
+ delete(m, "three") // Встроенная функция, удаляет элемент из map-а.
// Неиспользуемые переменные в Go являются ошибкой.
// Нижнее подчеркивание позволяет игнорировать такие переменные.
@@ -113,79 +118,91 @@ func learnTypes() {
// Вывод считается использованием переменной.
fmt.Println(s, c, a4, s3, d2, m)
- learnFlowControl() // идем далее
+ learnFlowControl() // Идем дальше.
}
// У Go есть полноценный сборщик мусора. В нем есть указатели но нет арифметики
-// указатеей. Вы можете допустить ошибку с указателем на nil, но не с его
-// инкрементацией.
+// указателей. Вы можете допустить ошибку с указателем на nil, но не с
+// инкрементацией указателя.
func learnMemory() (p, q *int) {
// Именованные возвращаемые значения p и q являются указателями на int.
- p = new(int) // встроенная функция new выделяет память.
+ p = new(int) // Встроенная функция new выделяет память.
// Выделенный int проинициализирован нулем, p больше не содержит nil.
- s := make([]int, 20) // Выделение единого блока памяти под 20 int-ов,
- s[3] = 7 // назначение одному из них,
- r := -2 // опредление еще одной локальной переменной,
- return &s[3], &r // амперсанд обозначает получение адреса переменной.
+ s := make([]int, 20) // Выделение единого блока памяти под 20 int-ов.
+ s[3] = 7 // Присвоить значение одному из них.
+ r := -2 // Определить еще одну локальную переменную.
+ return &s[3], &r // Амперсанд(&) обозначает получение адреса переменной.
}
-func expensiveComputation() int {
- return 1e6
+func expensiveComputation() float64 {
+ return m.Exp(10)
}
func learnFlowControl() {
- // If-ы всегда требуют наличине фигурных скобок, но круглые скобки
- // необязательны.
+ // If-ы всегда требуют наличине фигурных скобок, но не круглых.
if true {
fmt.Println("told ya")
}
// Форматирование кода стандартизировано утилитой "go fmt".
if false {
- // все тлен
+ // Будущего нет.
} else {
- // жизнь прекрасна
+ // Жизнь прекрасна.
}
- // Использоване switch на замену нескольким if-else
- x := 1
+ // Используйте switch вместо нескольких if-else.
+ x := 42.0
switch x {
case 0:
case 1:
- // case-ы в Go не проваливаются, т.е. break по умолчанию
- case 2:
- // не выполнится
+ case 42:
+ // Case-ы в Go не "проваливаются" (неявный break).
+ case 43:
+ // Не выполнится.
}
// For, как и if не требует круглых скобок
- for x := 0; x < 3; x++ { // ++ это операция
+ // Переменные, объявленные в for и if являются локальными.
+ for x := 0; x < 3; x++ { // ++ – это операция.
fmt.Println("итерация", x)
}
- // тут x == 1.
+ // Здесь x == 42.
- // For это единственный цикл в Go, но у него несколько форм.
- for { // бесконечный цикл
- break // не такой уж и бесконечный
- continue // не выполнится
+ // For – это единственный цикл в Go, но у него есть альтернативные формы.
+ for { // Бесконечный цикл.
+ break // Не такой уж и бесконечный.
+ continue // Не выполнится.
}
// Как и в for, := в if-е означает объявление и присвоение значения y,
- // затем проверка y > x.
+ // проверка y > x происходит после.
if y := expensiveComputation(); y > x {
x = y
}
// Функции являются замыканиями.
xBig := func() bool {
- return x > 100 // ссылается на x, объявленый выше switch.
+ return x > 10000 // Ссылается на x, объявленый выше switch.
}
- fmt.Println("xBig:", xBig()) // true (т.к. мы присвоили x = 1e6)
- x /= 1e5 // тут х == 10
- fmt.Println("xBig:", xBig()) // теперь false
+ fmt.Println("xBig:", xBig()) // true (т.к. мы присвоили x = e^10).
+ x = 1.3e3 // Тут х == 1300
+ fmt.Println("xBig:", xBig()) // Теперь false.
// Метки, куда же без них, их все любят.
goto love
love:
+ learnDefer() // Быстрый обзор важного ключевого слова.
learnInterfaces() // О! Интерфейсы, идем далее.
}
-// Объявление Stringer как интерфейса с одним мметодом, String.
+func learnDefer() (ok bool) {
+ // Отложенные(deferred) выражения выполняются сразу перед тем, как функция
+ // возвратит значение.
+ defer fmt.Println("deferred statements execute in reverse (LIFO) order.")
+ defer fmt.Println("\nThis line is being printed first because")
+ // defer широко используется для закрытия файлов, чтобы закрывающая файл
+ // функция находилась близко к открывающей.
+ return true
+}
+
+// Объявление Stringer как интерфейса с одним методом, String.
type Stringer interface {
String() string
}
@@ -196,35 +213,48 @@ type pair struct {
}
// Объявление метода для типа pair. Теперь pair реализует интерфейс Stringer.
-func (p pair) String() string { // p в данном случае называют receiver-ом
- // Sprintf - еще одна функция из пакета fmt.
+func (p pair) String() string { // p в данном случае называют receiver-ом.
+ // Sprintf – еще одна функция из пакета fmt.
// Обращение к полям p через точку.
return fmt.Sprintf("(%d, %d)", p.x, p.y)
}
func learnInterfaces() {
// Синтаксис с фигурными скобками это "литерал структуры". Он возвращает
- // проинициализированную структуру, а оператор := присваивает ее в p.
+ // проинициализированную структуру, а оператор := присваивает её p.
p := pair{3, 4}
- fmt.Println(p.String()) // вызов метода String у p, типа pair.
- var i Stringer // объявление i как типа с интерфейсом Stringer.
- i = p // валидно, т.к. pair реализует Stringer.
- // Вызов метода String у i, типа Stringer. Вывод такой же что и выше.
+ fmt.Println(p.String()) // Вызов метода String у переменной p типа pair.
+ var i Stringer // Объявление i как типа с интерфейсом Stringer.
+ i = p // Валидно, т.к. pair реализует Stringer.
+ // Вызов метода String у i типа Stringer. Вывод такой же, что и выше.
fmt.Println(i.String())
// Функции в пакете fmt сами всегда вызывают метод String у объектов для
// получения строкового представления о них.
- fmt.Println(p) // Вывод такой же что и выше. Println вызывает метод String.
- fmt.Println(i) // тоже самое
+ fmt.Println(p) // Вывод такой же, что и выше. Println вызывает метод String.
+ fmt.Println(i) // Вывод такой же, что и выше.
+
+ learnVariadicParams("Учиться", "учиться", "и еще раз учиться!")
+}
+
+// Функции могут иметь варьируемое количество параметров.
+func learnVariadicParams(myStrings ...interface{}) {
+ // Вывести все параметры с помощью итерации.
+ for _, param := range myStrings {
+ fmt.Println("param:", param)
+ }
+
+ // Передать все варьируемые параметры.
+ fmt.Println("params:", fmt.Sprintln(myStrings...))
learnErrorHandling()
}
func learnErrorHandling() {
- // Идиома ", ok" служит для обозначения сработало что-то или нет.
+ // Идиома ", ok" служит для обозначения корректного срабатывания чего-либо.
m := map[int]string{3: "three", 4: "four"}
if x, ok := m[1]; !ok { // ok будет false, потому что 1 нет в map-е.
- fmt.Println("тут никого")
+ fmt.Println("тут никого нет")
} else {
fmt.Print(x) // x содержал бы значение, если бы 1 был в map-е.
}
@@ -237,7 +267,7 @@ func learnErrorHandling() {
learnConcurrency()
}
-// c это тип данных channel (канал), объект для конкуррентного взаимодействия.
+// c – это тип данных channel (канал), объект для конкуррентного взаимодействия.
func inc(i int, c chan int) {
c <- i + 1 // когда channel слева, <- являтся оператором "отправки".
}
diff --git a/ru-ru/haskell-ru.html.markdown b/ru-ru/haskell-ru.html.markdown
new file mode 100644
index 00000000..03e66d05
--- /dev/null
+++ b/ru-ru/haskell-ru.html.markdown
@@ -0,0 +1,546 @@
+---
+language: haskell
+contributors:
+ - ["Adit Bhargava", "http://adit.io"]
+translators:
+ - ["Aleksey Pirogov", "http://astynax.github.io"]
+lang: ru-ru
+---
+
+Haskell разрабатывался, как чистый функциональный язык программирования, применимый на практике. Язык известен благодаря своей системе типов, и "знаменит" благодаря монадам. [Меня][autor] же Haskell заставляет возвращаться к себе снова и снова именно своей элегантностью и [я][autor] получаю истинное удовольствие, программируя на Haskell.
+
+```haskell
+-- Однострочные комментарии начинаются с двух дефисов
+{- Многострочный комментарий
+заключается в пару фигурных скобок с дефисами с внутренней стороны.
+-}
+
+-------------------------------------------------------
+-- 1. Примитивные типы и простейшие операции над ними
+-------------------------------------------------------
+
+-- Числа объявляются просто
+3 -- 3
+
+-- Арифметика тоже выглядит вполне ожидаемо
+1 + 1 -- 2
+8 - 1 -- 7
+10 * 2 -- 20
+35 / 5 -- 7.0
+
+-- Операция деления всегда возвращает действительное число
+35 / 4 -- 8.75
+
+-- Делим нацело так
+35 `div` 4 -- 8
+
+-- Булевы значения - тоже примитивные значения
+True
+False
+
+-- Булева алгебра
+not True -- False
+not False -- True
+1 == 1 -- True
+1 /= 1 -- False
+1 < 10 -- True
+
+-- В примере выше `not`, это функция, принимающая один аргумент.
+-- При вызове функции в Haskell список аргументов
+-- не нужно заключать в скобки - аргументы просто
+-- перечисляются через пробелы сразу после имени функции.
+-- Т.о. типичный вызов выглядит так:
+-- func arg1 arg2 arg3...
+-- Ниже же будет показано, как определять свои функции.
+
+-- Строки и символы
+"Это строка."
+'ы' -- а это символ
+'Нельзя заключать длинные строки в одинарные кавычки.' -- ошибка!
+
+-- Строки можно конкатенировать
+"Привет" ++ ", Мир!" -- "Привет, Мир!"
+
+-- При этом строки - это просто списки символов!
+"Я - строка!" !! 0 -- 'Я'
+
+
+----------------------------------------------------
+-- Списки и Кортежи
+----------------------------------------------------
+
+-- Все элементы списка в Haskell
+-- должны иметь один и тот же тип.
+
+-- Эти два списка - эквивалентны:
+[1, 2, 3, 4, 5]
+[1..5]
+
+-- Haskell позволяет определять даже бесконечные списки!
+[1..] -- список всех натуральных чисел!
+
+-- Бесконечные списки возможно в Haskell потому, что он "ленив".
+-- В Haskell все вычисления производятся тогда и только тогда,
+-- когда их результат потребуется.
+-- Эта стратегия так и называется - "lazy evaluation".
+-- Скажем, если вам нужен тысячный элемент из
+-- списка натуральных чисел (бесконечного) и вы напишете так:
+
+[1..] !! 999 -- 1000
+
+-- То Haskell вычислит элементы этого списка от 1 до 1000...
+-- ... и остановится, ведь последующие элементы пока не нужны.
+-- Это значит, что остальные элементы нашего
+-- "бесконечного" списка не будут вычисляться! По крайней мере,
+-- пока не понадобятся и они.
+
+-- Списки можно объединять
+[1..5] ++ [6..10]
+
+-- И добавлять значения в начало
+0:[1..5] -- [0, 1, 2, 3, 4, 5]
+
+-- А можно обратиться по индексу
+[0..] !! 5 -- 5
+
+-- Вот ещё несколько функций, часто используемых со списками
+head [1..5] -- 1
+tail [1..5] -- [2, 3, 4, 5]
+init [1..5] -- [1, 2, 3, 4]
+last [1..5] -- 5
+
+-- list comprehensions - "формулы" для описания списков
+[x*2 | x <- [1..5]] -- [2, 4, 6, 8, 10]
+
+-- можно указать условие попадания элементов в список
+[x*2 | x <- [1..5], x*2 > 4] -- [6, 8, 10]
+
+-- Списки могут даже состоять из других списков
+[[1,2,3],[4,5,6]] !! 1 !! 2 -- 6 (вторая строка, третий столбец)
+
+-- Кортежи позволяют своим элементам иметь различные типы,
+-- но при этом кортежи имеют фиксированную длину.
+-- Кортеж:
+("haskell", 1)
+
+-- Часто кортежи из двух элементов называются "парами".
+-- Элементы пары можно получать так:
+fst ("haskell", 1) -- "haskell"
+snd ("haskell", 1) -- 1
+
+----------------------------------------------------
+-- 3. Функции
+----------------------------------------------------
+-- Простая функция, принимающая два аргумента
+add a b = a + b
+
+-- Внимание!
+-- Если вы используете ghci (интерактивный интерпретатор Haskell),
+-- вам нужно использовать ключевое слово `let`, примерно так:
+-- let add a b = a + b
+
+-- Вызовем нашу функцию
+add 1 2 -- 3
+
+-- Функцию можно поместить между первым и вторым аргументами,
+-- если заключить её имя в обратные кавычки
+1 `add` 2 -- 3
+
+{- Вы можете также определять функции, имя которых
+вообще не содержит букв! Таки функции и называются "операторами",
+и, да, вы можете определять свои операторы!
+Скажем, оператор целочисленного деления можно определить так -}
+(//) a b = a `div` b
+35 // 4 -- 8
+{- Здесь оператор заключен в скобки - как говорят,
+поставлен в префиксную позицию.
+В префиксной позиции оператор можно не только определять,
+но и вызывать -}
+(+) 1 2 -- 3
+
+-- Охранные выражения (guards) порой удобны,
+-- если наша функция ветвится
+fib x
+ | x < 2 = x
+ | otherwise = fib (x - 1) + fib (x - 2)
+
+{- Сопоставление с образцом (pattern matching)
+чем-то напоминает охранные выражения.
+Здесь мы видим три определения функции fib.
+При вызове функции по имени Haskell использует
+первое определение, к образцу которого
+"подойдет" набор аргументов -}
+fib 1 = 1
+fib 2 = 2
+fib x = fib (x - 1) + fib (x - 2)
+
+-- Pattern matching для кортежей выглядит так
+foo (x, y) = (x + 1, y + 2)
+
+{- Pattern matching для списков устроен чуть сложнее.
+Пусть `x` - первый элемент списка, а `xs` - остальные элементы.
+Тогда операции `head` и `tail` могут быть определены так -}
+myHead (x:xs) = x
+myTail (x:xs) = xs
+
+-- Функцию отображения мы можем написать так
+myMap func [] = []
+myMap func (x:xs) = func x:(myMap func xs)
+
+-- При сопоставлении происходит привязка
+-- элементов значения с именами в образце
+fstPlusThird (a : _ : b : _) = a + b
+fstPlusThird [1,2,3,4,5] -- 4
+-- Значения, для которых вместо имени указано `_`,
+-- игнорируются. Это удобно, когда важен сам факт
+-- совпадения образца
+oneElem [_] = True
+oneElem _ = False
+
+startsWith x (y:_) = x == y
+startsWith _ _ = False
+
+startsWith 'H' "Hello!" -- True
+startsWith 'H' "hello!" -- False
+
+{- Обратите внимание на тот факт,
+что первый аргумент нашей функции `myMap` - тоже функция!
+Функции, подобно `myMap`, принимающие другие функции
+в качестве параметров, или, скажем, возвращающие функции
+в качестве результата, называются
+Функциями Высших Порядков (ФВП, High Order Functions, HOF)
+-}
+
+-- Вместе с ФВП часто используются анонимные функции
+myMap (\x -> x + 2) [1..5] -- [3, 4, 5, 6, 7]
+-- Такие функции описываются в виде
+-- \arg1 arg1 .. -> expression
+
+-- Популярные в других языках ФВП присутствуют и в Haskell
+map (\x -> x * 10) [1..5] -- [10, 20, 30, 40, 50]
+filter (\x -> x > 2) [1..5] -- [3, 4, 5]
+
+{- Функция свертки
+(она же `reduce` или `inject` в других языках)
+в Haskell представлены функциями `foldr` и `foldl`.
+Суть свертки можно представить так:
+
+foldl f x0 [x1,x2,x3] -> (f (f (f x0 x1) x2) x3)
+foldr f x0 [x1,x2,x3] -> (f x1 (f x2 (f x3 x0)))
+
+Здесь x0 - начальное значения так называемого "аккумулятора"
+-}
+-- Эти два вызова дают одинаковый результат
+foldr (\x acc -> acc + x) 0 [1..5] -- 15
+foldl (\acc x -> acc + x) 0 [1..5] -- 15
+-- Тут можно даже заменить анонимную функцию на оператор
+foldr (+) 0 [1..5] -- 15
+foldl (+) 0 [1..5] -- 15
+
+-- Зато здесь разница видна
+foldr (\x acc -> (x + 10) : acc) [] [1..3] -- [11, 12, 13]
+foldl (\acc x -> (x + 10) : acc) [] [1..3] -- [13, 12, 11]
+
+{- Часто в качестве начального значения
+удобно брать крайнее значение списка (крайнее слева или справа).
+Для этого есть пара функций - `foldr1` и `foldl1` -}
+foldr1 (+) [1..5] -- 15
+foldl1 (+) [1..5] -- 15
+
+----------------------------------------------------
+-- 4. Больше о функциях
+----------------------------------------------------
+
+{- Каррирование (currying)
+Если в Haskell при вызове функции передать не все аргументы,
+Функция становится "каррированой" - результатом вызова станет
+новая функция, которая при вызове и примет оставшиеся аргументы -}
+
+add a b = a + b
+foo = add 10 -- теперь foo будет принимать число
+ -- и добавлять к нему 10
+foo 5 -- 15
+
+-- Для операторов можно "опустить" любой из двух аргументов
+-- Используя этот факт можно определить
+-- функцию `foo` из кода выше несколько иначе
+foo = (+10)
+foo 5 -- 15
+
+-- Поупражняемся
+map (10-) [1..3] -- [9, 8, 7]
+filter (<5) [1..10] -- [1, 2, 3, 4]
+
+{- Композиция функций
+Функция (.) соединяет пару функций в цепочку.
+К примеру, можно соединить функцию, добавляющую 10,
+с функцией, умножающей на 5 -}
+foo = (*5) . (+10)
+
+-- (5 + 10) * 5 = 75
+foo 5 -- 75
+
+{- Управление приоритетом вычисления
+В Haskell есть функция `$`, которая применяет
+свой первый аргумент ко второму с наименьшим приоритетом
+(обычное применение функций имеет наивысший приоритет)
+Эта функция часто позволяет избежать использования
+"лишних" скобок -}
+head (tail (tail "abcd")) -- 'c'
+head $ tail $ tail "abcd" -- 'c'
+-- того же эффекта иногда можно достичь использованием композиции
+(head . tail . tail) "abcd" -- 'c'
+head . tail . tail $ "abcd" -- 'c'
+{- Тут стоит сразу запомнить, что композиция функций
+возвращает именно новую функцию, как в последнем примере.
+Т.е. можно делать так -}
+third = head . tail . tail
+-- но не так
+third = head $ tail $ tail -- (head (tail (tail))) - ошибка!
+
+----------------------------------------------------
+-- 5. Сигнатуры типов
+----------------------------------------------------
+
+{- Haskell обладает очень сильной системой типов.
+И типизация в Haskell - строгая. Каждое выражение имеет тип,
+который может быть описан сигнатурой.
+Сигнатура записывается в форме
+expression :: type signature
+-}
+
+-- Типы примитивов
+5 :: Integer
+"hello" :: String
+True :: Bool
+
+{- Функции тоже имеют тип
+`not` принимает булево значение и возвращает булев результат
+not :: Bool -> Bool
+
+Вот функция двух аргументов
+add :: Integer -> Integer -> Integer
+
+Тут то мы и видим предпосылки к каррированию: тип
+на самом деле выглядит так (скобки просто обычно опускаются)
+add :: (Integer -> Integer) -> Integer
+т.е. функция принимает аргумент,
+и возвращает функцию от второго аргумента! -}
+
+-- Считается хорошим тоном указывать сигнатуру определений,
+-- которые доступны другим разработчикам (публичны). Пример:
+double :: Integer -> Integer
+double x = x * 2
+
+----------------------------------------------------
+-- 6. Управление потоком исполнения
+----------------------------------------------------
+
+-- Выражение `if`
+haskell = if 1 == 1 then "awesome" else "awful" -- haskell = "awesome"
+
+-- Выражение `if` можно записать и в несколько строк.
+-- Соблюдайте отступы!
+haskell = if 1 == 1
+ then "awesome"
+ else "awful"
+
+-- Так как `if` - выражение, ветка `else` обязательна!
+-- И более того, результаты выражений в ветках `then` и `else`
+-- должны иметь одинаковый тип!
+
+-- `case`-выражение выглядит так
+case args of -- парсим аргументы командной строки
+ "help" -> printHelp
+ "start" -> startProgram
+ _ -> putStrLn "bad args"
+
+-- При вычислении результата `case`-выражения производится
+-- сопоставление с образцом:
+fib x = case x of
+ 1 -> 1
+ 2 -> 1
+ _ -> fib (x - 1) + fib (x - 2)
+
+-- В Haskell нет циклов - вместо них используются рекурсия,
+-- отображение, фильтрация и свертка (map/filter/fold)
+map (*2) [1..5] -- [2, 4, 6, 8, 10]
+
+for array func = map func array
+for [0..3] $ \i -> show i -- ["0", "1", "2", "3"]
+for [0..3] show -- ["0", "1", "2", "3"]
+
+----------------------------------------------------
+-- 7. Пользовательские типы данных
+----------------------------------------------------
+
+-- Создадим свой Haskell-тип данных
+
+data Color = Red | Blue | Green
+
+-- Попробуем использовать
+
+say :: Color -> String
+say Red = "You are Red!"
+say Blue = "You are Blue!"
+say Green = "You are Green!"
+
+-- Типы могут иметь параметры (параметры типов)
+
+data Maybe a = Nothing | Just a
+
+-- Все эти выражения имеют тип `Maybe`
+Just "hello" -- :: `Maybe String`
+Just 1 -- :: `Maybe Int`
+Nothing -- :: `Maybe a` для любого `a`
+
+-- Типы могут быть достаточно сложными
+data Figure = Rectangle (Int, Int) Int Int
+ | Square (Int, Int) Int
+ | Point (Int, Int)
+
+area :: Figure -> Int
+area (Point _) = 0
+area (Square _ s) = s * s
+area (Rectangle _ w h) = w * h
+
+----------------------------------------------------
+-- 8. Ввод-вывод в Haskell
+----------------------------------------------------
+
+-- Полноценно объяснить тему ввода-вывода невозможно
+-- без объяснения монад, но для использования в простых случаях
+-- вводного описания будет достаточно.
+
+-- Когда программа на Haskell выполняется,
+-- вызывается функция с именем `main`.
+-- Эта функция должна вернуть значение типа `IO ()`
+-- Например
+
+main :: IO ()
+main = putStrLn $ "Hello, sky! " ++ (say Blue)
+-- `putStrLn` имеет тип `String -> IO ()`
+
+-- Проще всего реализовать программу с вводом-выводом (IO),
+-- если вы реализуете функцию с типом `String -> String`.
+-- Далее ФВП
+-- interact :: (String -> String) -> IO ()
+-- сделает всё за нас!
+
+countLines :: String -> String
+countLines = show . length . lines
+-- здесь `lines` разделяет строку на список строк
+-- по символу перевода строки
+
+main' :: IO ()
+main' = interact countLines
+
+{- Вы можете думать о типе `IO ()`,
+как о некотором представлении последовательности
+действий, которые должен совершить компьютер.
+Такое представление напоминает программу
+на императивном языке программирования. Для описания
+такой последовательности используется `do`-нотация -}
+
+sayHello :: IO ()
+sayHello = do
+ putStrLn "What is your name?"
+ name <- getLine -- запрашиваем строку и связываем с "name"
+ putStrLn $ "Hello, " ++ name
+
+-- Упражнение:
+-- напишите свою реализацию функции `interact`,
+-- которая запрашивает и обрабатывает только одну строку
+
+{- Код функции `sayHello` не будет исполняться
+при её определении. Единственное место, где IO-действия
+могут быть произведены - функция `main`!
+Чтобы эта программа выполнила действия в функции `sayHello`,
+закомментируйте предыдущее определение функции `main`
+и добавьте новое определение:
+
+main = sayHello -}
+
+{- Давайте подробнее рассмотрим, как работает функция `getLine`
+Её тип:
+ getLine :: IO String
+Вы можете думать, что значение типа `IO a` представляет
+собой компьютерную программу, в результате выполнения которой
+генерируется значение типа `a`, в дополнение
+к остальным эффектам, производимым при выполнении - таким как
+печать текста на экран. Это значение типа `a` мы можем
+сохранить с помощью оператора `<-`. Мы даже можем реализовать
+свое действие, возвращающее значение: -}
+
+action :: IO String
+action = do
+ putStrLn "This is a line. Duh"
+ input1 <- getLine
+ input2 <- getLine
+ -- Тип блока `do` будет соответствовать типу последнего
+ -- выполненного в блоке выражения.
+ -- Заметим, что `return` - не ключевое слово, а функция
+ -- типа `a -> IO a`
+ return (input1 ++ "\n" ++ input2) -- return :: String -> IO String
+
+-- Теперь это действие можно использовать вместо `getLine`:
+
+main'' = do
+ putStrLn "I will echo two lines!"
+ result <- action
+ putStrLn result
+ putStrLn "This was all, folks!"
+
+{- Тип `IO` - пример "монады". Языку Haskell нужны монады,
+чтобы оставаться преимущественно чистым функциональным языком.
+Любые функции, взаимодействующие с внешним миром
+(производящие ввод-вывод) имеют `IO` в своих сигнатурах.
+Это позволяет судить о функции как о "чистой" - такая не будет
+производить ввод-вывод. В ином случая функция - не "чистая".
+
+Такой подход позволяет очень просто разрабатывать многопоточные
+программы - чистые функции, запущенные параллельно
+не будут конфликтовать между собой в борьбе за ресурсы. -}
+
+----------------------------------------------------
+-- 9. Haskell REPL
+----------------------------------------------------
+
+{- Интерактивная консоль Haskell запускается командой `ghci`.
+Теперь можно вводить строки кода на Haskell.
+Связывание значений с именами производится
+с помощью выражения `let`: -}
+
+let foo = 5
+
+-- Тип значения или выражения можно узнать
+-- с помощью команды `:t`:
+
+>:t foo
+foo :: Integer
+
+-- Также можно выполнять действия с типом `IO ()`
+
+> sayHello
+What is your name?
+Friend!
+Hello, Friend!
+
+```
+
+Многое о Haskell, например классы типов и монады невозможно уместить в столь короткую статью. Огромное количество очень интересных идей лежит в основе языка, и именно благодаря этому фундаменту на языке так приятно писать код. Позволю себе привести ещё один маленький пример кода на Haskell - реализацию быстрой сортировки:
+
+```haskell
+qsort [] = []
+qsort (p:xs) = qsort lesser ++ [p] ++ qsort greater
+ where lesser = filter (< p) xs
+ greater = filter (>= p) xs
+```
+
+Haskell прост в установке, забирайте [здесь](http://www.haskell.org/platform/) и пробуйте! Это же так интересно!.
+
+Более глубокое погрузиться в язык позволят прекрасные книги
+[Learn you a Haskell](http://learnyouahaskell.com/) и
+[Real World Haskell](http://book.realworldhaskell.org/).
+
+[autor]: http://adit.io имеется в виду автор оригинального текста Adit Bhargava *(примечание переводчика)*
diff --git a/ru-ru/julia-ru.html.markdown b/ru-ru/julia-ru.html.markdown
index c9213a42..cd55e116 100644
--- a/ru-ru/julia-ru.html.markdown
+++ b/ru-ru/julia-ru.html.markdown
@@ -24,58 +24,58 @@ Julia — гомоиконный функциональный язык прог
# Всё в Julia — выражение.
# Простые численные типы
-3 #=> 3 (Int64)
-3.2 #=> 3.2 (Float64)
-2 + 1im #=> 2 + 1im (Complex{Int64})
-2//3 #=> 2//3 (Rational{Int64})
+3 # => 3 (Int64)
+3.2 # => 3.2 (Float64)
+2 + 1im # => 2 + 1im (Complex{Int64})
+2//3 # => 2//3 (Rational{Int64})
# Доступны все привычные инфиксные операторы
-1 + 1 #=> 2
-8 - 1 #=> 7
-10 * 2 #=> 20
-35 / 5 #=> 7.0
-5 / 2 #=> 2.5 # деление Int на Int всегда возвращает Float
-div(5, 2) #=> 2 # для округления к нулю используется div
-5 \ 35 #=> 7.0
-2 ^ 2 #=> 4 # возведение в степень
-12 % 10 #=> 2
+1 + 1 # => 2
+8 - 1 # => 7
+10 * 2 # => 20
+35 / 5 # => 7.0
+5 / 2 # => 2.5 # деление Int на Int всегда возвращает Float
+div(5, 2) # => 2 # для округления к нулю используется div
+5 \ 35 # => 7.0
+2 ^ 2 # => 4 # возведение в степень
+12 % 10 # => 2
# С помощью скобок можно изменить приоритет операций
-(1 + 3) * 2 #=> 8
+(1 + 3) * 2 # => 8
# Побитовые операторы
-~2 #=> -3 # НЕ (NOT)
-3 & 5 #=> 1 # И (AND)
-2 | 4 #=> 6 # ИЛИ (OR)
-2 $ 4 #=> 6 # сложение по модулю 2 (XOR)
-2 >>> 1 #=> 1 # логический сдвиг вправо
-2 >> 1 #=> 1 # арифметический сдвиг вправо
-2 << 1 #=> 4 # логический/арифметический сдвиг влево
+~2 # => -3 # НЕ (NOT)
+3 & 5 # => 1 # И (AND)
+2 | 4 # => 6 # ИЛИ (OR)
+2 $ 4 # => 6 # сложение по модулю 2 (XOR)
+2 >>> 1 # => 1 # логический сдвиг вправо
+2 >> 1 # => 1 # арифметический сдвиг вправо
+2 << 1 # => 4 # логический/арифметический сдвиг влево
# Функция bits возвращает бинарное представление числа
bits(12345)
-#=> "0000000000000000000000000000000000000000000000000011000000111001"
+# => "0000000000000000000000000000000000000000000000000011000000111001"
bits(12345.0)
-#=> "0100000011001000000111001000000000000000000000000000000000000000"
+# => "0100000011001000000111001000000000000000000000000000000000000000"
# Логические значения являются примитивами
true
false
# Булевы операторы
-!true #=> false
-!false #=> true
-1 == 1 #=> true
-2 == 1 #=> false
-1 != 1 #=> false
-2 != 1 #=> true
-1 < 10 #=> true
-1 > 10 #=> false
-2 <= 2 #=> true
-2 >= 2 #=> true
+!true # => false
+!false # => true
+1 == 1 # => true
+2 == 1 # => false
+1 != 1 # => false
+2 != 1 # => true
+1 < 10 # => true
+1 > 10 # => false
+2 <= 2 # => true
+2 >= 2 # => true
# Сравнения можно объединять цепочкой
-1 < 2 < 3 #=> true
-2 < 3 < 2 #=> false
+1 < 2 < 3 # => true
+2 < 3 < 2 # => false
# Строки объявляются с помощью двойных кавычек — "
"This is a string."
@@ -84,12 +84,12 @@ false
'a'
# Строки индексируются как массивы символов
-"This is a string"[1] #=> 'T' # Индексы начинаются с единицы
+"This is a string"[1] # => 'T' # Индексы начинаются с единицы
# Индексирование не всегда правильно работает для UTF8-строк,
# поэтому рекомендуется использовать итерирование (map, for-циклы и т.п.).
# Для строковой интерполяции используется знак доллара ($):
-"2 + 2 = $(2 + 2)" #=> "2 + 2 = 4"
+"2 + 2 = $(2 + 2)" # => "2 + 2 = 4"
# В скобках можно использовать любое выражение языка.
# Другой способ форматирования строк — макрос printf
@@ -103,12 +103,12 @@ false
println("I'm Julia. Nice to meet you!")
# Переменные инициализируются без предварительного объявления
-some_var = 5 #=> 5
-some_var #=> 5
+some_var = 5 # => 5
+some_var # => 5
# Попытка доступа к переменной до инициализации вызывает ошибку
try
- some_other_var #=> ERROR: some_other_var not defined
+ some_other_var # => ERROR: some_other_var not defined
catch e
println(e)
end
@@ -116,12 +116,12 @@ end
# Имена переменных начинаются с букв.
# После первого символа можно использовать буквы, цифры,
# символы подчёркивания и восклицательные знаки.
-SomeOtherVar123! = 6 #=> 6
+SomeOtherVar123! = 6 # => 6
# Допустимо использование unicode-символов
-☃ = 8 #=> 8
+☃ = 8 # => 8
# Это особенно удобно для математических обозначений
-2 * π #=> 6.283185307179586
+2 * π # => 6.283185307179586
# Рекомендации по именованию:
# * имена переменных в нижнем регистре, слова разделяются символом
@@ -136,49 +136,49 @@ SomeOtherVar123! = 6 #=> 6
# оканчивается восклицательным знаком.
# Массив хранит последовательность значений, индексируемых с единицы до n:
-a = Int64[] #=> пустой массив Int64-элементов
+a = Int64[] # => пустой массив Int64-элементов
# Одномерный массив объявляется разделёнными запятой значениями.
-b = [4, 5, 6] #=> массив из трёх Int64-элементов: [4, 5, 6]
-b[1] #=> 4
-b[end] #=> 6
+b = [4, 5, 6] # => массив из трёх Int64-элементов: [4, 5, 6]
+b[1] # => 4
+b[end] # => 6
# Строки двумерного массива разделяются точкой с запятой.
# Элементы строк разделяются пробелами.
-matrix = [1 2; 3 4] #=> 2x2 Int64 Array: [1 2; 3 4]
+matrix = [1 2; 3 4] # => 2x2 Int64 Array: [1 2; 3 4]
# push! и append! добавляют в список новые элементы
-push!(a,1) #=> [1]
-push!(a,2) #=> [1,2]
-push!(a,4) #=> [1,2,4]
-push!(a,3) #=> [1,2,4,3]
-append!(a,b) #=> [1,2,4,3,4,5,6]
+push!(a,1) # => [1]
+push!(a,2) # => [1,2]
+push!(a,4) # => [1,2,4]
+push!(a,3) # => [1,2,4,3]
+append!(a,b) # => [1,2,4,3,4,5,6]
# pop! удаляет из списка последний элемент
-pop!(b) #=> возвращает 6; массив b снова равен [4,5]
+pop!(b) # => возвращает 6; массив b снова равен [4,5]
# Вернём 6 обратно
push!(b,6) # b снова [4,5,6].
-a[1] #=> 1 # индексы начинаются с единицы!
+a[1] # => 1 # индексы начинаются с единицы!
# Последний элемент можно получить с помощью end
-a[end] #=> 6
+a[end] # => 6
# Операции сдвига
-shift!(a) #=> 1 and a is now [2,4,3,4,5,6]
-unshift!(a,7) #=> [7,2,4,3,4,5,6]
+shift!(a) # => 1 and a is now [2,4,3,4,5,6]
+unshift!(a,7) # => [7,2,4,3,4,5,6]
# Восклицательный знак на конце названия функции означает,
# что функция изменяет переданные ей аргументы.
-arr = [5,4,6] #=> массив из 3 Int64-элементов: [5,4,6]
-sort(arr) #=> [4,5,6]; но arr равен [5,4,6]
-sort!(arr) #=> [4,5,6]; а теперь arr — [4,5,6]
+arr = [5,4,6] # => массив из 3 Int64-элементов: [5,4,6]
+sort(arr) # => [4,5,6]; но arr равен [5,4,6]
+sort!(arr) # => [4,5,6]; а теперь arr — [4,5,6]
# Попытка доступа за пределами массива выбрасывает BoundsError
try
- a[0] #=> ERROR: BoundsError() in getindex at array.jl:270
- a[end+1] #=> ERROR: BoundsError() in getindex at array.jl:270
+ a[0] # => ERROR: BoundsError() in getindex at array.jl:270
+ a[end+1] # => ERROR: BoundsError() in getindex at array.jl:270
catch e
println(e)
end
@@ -189,111 +189,111 @@ end
# то найти эти файлы можно в директории base.
# Создавать массивы можно из последовательности
-a = [1:5] #=> массив из 5 Int64-элементов: [1,2,3,4,5]
+a = [1:5] # => массив из 5 Int64-элементов: [1,2,3,4,5]
# Срезы
-a[1:3] #=> [1, 2, 3]
-a[2:] #=> [2, 3, 4, 5]
-a[2:end] #=> [2, 3, 4, 5]
+a[1:3] # => [1, 2, 3]
+a[2:] # => [2, 3, 4, 5]
+a[2:end] # => [2, 3, 4, 5]
# splice! удаляет элемент из массива
# Remove elements from an array by index with splice!
arr = [3,4,5]
-splice!(arr,2) #=> 4 ; arr теперь равен [3,5]
+splice!(arr,2) # => 4 ; arr теперь равен [3,5]
# append! объединяет списки
b = [1,2,3]
append!(a,b) # теперь a равен [1, 2, 3, 4, 5, 1, 2, 3]
# Проверка на вхождение
-in(1, a) #=> true
+in(1, a) # => true
# Длина списка
-length(a) #=> 8
+length(a) # => 8
# Кортеж — неизменяемая структура.
-tup = (1, 2, 3) #=> (1,2,3) # кортеж (Int64,Int64,Int64).
-tup[1] #=> 1
+tup = (1, 2, 3) # => (1,2,3) # кортеж (Int64,Int64,Int64).
+tup[1] # => 1
try:
- tup[1] = 3 #=> ERROR: no method setindex!((Int64,Int64,Int64),Int64,Int64)
+ tup[1] = 3 # => ERROR: no method setindex!((Int64,Int64,Int64),Int64,Int64)
catch e
println(e)
end
# Многие функции над списками работают и для кортежей
-length(tup) #=> 3
-tup[1:2] #=> (1,2)
-in(2, tup) #=> true
+length(tup) # => 3
+tup[1:2] # => (1,2)
+in(2, tup) # => true
# Кортежи можно распаковывать в переменные
-a, b, c = (1, 2, 3) #=> (1,2,3) # a = 1, b = 2 и c = 3
+a, b, c = (1, 2, 3) # => (1,2,3) # a = 1, b = 2 и c = 3
# Скобки из предыдущего примера можно опустить
-d, e, f = 4, 5, 6 #=> (4,5,6)
+d, e, f = 4, 5, 6 # => (4,5,6)
# Кортеж из одного элемента не равен значению этого элемента
-(1,) == 1 #=> false
-(1) == 1 #=> true
+(1,) == 1 # => false
+(1) == 1 # => true
# Обмен значений
-e, d = d, e #=> (5,4) # d = 5, e = 4
+e, d = d, e # => (5,4) # d = 5, e = 4
# Словари содержат ассоциативные массивы
-empty_dict = Dict() #=> Dict{Any,Any}()
+empty_dict = Dict() # => Dict{Any,Any}()
# Для создания словаря можно использовать литерал
filled_dict = ["one"=> 1, "two"=> 2, "three"=> 3]
# => Dict{ASCIIString,Int64}
# Значения ищутся по ключу с помощью оператора []
-filled_dict["one"] #=> 1
+filled_dict["one"] # => 1
# Получить все ключи
keys(filled_dict)
-#=> KeyIterator{Dict{ASCIIString,Int64}}(["three"=>3,"one"=>1,"two"=>2])
+# => KeyIterator{Dict{ASCIIString,Int64}}(["three"=>3,"one"=>1,"two"=>2])
# Заметьте, словарь не запоминает порядок, в котором добавляются ключи.
# Получить все значения.
values(filled_dict)
-#=> ValueIterator{Dict{ASCIIString,Int64}}(["three"=>3,"one"=>1,"two"=>2])
+# => ValueIterator{Dict{ASCIIString,Int64}}(["three"=>3,"one"=>1,"two"=>2])
# То же касается и порядка значений.
# Проверка вхождения ключа в словарь
-in(("one", 1), filled_dict) #=> true
-in(("two", 3), filled_dict) #=> false
-haskey(filled_dict, "one") #=> true
-haskey(filled_dict, 1) #=> false
+in(("one", 1), filled_dict) # => true
+in(("two", 3), filled_dict) # => false
+haskey(filled_dict, "one") # => true
+haskey(filled_dict, 1) # => false
# Попытка обратиться к несуществующему ключу выбросит ошибку
try
- filled_dict["four"] #=> ERROR: key not found: four in getindex at dict.jl:489
+ filled_dict["four"] # => ERROR: key not found: four in getindex at dict.jl:489
catch e
println(e)
end
# Используйте метод get со значением по умолчанию, чтобы избежать этой ошибки
# get(dictionary,key,default_value)
-get(filled_dict,"one",4) #=> 1
-get(filled_dict,"four",4) #=> 4
+get(filled_dict,"one",4) # => 1
+get(filled_dict,"four",4) # => 4
# Для коллекций неотсортированных уникальных элементов используйте Set
-empty_set = Set() #=> Set{Any}()
+empty_set = Set() # => Set{Any}()
# Инициализация множества
-filled_set = Set(1,2,2,3,4) #=> Set{Int64}(1,2,3,4)
+filled_set = Set(1,2,2,3,4) # => Set{Int64}(1,2,3,4)
# Добавление элементов
-push!(filled_set,5) #=> Set{Int64}(5,4,2,3,1)
+push!(filled_set,5) # => Set{Int64}(5,4,2,3,1)
# Проверка вхождения элементов во множество
-in(2, filled_set) #=> true
-in(10, filled_set) #=> false
+in(2, filled_set) # => true
+in(10, filled_set) # => false
# Функции для получения пересечения, объединения и разницы.
-other_set = Set(3, 4, 5, 6) #=> Set{Int64}(6,4,5,3)
-intersect(filled_set, other_set) #=> Set{Int64}(3,4,5)
-union(filled_set, other_set) #=> Set{Int64}(1,2,3,4,5,6)
-setdiff(Set(1,2,3,4),Set(2,3,5)) #=> Set{Int64}(1,4)
+other_set = Set(3, 4, 5, 6) # => Set{Int64}(6,4,5,3)
+intersect(filled_set, other_set) # => Set{Int64}(3,4,5)
+union(filled_set, other_set) # => Set{Int64}(1,2,3,4,5,6)
+setdiff(Set(1,2,3,4),Set(2,3,5)) # => Set{Int64}(1,4)
####################################################
@@ -311,7 +311,7 @@ elseif some_var < 10 # Необязательная ветка elseif.
else # else-ветка также опциональна.
println("some_var is indeed 10.")
end
-#=> prints "some var is smaller than 10"
+# => prints "some var is smaller than 10"
# Цикл for проходит по итерируемым объектам
@@ -368,7 +368,7 @@ try
catch e
println("caught it $e")
end
-#=> caught it ErrorException("help")
+# => caught it ErrorException("help")
####################################################
@@ -386,27 +386,27 @@ function add(x, y)
x + y
end
-add(5, 6) #=> Вернёт 11, напечатав "x is 5 and y is 6"
+add(5, 6) # => Вернёт 11, напечатав "x is 5 and y is 6"
# Функция может принимать переменное количество позиционных аргументов.
function varargs(args...)
return args
# для возвращения из функции в любом месте используется 'return'
end
-#=> varargs (generic function with 1 method)
+# => varargs (generic function with 1 method)
-varargs(1,2,3) #=> (1,2,3)
+varargs(1,2,3) # => (1,2,3)
# Многоточие (...) — это splat.
# Мы только что воспользовались им в определении функции.
# Также его можно использовать при вызове функции,
# где он преобразует содержимое массива или кортежа в список аргументов.
-Set([1,2,3]) #=> Set{Array{Int64,1}}([1,2,3]) # формирует множество массивов
-Set([1,2,3]...) #=> Set{Int64}(1,2,3) # эквивалентно Set(1,2,3)
+Set([1,2,3]) # => Set{Array{Int64,1}}([1,2,3]) # формирует множество массивов
+Set([1,2,3]...) # => Set{Int64}(1,2,3) # эквивалентно Set(1,2,3)
-x = (1,2,3) #=> (1,2,3)
-Set(x) #=> Set{(Int64,Int64,Int64)}((1,2,3)) # множество кортежей
-Set(x...) #=> Set{Int64}(2,3,1)
+x = (1,2,3) # => (1,2,3)
+Set(x) # => Set{(Int64,Int64,Int64)}((1,2,3)) # множество кортежей
+Set(x...) # => Set{Int64}(2,3,1)
# Опциональные позиционные аргументы
@@ -414,12 +414,12 @@ function defaults(a,b,x=5,y=6)
return "$a $b and $x $y"
end
-defaults('h','g') #=> "h g and 5 6"
-defaults('h','g','j') #=> "h g and j 6"
-defaults('h','g','j','k') #=> "h g and j k"
+defaults('h','g') # => "h g and 5 6"
+defaults('h','g','j') # => "h g and j 6"
+defaults('h','g','j','k') # => "h g and j k"
try
- defaults('h') #=> ERROR: no method defaults(Char,)
- defaults() #=> ERROR: no methods defaults()
+ defaults('h') # => ERROR: no method defaults(Char,)
+ defaults() # => ERROR: no methods defaults()
catch e
println(e)
end
@@ -429,9 +429,9 @@ function keyword_args(;k1=4,name2="hello") # обратите внимание
return ["k1"=>k1,"name2"=>name2]
end
-keyword_args(name2="ness") #=> ["name2"=>"ness","k1"=>4]
-keyword_args(k1="mine") #=> ["k1"=>"mine","name2"=>"hello"]
-keyword_args() #=> ["name2"=>"hello","k2"=>4]
+keyword_args(name2="ness") # => ["name2"=>"ness","k1"=>4]
+keyword_args(k1="mine") # => ["k1"=>"mine","name2"=>"hello"]
+keyword_args() # => ["name2"=>"hello","k2"=>4]
# В одной функции можно совмещать все виды аргументов
function all_the_args(normal_arg, optional_positional_arg=2; keyword_arg="foo")
@@ -455,7 +455,7 @@ function create_adder(x)
end
# Анонимная функция
-(x -> x > 2)(3) #=> true
+(x -> x > 2)(3) # => true
# Эта функция идентичная предыдущей версии create_adder
function create_adder(x)
@@ -471,16 +471,16 @@ function create_adder(x)
end
add_10 = create_adder(10)
-add_10(3) #=> 13
+add_10(3) # => 13
# Встроенные функции высшего порядка
-map(add_10, [1,2,3]) #=> [11, 12, 13]
-filter(x -> x > 5, [3, 4, 5, 6, 7]) #=> [6, 7]
+map(add_10, [1,2,3]) # => [11, 12, 13]
+filter(x -> x > 5, [3, 4, 5, 6, 7]) # => [6, 7]
# Списковые сборки
-[add_10(i) for i=[1, 2, 3]] #=> [11, 12, 13]
-[add_10(i) for i in [1, 2, 3]] #=> [11, 12, 13]
+[add_10(i) for i=[1, 2, 3]] # => [11, 12, 13]
+[add_10(i) for i in [1, 2, 3]] # => [11, 12, 13]
####################################################
## 5. Типы
@@ -489,12 +489,12 @@ filter(x -> x > 5, [3, 4, 5, 6, 7]) #=> [6, 7]
# Julia has a type system.
# Каждое значение имеет тип, но переменные не определяют тип значения.
# Функция `typeof` возвращает тип значения.
-typeof(5) #=> Int64
+typeof(5) # => Int64
# Types are first-class values
# Типы являются значениями первого класса
-typeof(Int64) #=> DataType
-typeof(DataType) #=> DataType
+typeof(Int64) # => DataType
+typeof(DataType) # => DataType
# Тип DataType представляет типы, включая себя самого.
# Типы используются в качестве документации, для оптимизации и организации.
@@ -515,10 +515,10 @@ end
# Аргументы конструктора по умолчанию — свойства типа
# в порядке их определения.
-tigger = Tiger(3.5,"orange") #=> Tiger(3.5,"orange")
+tigger = Tiger(3.5,"orange") # => Tiger(3.5,"orange")
# Тип объекта по сути является конструктором значений такого типа
-sherekhan = typeof(tigger)(5.6,"fire") #=> Tiger(5.6,"fire")
+sherekhan = typeof(tigger)(5.6,"fire") # => Tiger(5.6,"fire")
# Эти типы, похожие на структуры, называются конкретными.
# Можно создавать объекты таких типов, но не их подтипы.
@@ -530,23 +530,23 @@ abstract Cat # просто имя и точка в иерархии типов
# Объекты абстрактных типов создавать нельзя,
# но зато от них можно наследовать подтипы.
# Например, Number — это абстрактный тип.
-subtypes(Number) #=> 6 элементов в массиве Array{Any,1}:
+subtypes(Number) # => 6 элементов в массиве Array{Any,1}:
# Complex{Float16}
# Complex{Float32}
# Complex{Float64}
# Complex{T<:Real}
# ImaginaryUnit
# Real
-subtypes(Cat) #=> пустой массив Array{Any,1}
+subtypes(Cat) # => пустой массив Array{Any,1}
# У всех типов есть супертип. Для его определения есть функция `super`.
-typeof(5) #=> Int64
-super(Int64) #=> Signed
-super(Signed) #=> Real
-super(Real) #=> Number
-super(Number) #=> Any
-super(super(Signed)) #=> Number
-super(Any) #=> Any
+typeof(5) # => Int64
+super(Int64) # => Signed
+super(Signed) # => Real
+super(Real) # => Number
+super(Number) # => Any
+super(super(Signed)) # => Number
+super(Any) # => Any
# Все эти типы, за исключением Int64, абстрактные.
# Для создания подтипа используется оператор <:
@@ -595,23 +595,23 @@ function meow(animal::Tiger)
end
# Проверка
-meow(tigger) #=> "rawwr"
-meow(Lion("brown","ROAAR")) #=> "ROAAR"
-meow(Panther()) #=> "grrr"
+meow(tigger) # => "rawwr"
+meow(Lion("brown","ROAAR")) # => "ROAAR"
+meow(Panther()) # => "grrr"
# Вспомним иерархию типов
-issubtype(Tiger,Cat) #=> false
-issubtype(Lion,Cat) #=> true
-issubtype(Panther,Cat) #=> true
+issubtype(Tiger,Cat) # => false
+issubtype(Lion,Cat) # => true
+issubtype(Panther,Cat) # => true
# Определим функцию, принимающую на вход объекты типа Cat
function pet_cat(cat::Cat)
println("The cat says $(meow(cat))")
end
-pet_cat(Lion("42")) #=> выведет "The cat says 42"
+pet_cat(Lion("42")) # => выведет "The cat says 42"
try
- pet_cat(tigger) #=> ERROR: no method pet_cat(Tiger,)
+ pet_cat(tigger) # => ERROR: no method pet_cat(Tiger,)
catch e
println(e)
end
@@ -624,31 +624,31 @@ end
function fight(t::Tiger,c::Cat)
println("The $(t.coatcolor) tiger wins!")
end
-#=> fight (generic function with 1 method)
+# => fight (generic function with 1 method)
-fight(tigger,Panther()) #=> выведет The orange tiger wins!
-fight(tigger,Lion("ROAR")) #=> выведет The orange tiger wins!
+fight(tigger,Panther()) # => выведет The orange tiger wins!
+fight(tigger,Lion("ROAR")) # => выведет The orange tiger wins!
# Переопределим поведение функции, если Cat-объект является Lion-объектом
fight(t::Tiger,l::Lion) = println("The $(l.mane_color)-maned lion wins!")
-#=> fight (generic function with 2 methods)
+# => fight (generic function with 2 methods)
-fight(tigger,Panther()) #=> выведет The orange tiger wins!
-fight(tigger,Lion("ROAR")) #=> выведет The green-maned lion wins!
+fight(tigger,Panther()) # => выведет The orange tiger wins!
+fight(tigger,Lion("ROAR")) # => выведет The green-maned lion wins!
# Драться можно не только с тиграми!
fight(l::Lion,c::Cat) = println("The victorious cat says $(meow(c))")
-#=> fight (generic function with 3 methods)
+# => fight (generic function with 3 methods)
-fight(Lion("balooga!"),Panther()) #=> выведет The victorious cat says grrr
+fight(Lion("balooga!"),Panther()) # => выведет The victorious cat says grrr
try
- fight(Panther(),Lion("RAWR")) #=> ERROR: no method fight(Panther,Lion)
+ fight(Panther(),Lion("RAWR")) # => ERROR: no method fight(Panther,Lion)
catch
end
# Вообще, пускай кошачьи могут первыми проявлять агрессию
fight(c::Cat,l::Lion) = println("The cat beats the Lion")
-#=> Warning: New definition
+# => Warning: New definition
# fight(Cat,Lion) at none:1
# is ambiguous with
# fight(Lion,Cat) at none:2.
@@ -658,11 +658,11 @@ fight(c::Cat,l::Lion) = println("The cat beats the Lion")
#fight (generic function with 4 methods)
# Предупреждение говорит, что неясно, какой из методов вызывать:
-fight(Lion("RAR"),Lion("brown","rarrr")) #=> выведет The victorious cat says rarrr
+fight(Lion("RAR"),Lion("brown","rarrr")) # => выведет The victorious cat says rarrr
# Результат может оказаться разным в разных версиях Julia
fight(l::Lion,l2::Lion) = println("The lions come to a tie")
-fight(Lion("RAR"),Lion("brown","rarrr")) #=> выведет The lions come to a tie
+fight(Lion("RAR"),Lion("brown","rarrr")) # => выведет The lions come to a tie
# Под капотом