Rating@Mail.ru

Форум по операционной системе GNU/Linux и свободному программному обеспечению


Текущее время: 17 окт 2017, 08:56

Часовой пояс: UTC + 3 часа




Начать новую тему Ответить на тему  [ Сообщений: 26 ]  На страницу Пред.  1, 2, 3
Автор Сообщение
 Заголовок сообщения: Re: код Kotlin & Java
Непрочитанное сообщениеДобавлено: 04 июн 2017, 18:04 
Не в сети
Писатель
Аватара пользователя

Зарегистрирован: 24 сен 2011, 14:22
Сообщения: 10110
Откуда: Харьков
Здесь уже сразу начинаются интересные вещи:
Olej писал(а):
Код:
    val tests: Array< ()->Unit > = arrayOf(
            { println( tg( 1.0 ) ); },
            { test1() }
    )


Здесь записан массив функций (в данном случае массив размерности 2).
Что есть запись в коде: { ... }?
Это лямбда выражение, запись кода анонимной функции с прототипом fun (Unit): Unit, которое может быть записано в любом месте, где оно и используется.
Olej писал(а):
Код:
fun tg( x: Double ): Double = sin( x ) / cos( x ); // функция - одиночное выражение


А вот так может записываться функция, если она вычисляется как одно, сколь угодно сложное, вычисляемое выражение.


Вернуться к началу
 Профиль Отправить личное сообщение  
 
 Заголовок сообщения: Re: код Kotlin & Java
Непрочитанное сообщениеДобавлено: 04 июн 2017, 18:17 
Не в сети
Писатель
Аватара пользователя

Зарегистрирован: 24 сен 2011, 14:22
Сообщения: 10110
Откуда: Харьков
Дальше:
Код:
fun <T> asList(vararg ts: T): List<T> {            // переменное число параметров
    val result = ArrayList<T>()
    for (t in ts)                                  // ts - это массив (Array)
        result.add(t)
    return result
}

fun test2(): Unit {
    fun printListInt(list: List<Int>) {
        for (t in list)
            print("<" + t.toString() + "> ")
        println()
    }
    val list = asList(1, 2, 3)
    val a = arrayOf(1, 2, 3)
    printListInt( list )
    printListInt( asList(-1, 0, *a, 4) )           // оператор spread: *a
}

Здесь показано:
- как функция asList может иметь переменное (произвольное) число параметров вызова, причём переменные параметры могут иметь различающиеся типы, в том числе и лямбда-функции (в {} записи), аргумент отмеченный квалификатором vararg может быть только один, и желательно, чтобы он был последним в списке аргументов (если не последний, то последующие можно достать, но хлопотно: ключевым вызовом, см. далее);
- как могут определяться локальные (вложенные) определения функций (printListInt), причём глубина вложенности может быть произвольной;
- как контейнер (Array<Int> a) "разворачивается" в последовательность его элементов операцией spread: знак * перед именем a;
Код:
[olej@dell tests]$ java -jar test_fun.jar 3
3 ------------------------------------------
<1> <2> <3>
<-1> <0> <1> <2> <3> <4>


Вернуться к началу
 Профиль Отправить личное сообщение  
 
 Заголовок сообщения: Re: код Kotlin & Java
Непрочитанное сообщениеДобавлено: 04 июн 2017, 19:41 
Не в сети
Писатель
Аватара пользователя

Зарегистрирован: 24 сен 2011, 14:22
Сообщения: 10110
Откуда: Харьков
Olej писал(а):
Дальше:

Лямбда-выражения и анонимные функции:
Код:
val median: (Double, Double) -> Double = { x, y -> x + y / 2.0 }

fun test3(): Unit {
    val a = 5.0; val b = 12.0;
    var c = median(a, b);
    println( c )
    val ar = Array(7, { i -> (i * i - 10).toString() })
    for (t in ar)
        print( t + " " )
    println()
}

Здесь константа median получает функциональное значение, записанное лямбда-выражением, а в инициализации ar 2-м параметром используется анонимная функция (фабрика) для инициализации элементов.
Код:
[olej@dell tests]$ java -jar test_fun.jar 4
4 ------------------------------------------
11.0
-10 -9 -6 -1 6 15 26


Вернуться к началу
 Профиль Отправить личное сообщение  
 
 Заголовок сообщения: Re: код Kotlin & Java
Непрочитанное сообщениеДобавлено: 04 июн 2017, 20:39 
Не в сети
Писатель
Аватара пользователя

Зарегистрирован: 24 сен 2011, 14:22
Сообщения: 10110
Откуда: Харьков
Olej писал(а):
Дальше:

Хвостовая рекурсия:
Код:
tailrec fun findFixPoint(x: Double = 1.0): Double
        = if (x == cos(x)) x else findFixPoint(cos(x))

Ничего особенного в коде, такое можно написать на любом языке программирования ... только здесь если а). стоит квалификатор tailrec и б). это действительно хвостовая рекурсия (т.е. рекурсивный вызов - последний в последовательности операторов), то компилятор вместо рекурсивных вызовов превратит это примерно в следующее:
Код:
fun findFixPoint(): Double {
    var x = 1.0
    while (true) {
        val y = cos(x)
        if (x == y) return y
        x = y
    }
}

