กฎขอบเขตแบบเล็กซิคัล
ทำความเข้าใจว่า R ค้นหาตัวแปรอย่างไรโดยค้นหาใน environment ของ parent
กฎขอบเขตแบบเล็กซิคัล เป็นบทเรียน R Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน R Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส R Academy มีบทเรียนทั้งหมด 4 บทเรียน
การกำหนดขอบเขตแบบเลกซิคัลคืออะไร
การกำหนดขอบเขตแบบเลกซิคัล หมายความว่า ฟังก์ชันจะค้นหาตัวแปรจากตำแหน่งที่ฟังก์ชันถูกกำหนด ไม่ใช่ตำแหน่งที่ฟังก์ชันถูกเรียกใช้ R ใช้การกำหนดขอบเขตแบบเลกซิคัล ซึ่งคาดเดาได้ เพราะสภาพแวดล้อมที่ฟังก์ชันค้นหาจะถูกกำหนดตายตัวเมื่อสร้างฟังก์ชัน ไม่ใช่เมื่อเรียกใช้
x <- 'global'
f <- function() {
cat('x =', x, '\n') # looks where f was defined (global)
}
local({
x <- 'local to local block'
f() # still prints global x, not the local one
})การกำหนดขอบเขตแบบเลกซิคัลกับแบบไดนามิก
ในการกำหนดขอบเขตแบบไดนามิก (ซึ่งใช้ในภาษาอื่นบางภาษา) ฟังก์ชันจะพบตัวแปรในสภาพแวดล้อมของผู้เรียกใช้ แต่ R ใช้การกำหนดขอบเขตแบบเลกซิคัลแทน นั่นคือสภาพแวดล้อมที่ครอบอยู่ในขณะกำหนดฟังก์ชันจะมีผลเสมอ ทำให้ฟังก์ชันทำงานอย่างสม่ำเสมอไม่ว่าจะถูกเรียกจากที่ใด
val <- 100
make_adder <- function(n) {
# n is captured from the definition environment
function(x) x + n
}
add10 <- make_adder(10)
add20 <- make_adder(20)
cat(add10(5), '\n') # 15 — n=10 from definition
cat(add20(5), '\n') # 25 — n=20 from definitionตัวแปรอิสระและคลอเชอร์
ตัวแปรภายในฟังก์ชันที่ไม่ใช่พารามิเตอร์หรือการกำหนดค่าในฟังก์ชัน จะเรียกว่าตัวแปรอิสระ R จะค้นหาตัวแปรนี้ในสภาพแวดล้อมที่ครอบอยู่ ฟังก์ชันที่เก็บตัวแปรอิสระไว้จะเรียกว่าคลอเชอร์
base_rate <- 0.05 # free variable captured by f
f <- function(principal, years) {
principal * (1 + base_rate) ^ years
}
cat('5 yr return:', f(1000, 5), '\n')
# Even if we change base_rate later:
base_rate <- 0.08
cat('New rate return:', f(1000, 5), '\n')คลอเชอร์เก็บสภาพแวดล้อมไว้
ทุกครั้งที่เรียกฟังก์ชันโรงงาน ฟังก์ชันที่ส่งคืน (คลอเชอร์) จะเก็บภาพสถานะของสภาพแวดล้อมที่ครอบอยู่ไว้ การเรียกแต่ละครั้งจึงสร้างคลอเชอร์ที่มีค่าซึ่งเก็บไว้แตกต่างกัน ซึ่งเป็นพื้นฐานของฟังก์ชันโรงงาน
power_fn <- function(exp) {
function(x) x ^ exp
}
square <- power_fn(2)
cube <- power_fn(3)
cat('square(4) =', square(4), '\n')
cat('cube(3) =', cube(3), '\n')ตัวดำเนินการ <<-
<<- (การกำหนดค่าแบบลูกศรคู่) จะค้นหาการผูกชื่อที่มีอยู่ตามสายโซ่สภาพแวดล้อมแม่ แล้วแก้ไขค่าดังกล่าวโดยตรง หากไม่พบการผูกชื่อ จะสร้างขึ้นในสภาพแวดล้อมส่วนกลาง ตัวดำเนินการนี้ใช้สำหรับแก้ไขตัวแปรในขอบเขตที่ครอบอยู่จากภายในฟังก์ชัน
count <- 0
increment <- function() {
count <<- count + 1
}
increment()
increment()
increment()
cat('count:', count, '\n')<<- กับคลอเชอร์
การใช้ <<- ที่เป็นรูปแบบตามธรรมเนียมมากที่สุด คือใช้ภายในคลอเชอร์ที่ต้องอัปเดตสถานะในสภาพแวดล้อมที่ครอบอยู่ วิธีนี้จะสร้างฟังก์ชันที่มีสถานะ ซึ่งมีหน่วยความจำคงอยู่ระหว่างการเรียกใช้
make_counter <- function() {
n <- 0
list(
increment = function() n <<- n + 1,
get = function() n,
reset = function() n <<- 0
)
}
ctr <- make_counter()
ctr$increment()
ctr$increment()
cat('Count:', ctr$get(), '\n')
ctr$reset()
cat('After reset:', ctr$get(), '\n')การกำหนดขอบเขตในฟังก์ชันซ้อนกัน
เมื่อฟังก์ชันซ้อนกัน ฟังก์ชันด้านในจะมองเห็นตัวแปรที่กำหนดไว้ในฟังก์ชันด้านนอก สภาพแวดล้อมของฟังก์ชันด้านนอกจะกลายเป็นสภาพแวดล้อมที่ครอบอยู่ของฟังก์ชันด้านใน และก่อเป็นสายโซ่
outer <- function() {
greeting <- 'Hello'
inner <- function(name) {
# greeting comes from outer's environment
paste(greeting, name)
}
inner('World')
}
cat(outer(), '\n')การค้นหาตามสายโซ่ขอบเขต
เมื่อ R ค้นหาตัวแปร จะค้นหาสภาพแวดล้อมตามลำดับดังนี้: ของฟังก์ชันเอง → ที่ครอบอยู่ → ที่ครอบสภาพแวดล้อมนั้น → ... → ส่วนกลาง → เส้นทางการค้นหา → พื้นฐาน → ว่างเปล่า ผลลัพธ์แรกที่พบจะถูกใช้
x <- 'global'
f <- function() {
x <- 'local to f'
g <- function() {
# g has no x, so looks in f's env
cat('g sees x =', x, '\n')
}
g()
}
f()environment() ของฟังก์ชัน
คุณสามารถตรวจสอบสภาพแวดล้อมที่ครอบอยู่ของฟังก์ชันใด ๆ ด้วย environment(f) และยังตั้งค่าได้ด้วย environment(f) <- e ซึ่งจะเปลี่ยนตำแหน่งที่ฟังก์ชันใช้ค้นหาตัวแปรอิสระ วิธีนี้มีพลังมากแต่เป็นเทคนิคขั้นสูง
x <- 'global_x'
f <- function() x
cat('f sees:', f(), '\n')
# Change f's enclosing environment
my_env <- new.env(parent = emptyenv())
my_env$x <- 'env_x'
environment(f) <- my_env
cat('f now sees:', f(), '\n')คลอเชอร์ภาคปฏิบัติ: การจำผลลัพธ์
การกำหนดขอบเขตแบบเลกซิคัลร่วมกับ <<- ช่วยให้ทำการจำผลลัพธ์ได้ โดยเก็บผลลัพธ์ของฟังก์ชันที่ใช้เวลาคำนวณสูงไว้ในสภาพแวดล้อมของคลอเชอร์ แคชนี้เป็นข้อมูลส่วนตัวของคลอเชอร์และคงอยู่ระหว่างการเรียกใช้
make_memoized_fib <- function() {
cache <- c()
function(n) {
if (!is.null(cache[n])) return(cache[n])
if (n <= 1) { cache[n] <<- n; return(n) }
result <- Recall(n-1) + Recall(n-2)
cache[n] <<- result
result
}
}
fib <- make_memoized_fib()
cat(sapply(0:8, fib), '\n')ข้อควรระวังของการกำหนดขอบเขตแบบเลกซิคัล: ตัวแปรในลูป
ข้อผิดพลาดที่พบบ่อยคือการสร้างคลอเชอร์ภายในลูป คลอเชอร์ทั้งหมดจะเก็บสภาพแวดล้อมเดียวกันไว้ ไม่ใช่สำเนาของค่า เมื่อถูกเรียกใช้ ตัวแปรในลูปจึงมีค่าครั้งสุดท้ายไปแล้ว
fns <- vector('list', 3)
for (i in 1:3) {
local({
captured_i <- i
fns[[captured_i]] <<- function() captured_i
})
}
cat(fns[[1]](), fns[[2]](), fns[[3]](), '\n')ตรวจสอบความเข้าใจอย่างรวดเร็ว
ในการกำหนดขอบเขตแบบเลกซิคัลของ R ฟังก์ชันจะค้นหาตัวแปรอิสระ (ตัวแปรที่ไม่ได้กำหนดไว้ในฟังก์ชันเอง) จากที่ใด
การกำหนดขอบเขตแบบเลกซิคัล: ประเด็นสำคัญ
ประเด็นสำคัญเกี่ยวกับการกำหนดขอบเขตแบบเลกซิคัล:
- R ใช้การกำหนดขอบเขตแบบเลกซิคัล ฟังก์ชันจะค้นหาตัวแปรจากตำแหน่งที่ถูกกำหนด
- ฟังก์ชันจะเก็บสภาพแวดล้อมที่ครอบอยู่ไว้เป็นคลอเชอร์
- ตัวแปรอิสระจะถูกแก้ไขการอ้างอิงเมื่อกำหนดฟังก์ชัน ไม่ใช่เมื่อเรียกใช้
<<-แก้ไขการผูกชื่อในสายโซ่สภาพแวดล้อมแม่ (หรือในส่วนกลางหากไม่พบ)- คลอเชอร์ +
<<-= ฟังก์ชันที่มีสถานะและสถานะส่วนตัวคงอยู่ - ข้อควรระวังเกี่ยวกับคลอเชอร์ในลูป: ใช้
local()เพื่อบังคับให้สร้างสภาพแวดล้อมใหม่ในแต่ละรอบ
make_multiplier <- function(factor) {
function(x) x * factor
}
double <- make_multiplier(2)
triple <- make_multiplier(3)
cat('double(7):', double(7), '\n')
cat('triple(7):', triple(7), '\n')
cat('double env factor:', get('factor', envir = environment(double)), '\n')คำถามที่พบบ่อย
บทเรียน “กฎขอบเขตแบบเล็กซิคัล” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “กฎขอบเขตแบบเล็กซิคัล” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส R Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส R Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “กฎขอบเขตแบบเล็กซิคัล”
ทำความเข้าใจว่า R ค้นหาตัวแปรอย่างไรโดยค้นหาใน environment ของ parent คุณปฏิบัติ R Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน R Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน R Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน
บทเรียน “กฎขอบเขตแบบเล็กซิคัล” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน R Academy นี้ได้ไหม
ได้ บทเรียน R Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- Environment ใน R คืออะไร
- กฎขอบเขตแบบเล็กซิคัล
- ขอบเขตส่วนกลางเทียบกับขอบเขตเฉพาะที่
- การสร้างและตรวจสอบ Environment