ML (שפת תכנות) – הבדלי גרסאות

תוכן שנמחק תוכן שנוסף
עריכה: תבנית שפת תכנות
מ ←‏דוגמאות: עיצוב
שורה 37:
=== עצרת ===
פונקציית ה[[עצרת]] מבוטאת כ-ML בצורתה הטהורה, כלומר ללא תוצאות לוואי פרט לחישוב ערך הפונקציה:
<source lang="ocaml">
<div style="direction: ltr;">
fun fac (0 : int) : int = 1
| fac (n : int) : int = n * fac (n - 1)
</divsource>
 
כאן הגדרנו את פונקציית העצרת כפונקציה רקורסיבית, עם תנאי עצירה יחיד. זוהי דרך דומה לזו שבה מוגדרת הפונקציה במתמטיקה. הרבה קוד ML
דומה ל[[מתמטיקה]] בכלים שלו ובתחביר.
שורה 46 ⟵ 47:
חלק מההגדרה שהוצגה כאן היא אופציונלית, ומתארת את הטיפוסים של הפונקציה. הסימון E : t ניתן להיקרא כ"לביטוי E יש טיפוס t". לדוגמה, הארגומנט n מקבל את הטיפוס '''מספר שלם''' (int), ותוצאת הפעלת הפונקצייה (fac (n: int מקבלת את הטיפוס int גם כן. הפונקציה כולה מקבלת בהתאם את הטיפוס "פונקציה ממספר שלם למספר שלם" (int -> int). הודות למנגנון הסקת הטיפוסים, ניתן לוותר על כתיבת הטיפוסים במפורש ואלו יוסקו על ידי המפרש או המהדר של השפה.
כתיבה מחדש של הדוגמה ללא הטיפוסים תראה כך:
<source lang="ocaml">
<div style="direction: ltr;">
fun fac 0 = 1
| fac n = n * fac (n - 1)
</divsource>
 
הפונקציה מתבססת גם על התאמת-תבניות, מנגנון חשוב בתכנות בשפת ML. כמו כן, פרמטרים לפונקציה לא בהכרח נמצאים בתוך סוגריים (כמו ברוב שפות התכנות הנפוצות) אלא מופרדים ברווח (אוסף פרמטרים בתוך סוגריים ייחשב כפרמטר אחד, מסוג [[טיפוס נתונים#Tuple|Tuple]]). כאשר הארגומנט לפונקציה הוא 0 יוחזר המספר 1. לכל מקרה אחר תיבחר השורה השנייה לפעולה. זהו החלק ה[[רקורסיה|רקורסיבי]], והפונקציה תיקרא שוב ושוב עד שיגיע מקרה השפה - ארגומנט 0.
 
המימוש הזה של פונקציית העצרת איננו מובטח שיעצור, כיוון שארגומנט שלילי יגרום לשרשרת אינסופית של קריאות רקורסיביות. מימוש יציב יותר יבדוק שהארגומנט הינו אי-שלילי, בצורה הבאה:
<source lang="ocaml">
<div style="direction: ltr;">
fun fact n = let
fun fac 0 = 1
שורה 61 ⟵ 63:
else fac n
end
</divsource>
 
המקרה הבעייתי (מספר שלילי) מנוהל בעזרת מנגנון ה[[טיפול בחריגות (תכנות)|טיפול בחריגות]] של השפה.
 
הפונקציה יכולה להיכתב בצורה יעילה יותר על ידי שימוש ברקורסיית-זנב, כלומר רקורסיה שבה לא מבוצע כל חישוב לאחר הקריאה הרקורסיבית בפונקציה הקוראת, וה[[מחסנית (מבנה נתונים)]] לא תצטרך לגדול ביחס ישר למספר הקריאות לפונקציה. זאת ניתן להשיג בעזרת שימוש פרמטר נוסף, "צובר" (Accumulator) עבור הפונקציה הפנימית:
<source lang="ocaml">
<div style="direction: ltr;">
fun factorial n = let
fun fac (0, acc) = acc
| fac (n, acc) = fac (n - 1, n*acc)
שורה 73 ⟵ 76:
else fac (n, 1)
end
</divsource>
 
== ראו גם ==