آموزش - Kotlin
منتشر شده در 12 May 2022
نقشه ذهنی

برنامهنویسی تابعی
این execrices از کتاب گرفته شدهاند:
برنامهنویسی تابعی در Kotlin با آموزشها
نوشته شده توسط Massimo Carli
مخزن: https://github.com/kodecocodes/fpk-materials
سینتکس
اولین تست برنامه
مفاهیم: نمایش صفحه، عملکرد
تست برنامه اول:https://github.com/cheroliv/cheroliv.com/blob/master/codes/src/test/kotlin/programming/FirstProgramTest.kt[source]+
ConcatFunctionTest
مفاهیم: حافظه، متغیر، مقدار، شیء، گسترش تابع
نمونه تست واحد:https://github.com/cheroliv/cheroliv.com/blob/master/codes/src/test/kotlin/programming/ConcatFunctionTest.kt[منبع]+
BirthdayMessageTestOutput
مفاهیم: مجموعهها، حلقات
معرفی به کاتلین
BirthdayMessageTestOutputhttps://github.com/cheroliv/cheroliv.com/blob/master/codes/src/test/kotlin/programming/BirthdayMessageTestOutput.kt[منبع]+
دوره Kotlin
اساسهای عملکردی
رویکرد اعلانی-اجباری X
package functional
import kotlin.test.Test
import kotlin.test.assertEquals
class DeclarativeTests {
val input = listOf(
"123", "abc", "1ds", "987", "abdf", "1d3", "de1", "88", "101"
)
fun imperativeSum(list: List<String>): Int {
var sum = 0
for (item in list) {
try {
sum += item.toInt()
} catch (_: NumberFormatException) {
}
}
return sum
}
@Test
fun `test imperative approach`() {
imperativeSum(input).run {
println("Sum $this")
assertEquals(1299, this)
}
}
fun isValidNumber(s: String) = try {
s.toInt()
true
} catch (_: NumberFormatException) {
false
}
fun declarativeSum(list: List<String>) = list
.filter(::isValidNumber)
.map(String::toInt)
.sum()
@Test
fun `test declarative approach`() {
assertEquals(1299, declarativeSum(input).apply {
println("Sum $this")
})
}
}
تمرین ۱.۱
تابع sumInRange را پیادهسازی کنید که مقادیر را در
یک List<String> در یک بازه معین. امضا به صورت زیر است :
fun sumInRange(input: List<String>, range: IntRange): Int
@Test
fun `Exercise 1_1`() {
assertEquals(4, sumInRange(
listOf("1", "10", "a", "7", "ad2", "3"),
1..5
).apply { println("sumInRange 1..5: $this") }
)
}
امتحان کنید و پاسخ خود را باhttps://github.com/cheroliv/cheroliv.com/blob/master/codes/src/test/kotlin/functional/DeclarativeTests.kt[حل, windows="_blank].
توابعهای رتبه بالاتر
package functional
import java.io.ByteArrayOutputStream
import java.io.PrintStream
import java.lang.System.*
import java.lang.Thread.sleep
import kotlin.math.sign
import kotlin.test.Test
import kotlin.test.assertEquals
class BasicsHOFTests {
val ONE_SECOND = 1000L
@Test
fun `high order function`() {
//capture de la sortie standard
val standardOut: PrintStream? = out
val outputStreamCaptor = ByteArrayOutputStream()
setOut(PrintStream(outputStreamCaptor))
3.times { println("Hello") }
assertEquals(
buildString {
repeat(3) { append("Hello\n") }
deleteAt(length - 1)
}, outputStreamCaptor
.toString()
.trim()
)
//libération de la sortie standard
setOut(standardOut)
}
fun Int.times1(fn: () -> Unit) {
for (i in 1..this) {
fn()
}
}
fun Int.times2(fn: () -> Unit) {
for (i in 1..this) fn()
}
fun Int.times3(fn: () -> Unit) =
(1..this).forEach { fn() }
fun Int.times4(fn: () -> Unit) =
repeat((1..this).count()) { fn() }
fun Int.times(fn: () -> Unit) =
(1..this).forEach { _ -> fn() }
}
تمرین 1.2
پیادهسازی chrono که یک تابع از نوع را میپذیرد`() →`
واحد در ورودی و زمان صرف شده برای اجرا آن را برمیگرداند. امضای آن:
fun chrono(fn : () -> Unité) : Long
@Test
fun `Exercise 1_2`() {
val waitOneSec = { sleep(ONE_SECOND) }
chrono(waitOneSec).apply {
println("chrono: $this")
assertEquals(1, sign)
}
}
آن را امتحان کنید و پاسخ خود را باhttps://github.com/cheroliv/cheroliv.com/blob/master/codes/src/test/kotlin/functional/BasicsHOFTests.kt[حل، windows="_blank].
ترکیب
package functional
import kotlin.test.Test
import kotlin.test.assertEquals
fun double(x: Int): Int = 2 * x
fun square(x: Int): Int = x * x
fun squareAndDouble1(x: Int) = double(square(x))
infix fun <A, B, C> ((A) -> B).compose(g: (B) -> C)
: (A) -> C = { a -> g(this(a)) }
class CompositionTests {
@Test
fun composition_impure() {
assertEquals(200, double(square(10)))
assertEquals(200, squareAndDouble1(10))
}
@Test
fun composition_pure() {
val squareAndDouble = ::square compose ::double
assertEquals(200, squareAndDouble(10))
}
}
توابع صاف و قابلیت تست
package functional
import java.io.ByteArrayOutputStream
import java.io.PrintStream
import java.lang.System.out
import java.lang.System.setOut
import kotlin.test.Test
import kotlin.test.assertEquals
var count = 0
//impure car une variable global subit un effet de bord
fun impure(value: Int): Int {
count++
return value + count
}
//impure car utilisation de la sortie standard qui fait muter le system
fun addOneAndLog(x: Int): Int {
val result = x + 1
println("New Value is $result")
return result
}
//pure
fun addOne(x: Int) = (x + 1).run {
Pair(this, "New Value is $this")
}
class PureTests {
@Test
fun `impure fonction`() {
assertEquals(3, impure(2))
val standardOut = out
val outputStreamCaptor = ByteArrayOutputStream()
setOut(PrintStream(outputStreamCaptor))
addOneAndLog(3)
assertEquals(
"New Value is 4",
outputStreamCaptor
.toString()
.trim()
)
setOut(standardOut)
}
@Test
fun `pure fonction`() {
addOne(3).run {
assertEquals(4, first)
assertEquals("New Value is 4", second)
}
}
}
مدیریت استثناها
package functional
import org.junit.jupiter.api.assertThrows
import kotlin.Result.Companion.failure
import kotlin.Result.Companion.success
import kotlin.test.Test
import kotlin.test.assertEquals
//NumberFormatException est un effet de bord qui rend la fonction impure
fun strToInt(str: String) = str.toInt()
//pure
fun strToIntOrNull(str: String) = try {
str.toInt()
} catch (nfe: NumberFormatException) {
null
}
//pure avec gestion de l'exception plus élégante
fun strToIntResult(str: String): Result<Int> =
try {
success(str.toInt())
} catch (nfe: NumberFormatException) {
failure(nfe)
}
class ExceptionHandlingTests {
@Test
fun impure() {
assertThrows<NumberFormatException> { strToInt("foo") }
assertEquals(1, strToInt("1"))
}
@Test
fun pure() {
assertEquals(null, strToIntOrNull("foo"))
assertEquals(1, strToIntOrNull("1"))
}
@Test
fun `pure avec result`() {
assertEquals(1, strToIntResult("1").getOrNull())
assertEquals(
"For input string: \"foo\"",
strToIntResult("foo")
.exceptionOrNull()
?.message
)
}
}
نقطههای کلیدی
-
در حالی که برنامهنویسی شیءگرا به این معنی است که برنامهنویسی با اشیاء انجام شود،
برنامهنویسی تابعی یعنی برنامهنویسی با توابع شما یک مشکل را به چندین زیرمسئله تقسیم میکنید، که آنها را با توابع.
-
توابع از رتبه بالاتر توابع دیگر را بهعنوان ورودی میپذیرند یا توابع دیگر را برمیگردانند
مثل مقادیر برگشتی عمل میکنند. نظریهی دستهها است نظریهی ترکیب، و شما از آن برای درک استفاده میکنید چگونه توابع خود را در یک برنامه کاری ترکیب کنید. مقدار خروجی یک تابع پاک فقط به پارامترهای ورودی آن بستگی دارد، و آن اثرات جانبی ندارد.
-
یک اثر جانبی چیزی است که یک عملکرد در دنیای خارجی انجام میدهد. این
ممکن است یک لاگ در خروجی استاندارد یا تغییر مقدار یک متغیر سراسری باشد. برنامهنویسی عملکردی برای توابع خالص کار میکند، اما همچنین آنها را فراهم میسازد ابزارها برای تبدیل توابع ناصاف به توابع صاف. میتوانید یک تابع ناپاک را به یک تابع پاک تبدیل کنید با جابهجایی اثرات تا آنها را پاک کنید بخش از مقدار بازگشتی
-
برنامهنویسی تابعی مسألهٔ ترکیب است.
مدیریت خطاها یک مورد عادی از اثرات جانبی است، و Kotlin ابزارهای لازم را برای شما فراهم میکند. برای مدیریت آنها به صورت عملکردی.
عمیق کردن java8: عبارات lambda و واجهات عملکردی
نظریهٔ دستهها
نظریه ریاضی دستهها:
مبانی توابع
تمرین ۲.۱
میتوانید یک مثال از تابعی که مقادیر متمایز را به یکدیگر نگاشت میکند بنویسید؟
دامنهی آن چه مقادیری که متمایز نیستن در بازه، مثل f(b) و f(c) در شکل زیر؟
انجام بده، سپس پروژه چالش را برای یک راهحل بررسی کنید تا ببینید چقدر خوب انجام دادید.
شما مشاوره و توضیحی را با دنبال کردن لینک به … حل.
تمرین ۲.۲
میتوانید معکوس تابع دو برابر را بنویسید؟
دامنه و بازه برای معکوس تابع چیست؟
ببینید پروژه چالش و ضمیمه ب برای راهحل.
fun chrono(fn : () -> Unité) : Long
@Test
fun `Exercise 1_2`() {
val waitOneSec = { sleep(ONE_SECOND) }
chrono(waitOneSec).apply {
println("chrono: $this")
assertEquals(1, sign)
}
}
آن را امتحان کنید و پاسخ خود را باhttps://github.com/cheroliv/cheroliv.com/blob/master/codes/src/test/kotlin/functional/BasicsHOFTests.kt[راهحل, windows="_blank].