Т.е. последовательность рекурсивных вызовов автоматически превратится в цикл.
[url=https://ru.wikipedia.org/wiki/Хвостовая_рекурсия]Хвостовая рекурсия[/url]
Цитата:
Хвостовая рекурсия — частный случай рекурсии, при котором любой рекурсивный вызов является последней операцией перед возвратом из функции.[1] Подобный вид рекурсии примечателен тем, что может быть легко заменён на итерацию путём формальной и гарантированно корректной перестройки кода функции. Оптимизация хвостовой рекурсии путём преобразования её в плоскую итерацию реализована во многих оптимизирующих компиляторах. В некоторых функциональных языках программирования спецификация гарантирует обязательную оптимизацию хвостовой рекурсии.

Иногда это даст радикальное повышение производительности!
Выполнение:
Код:
[olej@dell tests]$ java -jar test_fun.jar 5
5 ------------------------------------------
0.7390851332151607


Вернуться к началу
 Профиль Отправить личное сообщение  
 
 Заголовок сообщения: Re: код Kotlin & Java
Непрочитанное сообщениеДобавлено: 04 июн 2017, 22:35 
Не в сети
Писатель
Аватара пользователя

Зарегистрирован: 24 сен 2011, 14:22
Сообщения: 10110
Откуда: Харьков
Olej писал(а):
если а). стоит квалификатор tailrec и б). это действительно хвостовая рекурсия (т.е. рекурсивный вызов - последний в последовательности операторов), то компилятор вместо рекурсивных вызовов превратит это примерно в следующее:

Вопрос относительно хвостовой рекурсии настолько интересный, что на нём стоит остановиться на время и уточниться...
Начиная с того, что традиционное вычисление факториала, которое показывают школьникам, вот на C, например:
Код:
int factorial (int n) {
    return (n==0) ? 1 : n*factorial(n-1);
}

Оно не является хвостовой рекурсией, т.к., хотя вызов factorial(n-1) и записан последним, но выполняется последним оператор умножения на n.
Написал 2 маленьких тестовых программки на Kotlin:
- factr.kt - здесь нет хвостовой рекурсии:
Код:
fun factorial(n: Long): Double {
    return if (n == 0.toLong()) 1.toDouble() else n*factorial(n-1)
}

fun main( args: Array<String> ) {
   val x = args[0].toLong()
   println( factorial( x ) )
}

- factt.kt - здесь разворачивается хвостовая рекурсия:
Код:
tailrec fun fac_times(n: Long, acc: Long): Double {
    return if (n == 0.toLong()) acc.toDouble() else fac_times(n - 1, acc * n)
}

fun factorial(n: Long): Double {
    return fac_times(n, 1)
}

fun main( args: Array<String> ) {
   val x = args[0].toLong()
   println( factorial( x ) )
}

Выполняем:
Код:
[olej@dell tests]$ kotlinc factr.kt -include-runtime -d factr.jar

[olej@dell tests]$ kotlinc factt.kt -include-runtime -d factt.jar

[olej@dell tests]$ java -jar factr.jar 20
2.43290200817664E18

[olej@dell tests]$ java -jar factt.jar 20
2.43290200817664E18

А вот если я припишу tailrec в 1-ю реализацию:
Код:
tailrec fun factorial(n: Long): Double {
    return if (n == 0.toLong()) 1.toDouble() else n*factorial(n-1)
}
...

То компилятор очень лихо распознаёт эту ситуацию!:
Код:
[olej@dell tests]$ kotlinc factr.kt -include-runtime -d factr.jar
factr.kt:1:1: warning: a function is marked as tail-recursive but no tail calls are found
tailrec fun factorial(n: Long): Double {
^
factr.kt:2:53: warning: recursive call is not a tail call
    return if (n == 0.toLong()) 1.toDouble() else n*factorial(n-1)
                                                    ^


Вложения:
factr.kt [195 байт]
Скачиваний: 11
factt.kt [288 байт]
Скачиваний: 15
Вернуться к началу
 Профиль Отправить личное сообщение  
 
 Заголовок сообщения: Re: код Kotlin & Java
Непрочитанное сообщениеДобавлено: 05 июн 2017, 14:05 
Не в сети
Писатель
Аватара пользователя

Зарегистрирован: 24 сен 2011, 14:22
Сообщения: 10110
Откуда: Харьков
Olej писал(а):
Тестирую функции (и функции-методы), как наиболее сильно отличающуюся часть...

Не менее интересной (и отличительной) стороной Kotlin есть их концепция классов и их иерархии (см. Классы и наследование).
Их классы позволяют наследование и переопределение методов только (и там) если автор базового класса (суперкласса) явно разрешает это в определении класса, указывая oprn и override (или определив его как abstract):
Цитата:
Ключевое слово open является противоположностью слову final в Java: оно позволяет другим классам наследоваться от данного. По умолчанию, все классы в Kotlin имеют статус final,

Цитата:
Стойте! Как мне теперь хакнуть свои библиотеки?

При нашем подходе к переопределению классов и их членов (которые по дефолту final) будет сложно унаследоваться от чего-нибудь внутри используемых вами библиотек для того, чтобы переопределить не предназначенный для этого метод и внедрить туда свой гнусный хак.

Там есть ещё ряд интересных частностей:
Цитата:
Изолированные классы (sealed classes)
Классы данных (data classes)
Вложенные классы (nested classes)
Классы-перечисления (enum classes)

Так что для тестирования разных замысловатых конструкций с классами имеет смысл строить отдельное тестирующее приложение, по типу такого же как для функций: test_class.kt.


Вернуться к началу
 Профиль Отправить личное сообщение  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 26 ]  На страницу Пред.  1, 2, 3

Часовой пояс: UTC + 3 часа


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Перейти:  
cron
Создано на основе phpBB® Forum Software © phpBB Group
Русская поддержка phpBB
[ Time : 0.149s | 20 Queries | GZIP : On ]