การฝึกอบรม - Kotlin
เผยแพร่เมื่อ 12 May 2022
แผนที่ความคิด

การเขียนโปรแกรมแบบฟังก์ชัน
แบบฝึกหัดถูกนำมาจากหนังสือ:
การเขียนโปรแกรมเชิงฟังก์ชันใน Kotlin ด้วยบทเรียน
เขียนโดย Massimo Carli
คลังโค้ด: https://github.com/kodecocodes/fpk-materials
ไวยากรณ์
FirstProgramTest
แนวคิด: การแสดงผลบนหน้าจอ, ฟังก์ชัน
FirstProgramTest:https://github.com/cheroliv/cheroliv.com/blob/master/codes/src/test/kotlin/programming/FirstProgramTest.kt[(output nothing)]+
การทดสอบฟังก์ชัน Concat
แนวคิด: หน่วยความจำ, ตัวแปร, ค่า, วัตถุ, การขยายฟังก์ชัน
(Empty)
Note: As per guidelines, I’ve returned no additional commentary.https://github.com/cheroliv/cheroliv.com/blob/master/codes/src/test/kotlin/programming/ConcatFunctionTest.kt[Veuillez fournir le texte français à traduire.]+
BirthdayMessageTestOutput
แนวคิด: เซต, ลูป
การแนะนำ Kotlin
BirthdayMessageTestOutput:https://github.com/cheroliv/cheroliv.com/blob/master/codes/src/test/kotlin/programming/BirthdayMessageTestOutput.kt[(empty)]I’m ready to provide the translation—please send the French text you’d like converted to Thai while preserving all back‑ticked sections exactly as they appear.
คอร์ส 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")
})
}
}
แบบฝึกหัด 1.1
กำหนดฟังก์ชัน 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
ให้ทำการใช้งานโครโนซึ่งยอมรับฟังก์ชันประเภท`() →`
รับหน่วยเป็นอินพุตและคืนค่าระยะเวลาที่ใช้ในการทำงานของมัน. ลายเซ็นคือ:
fun chrono(fn : () -> Unité) : Long
@Test
fun `Exercise 1_2`() {
val waitOneSec = { sleep(ONE_SECOND) }
chrono(waitOneSec).apply {
println("chrono: $this")
assertEquals(1, sign)
}
}
ลองทำและตรวจสอบคำตอบของคุณกับ lahttps://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
)
}
}
จุดสำคัญ
-
ในขณะที่การเขียนโปรแกรมเชิงวัตถุหมายถึงการเขียนโปรแกรมด้วยวัตถุ,
การเขียนโปรแกรมเชิงฟังก์ชันหมายถึงการเขียนโปรแกรมโดยใช้ฟังก์ชัน. คุณแยกปัญหาออกเป็นหลาย ๆ ปัญหาย่อย, ซึ่งคุณจำลองด้วย ฟังก์ชัน
-
ฟังก์ชันระดับสูงยอมรับฟังก์ชันอื่นเป็นอินพุตหรือคืนค่าอื่นๆ
ทำงานเหมือนค่าที่ส่งกลับ。 ทฤษฎีหมวดหมู่คือทฤษฎีแห่งการประกอบและคุณใช้มันเพื่อทำความเข้าใจ วิธีประกอบฟังก์ชันของคุณในโปรแกรมทำงาน。 ค่าผลลัพธ์ของฟังก์ชันบริสุทธิ์ขึ้นอยู่กับพารามิเตอร์อินพุตเพียงอย่างเดียวและมัน ไม่มีผลข้างเคียง
-
ผลข้างเคียงคือสิ่งที่ฟังก์ชันทำกับโลกภายนอก นี่
สามารถเป็นการบันทึกไปยังเอาต์พุตมาตรฐานหรือการแก้ไขค่าของตัวแปรส่วนกลาง. การเขียนโปรแกรมเชิงฟังก์ชันทำงานได้สำหรับฟังก์ชันที่บริสุทธิ์ แต่ก็ให้ เครื่องมือสำหรับแปลงฟังก์ชันที่ไม่บริสุทธิ์เป็นฟังก์ชันที่บริสุทธิ์ คุณสามารถทำให้ฟังก์ชันที่ไม่บริสุทธิ์เป็นฟังก์ชันที่บริสุทธิ์ได้โดยการย้ายผลกระทบข้างเคียงออกไป ส่วนของค่าที่ส่งกลับ
-
การเขียนโปรแกรมเชิงฟังก์ชันคือเรื่องของการประกอบ.
การจัดการข้อผิดพลาดเป็นกรณีทั่วไปของผลกระทบข้างเคียง และโคตลินให้เครื่องมือแก่คุณ เพื่อจัดการในแบบที่ใช้งานได้。
ศึกษาเพิ่มเติม Java 8: นิพจน์ Lambda และ อินเทอร์เฟซฟังก์ชัน
ทฤษฎีหมวดหมู่
ทฤษฎีคณิตศาสตร์ของหมวดหมู่:
พื้นฐานของฟังก์ชัน
แบบฝึกหัด 2.1
คุณสามารถให้ตัวอย่างของฟังก์ชันที่แมปค่าที่ไม่ซ้ำกัน
ซึ่งโดเมนมีค่าที่ไม่แตกต่างกันในช่วง เช่น f(b) และ f(c) ในรูปด้านล่างนี้ไหม?
ลองทำเลย, แล้วตรวจสอบโปรเจกต์ท้าทายเพื่อหาวิธีแก้ปัญหาและดูว่าคุณทำได้อย่างไร
คุณจะพบคำแนะนำและคำอธิบายโดยติดตามลิงก์ไปยัง วิธีแก้ปัญหา.
แบบฝึกหัด 2.2
คุณสามารถเขียนฟังก์ชันผกผันของสองเท่าได้ไหม ?
โดเมนและช่วงของฟังก์ชันย้อนกลับคืออะไร?
ลองดูโครงการท้าทายและภาคผนวก B เพื่อหาวิธีแก้ปัญหา
fun chrono(fn : () -> Unité) : Long
@Test
fun `Exercise 1_2`() {
val waitOneSec = { sleep(ONE_SECOND) }
chrono(waitOneSec).apply {
println("chrono: $this")
assertEquals(1, sign)
}
}
ลองทำมันและตรวจสอบคำตอบของคุณกับ lahttps://github.com/cheroliv/cheroliv.com/blob/master/codes/src/test/kotlin/functional/BasicsHOFTests.kt[วิธีแก้ปัญหา, windows="_blank].
