הגדרת פונקציה וקריאה לה
פונקציה ב-R היא ערך, כמו מספר או מחרוזת. בונים אחת עם מילת המפתח function ומצמידים אותה לשם עם <-, באותה צורה שבה שומרים כל דבר אחר במשתנה:
החלקים: function(x) מצהירה על פרמטר אחד בשם x, הסוגריים המסולסלים מכילים את הגוף, והקריאה square(4) מריצה את הגוף כש-x מוגדר ל-4. לגוף של שורה אחת הסוגריים המסולסלים אופציונליים, square <- function(x) x^2 היא אותה פונקציה, אבל עם סוגריים זה נקרא טוב יותר ברגע שהגוף גדל.
מכיוון שפונקציה היא סתם ערך, כל מה שאתם יודעים על משתנים חל עליה: אפשר לבצע לה השמה מחדש, להעביר אותה לפונקציה אחרת, או לשמור אותה ברשימה. העובדה האחת הזו מניעה חצי מה-R המקובל, כולל כל משפחת apply.
ערכי החזרה: הביטוי האחרון מנצח
פונקציה ב-R מחזירה את מה שהביטוי האחרון שהיא מעריכה מייצר. אין הוראת return חובה:
return() קיימת, והיא עובדת כמו שהייתם מצפים: היא עוצרת את הפונקציה מיד ומחזירה את הארגומנט שלה. R מקובלת שומרת אותה ליציאות מוקדמות: עצירה בראש הפונקציה כשקלט הופך את שאר העבודה לחסרת טעם. שלבו אותה עם בדיקות if-else:
כתיבת return(a / b) בשורה האחרונה לא הייתה שגויה, רק רעש. שמרו את return() ליציאות שקורות מוקדם, ותנו לביטוי האחרון לדבר בשם המסלול הרגיל.
ערכי ברירת מחדל וארגומנטים בעלי שם
לפרמטר יכול להיות ערך ברירת מחדל, שמוצהר עם = ברשימת הפרמטרים. מי שקורא לפונקציה ומרוצה מברירת המחדל פשוט משמיט את הארגומנט:
הקריאה השלישית מראה את החצי השני של הסיפור: ארגומנטים בעלי שם. כשכותבים name = "Ada" בנקודת הקריאה, המיקום מפסיק להיות חשוב: R מתאימה קודם לפי שם, ואז ממלאת את שאר הפרמטרים לפי מיקום. שני כללים מעשיים נובעים מזה:
- שימו פרמטרים חובה קודם ופרמטרים עם ברירת מחדל אחריהם, כך שקריאות לפי מיקום יישארו טבעיות.
- בנקודת הקריאה, תנו שם לכל ארגומנט שלא ברור מהמיקום שלו.
greet("Ada", punctuation = "?")ברור יותר מלגרום לקורא לספור פסיקים.
העברת ארגומנטים הלאה עם ...
הפרמטר המיוחד ... (נקרא "dots") פירושו "כל מספר של ארגומנטים נוספים". פונקציה שמצהירה על ... יכולה לקבל ארגומנטים שהיא מעולם לא פירטה ולהעביר אותם לפונקציה אחרת:
ל-shout() לא ידוע ולא אכפת כמה מילים אתם מעבירים: היא מגישה את כולן ל-paste(). שימו לב ש-punctuation מגיע אחרי ה-dots: כל פרמטר שמוצהר אחרי ... אפשר להגדיר רק לפי שם, וזה בדיוק מה שרוצים לאפשרויות. דפוס ההעברה הזה נמצא בכל מקום ב-base R: sapply(x, round, digits = 2) עובד כי sapply מעבירה את digits = 2 ל-round דרך ה-... שלה.
המחיר של dots הוא ששגיאות הקלדה חומקות בשקט: כתבו punctuation בטעות כ-punctation והוא פשוט ייבלע לתוך ... במקום להעלות שגיאה. שמרו על פונקציות שמשתמשות ב-dots קטנות.
פונקציות אנונימיות
כשצריך פונקציה רק פעם אחת, בדרך כלל כארגומנט לפונקציה אחרת, אפשר לוותר על השם לגמרי:
שתי השורות עושות את אותו הדבר. function(x) x^2 הוא הכתיב הקלאסי; \(x) x^2 הוא הקיצור שנוסף ב-R 4.1, שבו \ מחליף את המילה function. הם זהים מכל בחינה חוץ ממספר ההקשות: הקיצור אינו סוג אחר של פונקציה.
השתמשו בפונקציה אנונימית כשהפעולה היא שורה אחת שקשורה לנקודת קריאה אחת. ברגע שאתם מדביקים את אותה lambda בשני מקומות, או שהיא גדלה מעבר לשורה אחת, תנו לה שם: פונקציה עם שם אפשר לבדוק, והיא מתעדת את עצמה.
Scoping: מה פונקציה יכולה לראות
R משתמשת ב-lexical scoping: כשפונקציה צריכה משתנה שהיא לא מוצאת בין הפרמטרים וההשמות המקומיות שלה, היא מחפשת בסביבה שבה הפונקציה הוגדרה, לא במקום שבו קראו לה. בפועל זה אומר שפונקציה יכולה לקרוא משתנים מהסקריפט שסביבה:
הצד השני: השמה בתוך פונקציה לעולם לא דולפת החוצה. rate <- 0.5 בתוך change_inside יוצרת משתנה מקומי חדש שמת כשהפונקציה מחזירה ערך; ה-rate החיצוני עדיין מדפיס 0.1. זו תכונה: פונקציות לא יכולות לדרוס בטעות את סביבת העבודה שלכם, אבל זה מפתיע מתחילים שמצפים שההשמה הפנימית תישאר. אם פונקציה צריכה להעביר תוצאה לעולם החיצון, החזירו אותה ובצעו השמה בנקודת הקריאה. (יש אופרטור <<- שמגיע החוצה; התייחסו אליו כסימן לקוד בעייתי עד שאתם באמת צריכים אותו.)
דוגמה מלאה
הנה הדפוס שמשתלם: שימו לב שאתם חוזרים על שלוש שורות ניתוח, עטפו אותן בפונקציה, השתמשו בה שוב. נניח שאתם מסכמים שוב ושוב וקטורים של מדידות:
כל מה שבעמוד הזה נמצא שם: פרמטר digits עם ברירת מחדל, קריאה עם שם שדורסת אותו, וביטוי אחרון (round(out, digits)) שמבצע את ההחזרה. הפונקציה נקראת כמו משפט, עובדת על כל וקטור מספרי, ויושבת במקום אחד כשתחליטו להוסיף חציון.
מה לקחת מכאן
name <- function(args) { body }יוצרת פונקציה; הביטוי האחרון שמוערך הוא ערך ההחזרה שלה.return()מיועדת ליציאות מוקדמות, לא לשורה האחרונה הרגילה.- ברירות מחדל מוצהרות עם
=ברשימת הפרמטרים; ארגומנטים בעלי שם הופכים נקודות קריאה לבלתי תלויות בסדר ולקריאות. ...מקבל ומעביר הלאה כל ארגומנט נוסף: חזק, אבל מסתיר שגיאות הקלדה.function(x)ו-\(x)הם אותו דבר; השתמשו בפונקציות אנונימיות לשורות חד-פעמיות.- פונקציות קוראות משתנים מהמקום שבו הוגדרו; השמות בתוכן נשארות בתוכן.
הבא בתור: משפחת apply, הפונקציות שלוקחות את הפונקציות שלכם ומריצות אותן על וקטורים ורשימות שלמים.
שאלות נפוצות
איך יוצרים פונקציה ב-R?
מבצעים השמה של אובייקט function לשם: square <- function(x) { x^2 }. הפרמטרים נכנסים לסוגריים, הגוף נכנס לסוגריים המסולסלים, וקוראים לה כמו square(4). הביטוי האחרון שמוערך הוא מה שהפונקציה מחזירה.
האם צריך return() ב-R?
לא. פונקציה ב-R מחזירה אוטומטית את הערך של הביטוי האחרון שהיא מעריכה. return() קיימת, ו-R מקובלת שומרת אותה ליציאות מוקדמות: עצירה בראש הפונקציה כשקלט לא תקין או כשמקרה קצה טופל.
מה זו פונקציה אנונימית ב-R?
פונקציה שמגדירים בלי לתת לה שם, ובדרך כלל מעבירים אותה ישר לפונקציה אחרת: sapply(x, function(v) v^2). מאז R 4.1 יש גם את הקיצור \(v) v^2, שאומר בדיוק את אותו הדבר עם פחות הקשות.