Обозначение композиции функции высшего порядка - PullRequest
1 голос
/ 27 мая 2019

Я работаю с этой функцией составления высшего порядка:

fun <T, U, V> higherCompose(): ((U) -> V) -> ((T) -> U) -> (T) -> V =
    { f ->
        { g ->
            { x -> f(g(x)) }
        }
    } 

и приложение:

 val cos = higherCompose<Double, Double, Double>()()
{ x: Double -> Math.sin(x)}() { x : Double -> Math.PI/2  - x }

Я понимаю, чего мы пытаемся достичь математически. Но то, с чем я борюсь, это обозначения и значение программирования:

Что именно такое

higherCompose<Double>()

И почему мы применяем к нему столь странные значения:

1. () () 
2. { function1} { function 1} 

Ответы [ 2 ]

1 голос
/ 28 мая 2019

Вот как эта нотация анализируется и что вызывает функция:

higherCompose<Double, Double, Double>()() { x -> Math.sin(x) }() { x -> Math.PI/2  - x }
|                                    ^| ^ ^^^^^^^^^^^^^^^^^^^| ^ ^^^^^^^^^^^^^^^^^^^^^^|
|                                    1| 2          3         | 4           5           | 
|_____________________________________|______________________|_________________________|
| first call                          | second call          | third call              |
  1. Это начальный вызов без аргумента higherCompose, который возвращает значение точно возвращаемого типа higherCompose, ((U) -> V) -> ((T) -> U) -> (T) -> V, с тремя параметрами типа, замененными на Double.

  2. Эти скобки просто используются для устранения неоднозначности при разборе. Kotlin позволяет вызывать функцию с лямбдой в любой из форм: f({ }), f() { }, f { }. Если вы удалите скобки, лямбда, помеченная как (3), будет рассматриваться как аргумент первого вызова. Один из способов решения этой неоднозначности - добавить (), чтобы сообщить компилятору, что вызывается возвращаемое значение (1), а не higherCompose

  3. Следовательно, эта лямбда-выражение передается в качестве аргумента ((U) -> V) типу результата higherCompose, что приводит к ((T) -> U) -> (T) -> V.

  4. Эти скобки добавлены, потому что Kotlin не позволяет вызывать возвращаемое значение вызова с лямбда-выражением вне скобок (f() { }) напрямую с другой лямбда-выражением: f() { } { } запрещено, но добавление другой пары скобок между лямбда решает это: f() { }() { } означает вызов результата f с лямбдой.

  5. Эта лямбда-выражение передается в качестве аргумента ((T) -> U) типу результата (3), и результатом этого вызова является (T) -> V

Вы можете получить гораздо менее загадочную версию этого выражения, если пропустите все лямбда-выражения в скобках (форма f({ }) вместо f() { } или f { }):

higherCompose<Double, Double, Double>()({ x -> Math.sin(x) })({ x -> Math.PI / 2 - x })

См .: Лямбда-выражения и анонимные функции в справочнике по языку.

0 голосов
/ 28 мая 2019

Другим способом обработки композиции функций в Kotlin является использование функции расширения для типа функции. Попробуйте что-то вроде этого:

infix fun <P1, R1, R2> ((P1) -> R1).then(f: ((R1)-> R2)) : (P1) -> R2 {
    return { p1 : P1 -> f(this(p1)) }
}

Это позволяет вам использовать более простую конструкцию в вашем коде:

function1 then function1

Используя ваш пример выше, вы можете сделать:

infix fun <P1, R1, R2> ((P1) -> R1).then(f: ((R1)-> R2)) : (P1) -> R2 {
    return { p1 : P1 -> f(this(p1)) }
}

fun main() {
    val c = { x: Double -> Math.sin(x)} then { x : Double -> Math.PI/2  - x }
    println(c(2.4))
}

который печатает 0.8953331462437456.

Ознакомьтесь с моим Функциональным постом FizzBuzz , в котором используется этот подход.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...