Monday, June 24, 2013

Scheme պրոցեդուրաները

Scheme ծրագրավորման լեզվում պրոցեդուրաները սահմանվում են lambda ծառայողական բառով, որին հետևում են արգումենտների ցուցակը և պրոցեդուրայի մարմինը կազմող արտահայտությունները։ Օրինակ, կարող եմ սահմանել տրված երկու թվերի քառակուսիների գումարը հաշվող պրոցեդուրա․

(lambda (x y) (+ (* x x) (* y y)))

Սա x և y ֆորմալ արգումենտներով պրոցեդուրա է։ Եթե ուզենամ այն կիրառել 3 կամ 4 արգումենտների նկատմամբ, ապա պետք է գրեմ․

((lambda (x y) (+ (* x x) (* y y))) 3 4)  ; => 25

Այս անհարմար գրառումից խուսափելու համար կարող եմ պրոցեդուրային անուն տալ՝ define ծառայողական բառի օգնությամբ այն կապելով որևէ սիմվոլի հետ.

(define sum-squares
    (lambda (x y) (+ (* x x) (* y y))))

Եվ արդեն կարող եմ պրոցեդուրան արգումենտների նկատմամբ կիրառել sum-squares անունով։

(sum-squares 3 4)  ; => 25

Պրոցեդուրայի սահմանումն ավելի համառոտ կարելի է գրել առանց lambda ծառայողական բառի օգտագործման՝ define սահմանման առաջին արգումենտը դարձնելով ցուցակ, որի առաջին տարրը սահմանվող պրոցեդուրայի անունն է, իսկ հաջորդողները՝ ֆորմալ արգումենտները։ Օրինակ,

(define (sum-squares x y)
    (+ (* x x) (* y y)))

Ես նախնտրում եմ lambda-ի օգտատգործմամբ տարբերակը։ Կարծում եմ, որ դա ավելի համահունչ է define բառի հետ։

Հիմա, ենթադրենք, պետք է սահմանել պրոցեդուրա, որը իրար է գումարում տրված թվերը։ Առաջին միտքն այն է, որ սհամանել մեկ արգումենտով պրեցեդուրա և նրան փոխանցել թվերի ցուցակը։ Օրինակ այսպես.

(define sum-list
    (lambda (l)
        (if (null? l)
            0
            (+ (car l) (sum-list (cdr l))))))

Սա ռեկուրսիվ պրոցեդուրա է, որ 0 է վերադարձնում դատարկ ցուցակի դեպքում, իսկ ոչդատարկ ցուցակների համար ցուցակի առաջին տարրը գումարում է պոչի տարրերի գումարին։ Այս պրոցեդուրան պետք է կիրառել հետևյալ կերպ.

(sum-list '())         ; => 0
(sum-list '(1))        ; => 1
(sum-list '(1 2 3 4))  ; => 10

Բայց ավելի բնական կլիներ, եթե ես կարողանայի գրել այսպիսի արտահայտություններ.

(sum)          ; => 0
(sum 1)        ; => 1
(sum 1 2 3 4)  ; => 10

Այլ կերպ ասած՝ ունենալ պրոցեդուրա, որի արգումենտների քանակը ֆիքսված չէ. դրանք կարող են կա՛մ բացակայել, կա՛մ լինել անորոշ քանակի։

Երբ lambda կառուցվածքի առաջին արգումենտը տրված է որպես ատոմ (այլ ոչ թե որպես ցուցակ), ապա պրոցեդուրայի արգումենտը համարվում է անորոշ քանակի։ Օրինակ, հիշատակված sum պրոցեդուրան, օգտագործելով sum-list պրոցեդուրան, կարելի է սահմանել հետևյալ կերպ.

(define sum
    (lambda nums
        (sum-list nums)))

Երբ այս կերպ սահմանված պրոցեդուրան կիրառվում է արգումենտների նկատմամբ, այդ արգումենտներից կազմվում է ցուցակ և փոխանցվում է պրոցեդուրային։ Բնականաբար, պրոցեդուրայի մարմնում պետք է ֆորմալ արգումետի հետ աշխատել որպես ֆունկցիա։ Օրինակ, եթե sum պրոցեդուրան սահմանելու լինեի առանց sum-list պրոցեդուրայի օգտագործման, ապա պետք է գրեի.

(define sum
    (lambda nums
        (if (null? nums)
            0
            (+ (car nums) (apply sum (cdr nums))))))

apply հրամանն օգտագործված է այն պատճառով, որ sum պրոցեդուրայի ռեկուրսիվ կանչի ժամանակ (cdr nums) ցուցակը նրան փոխանցվելու է որպես նոր ցուցակի միակ տարր։

No comments:

Post a Comment