Friday, July 6, 2018

JavaScript: mapcar-ի ևս մի իրականացման մասին

Չեմ հիշում, թե ինչի համար, բայց ինձ պետք էր JavaScript ծրագրում օգտագործել Common Lisp-ի mapcar ֆունկցիայի պես մի ֆունկցիա։ Մի քիչ դեսուդեն քչփորելուց հետո գտա սա. https://www.npmjs.com/package/mapcar։ Իրականացումից շատ բան չհասկացա ու դրա համար էլ որոշեցի գրել ավելի պարզ տարբերակը։
Ահա այն՝ մանրամասն մեկնաբանություններով.
//
// Ֆայլի անունը. mapcar.js
//

//
// Ֆունկցիայի անունը որոշեցի թողնել նույնը, ինչ որ
// Common Lisp լեզվում է՝ mapcar։
//
// mapcar ֆունկցիան սպասում է մեկ և ավելի արգումենտներ։
// Դրանցից առաջինը կիրառվող ֆունկցիան է, մյուսները՝ վեկտորներ են։
//
var mapcar = function( func, ...args ) {
    // համոզվել, որ առաջին արգումենտը ֆունկցիա է
    if( 'function' !== typeof func ) {
        throw 'mapcar-ի առաջին արգումենտը ֆունկցիա չէ։'
    }

    // համոզվել, որ երկրորդ և հաջորդ արգումենտներում վեկտորներ են.
    if( !args.every(Array.isArray) ) {
        throw 'Ոչ բոլոր արգումենտներն են վեկտոր տիպի։'
    }

    // համոզվել, որ ֆունկցիայի պարամետրերի քանակն ու mapcar-ին
    // տրված արգումենտների քանակները նույնն են
    if( func.length != args.length ) {
        throw 'Ֆունկցիայի պարամետրերի քանակն ու վեկտորների քանակը տարբեր են։'
    }

    // mapcar ֆունկցիայի կիրառման արդյունքը վեկտոր է
    let result = []

    // եթե վեկտորների երկարությունները տարբեր են, ապա mapcar—ի
    // արդյունքը ստացվելու է դրանցից ամենակարճի չափով
    const lengths = args.map((e) => e.length)
    const reslen = Math.min.apply(null, lengths)

    // ցիկլը կատարելով վեկտորներից ամենակարճի տարրերի քանակով...
    for( let i = 0; i < reslen; ++i )  {
        // վերցնել բոլոր վեկտորների i-րդ տարրերը, ...
        const atu = args.map((ev) => ev[i])
        // ֆունկցիան կիրառել դրանց նկատմամբ, ...
        const ri = func.apply(null, atu)
        // արդյունքն ավելացնել result վեկտորում
        result.push(ri)
    }

    // վերադարձնել կառուցված արդյունքը
    return result
}

// տրամադրել այս ֆունկցիան արտաքին աշխարհին
module.exports.mapcar = mapcar

  1. every մեթոդը true է վերադարձնում միայն այն դեպքում, երբ զանգվածի բոլոր տարրերը բավարարում են տրված պրեդիկատին։
  2. map մեթոդը վերադարձնում է զանգված բոլոր տարրերի նկատմամբ տրված ֆունկցիայի կիրառումների արդյունքում ստացված արժեքների վեկտորը։
  3. apply մեթոդը հնարավորություն է տալիս ֆունկցիան կանչել արգումենտների վեկտորով։ Օրինակ, եթե սահմանված է var f = function(x, y, z) { ... } , ապա -ը կարելի է օգտագործել այսպես. f.apply(null, [1, 2, 3])։ Հարմար է այն դեպքում, երբ կանչի արգումենտները դինամիկ են ձևավորվում։


Հիշեցի. mapcar-ն ինձ պետք էր zip-ի նման մի ֆունկցիա իրականացնելու համար։
var zip = function(x, y) {
    return mapcar((a, b) => [a, b], x, y)
}

No comments:

Post a Comment