Котлин — состав функций — объяснение

#kotlin #functional-programming #function-composition

Вопрос:

Я слежу за некоторой видеопрезентацией библиотеки arrow от Kotlin о функциональном программировании. Я пришел к этому примеру композиции функций:

 val greaterThanThree = { it > 3 } 
val even = { it % 2 == 0 }
val greaterThanThreeAndEven = greaterThanThree compose even
 

тогда его можно использовать для чего-то вроде:

 list.filter(::greaterThanThreeAndEven)
 

Из моего предыдущего понимания композиции функции следует, что мы передаем параметр первой функции, а затем возвращаемое значение передается второй функции, как в этом примере:

 fun compose(f: (Int) -> Boolean, g: (Int) -> Boolean): (Int) -> Boolean = {
                                                                   x -> f(g(x)) }
 

Итак, я не знаю, правильно ли я понял, так как я еще не занимался функциональным программированием, но я думал, что шаги будут примерно такими:

val x = 8 передается в Greaterthantree(8) оценивается как -> true>
// тогда меня смущает то, что в соответствии с приведенной выше логикой истина будет передана даже, что не имеет смысла

даже(правда)

Может ли кто-нибудь объяснить мне, как составлены эти две функции и каковы шаги для этой результирующей составленной функции:

 { it > 3 amp;amp; it % 2 == 0 } 
 

Комментарии:

1. Можете ли вы сослаться на источник? Я не знаю Котлина, но это не похоже ни на какую функциональную композицию, которую я когда-либо видел….

2. @JaredSmith это видеоурок по библиотеке arrow, где показан пример Greaterthree и даже пример, пример начинается здесь: youtu.be/tM2wEI-e80E?t=157

3. Да, это так… по-другому? Предполагая, что это функции, вы правы в том, что что-то не так, в зависимости от того, как Kotlin относится к булам (на некоторых языках они являются подклассом int), которые либо не должны компилироваться (несоответствие типов), либо будут компилироваться, но давать неправильные ответы.

4. компилируется ли этот код без каких-либо ошибок?

Ответ №1:

compose это не amp;amp; так , это цепные вызовы функций.

В тексте определения вашей функции

 fun compose(f: (Int) -> Boolean, g: (Int) -> Boolean): (Int) -> Boolean = { x -> f(g(x)) }
 

g вызывается с параметром x , так что x должно быть an Int , и g(x) возвращает a Boolean .

Однако f вызывается с возвращаемым значением g в качестве параметра. Поскольку f требуется Int и g возвращает a Boolean , компилятор сообщает об ошибке:

 error: type mismatch: inferred type is Boolean but Int was expected
 

Если вы хотите создать логические функции, это может быть примером,

 fun booleanCompose(
    f: (Int) -> Boolean,
    g: (Int) -> Boolean,
    op: (Boolean, Boolean) -> Boolean,
): (Int) -> Boolean = {
    x -> op(f(x), g(x))
}

val greaterThanThree: (Int) -> Boolean = { it > 3 }
val even: (Int) -> Boolean = { it %2 == 0 }

val and: (Boolean, Boolean) -> Boolean = { b1, b2 -> b1 amp;amp; b2 }

val greaterThanThreeAndEven = booleanCompose(greaterThanThree, even, and)

 

Чтобы разрешить используемый вами синтаксис, необходима функция расширения с инфиксом:

 infix fun ((Int) -> Boolean).and(g: (Int) -> Boolean): (Int) -> Boolean = 
    booleanCompose(this, g, and)

val greaterThanThreeAndEven = greaterThanThree and even
 

Комментарии:

1. Да, это выглядит правильно, я действительно был смущен этим примером из учебника arrow, так странно, что они используют примеры, которые даже не могут скомпилироваться, потому что таких новичков, как я, легко спутать с такими неправильными примерами.

2. @Leff Я определенно не считаю себя новичком в FP, и это меня смутило. Я думаю, что это просто сбивает с толку лол.

3. @ДжареДсмит, это утешает