javascript: ფუნქციური დაპროგრამება დამწყებთათვის
ამ სტატიაში მინდა განვიხილო fp მიდგომა, ანუ როგორი იცვლება მიდგომა პროცედურულ ან oop სთან მიმართებაში, ამას განვიხილავთ მარტივი კოდის მაგალითით.
მაგალითად გვაქვს პროდუქტების სია კალათაში
var cart = [
{
name: 'შავი მაიკა',
price: 25,
}, {
name: 'მწვანე მაიკა',
price: 19
}
];
და გვინდა გავიგოთ ფასების ჯამი
ამას პროცედურულად გავაკეთებდით ასე
var total = 0;
for(var i in cart) {
total += cart[i].price;
}
ანუ ვქმნით ცვლადს total
შემდეგ გავრბივართ კალათაში და total
-ს ვმატებთ თითოეულის ღირებულებას
fp ვერსიაში ლოგიკა განსხვავებულია
var total = cart
.map(function(obj) {return obj.price})
.reduce(function(a, b) {return a + b});
ანუ map
-ით კალათაში არსებულ პროდუქტების სიას გარდავქმნით ფასების სიათ
და შემდეგ reduce
-ით ფასებს ერთმანეთს ვუმატებთ
უფრო fp-ური ვერსია (ramda-ს გამოყენებით)
var total = R.pipe(
R.map(R.prop('price')),
R.reduce(R.add, 0)
)(cart);
აქაც ზუსტად იგივე ხდება რაც პირველ fp მაგალითში მაგრამ ვიყენებთ function composition-ს (დეტალებს ცოტახანში ავხსნი)
ასევე შეგვიძლია სხვანაირადაც გავაკეთოთ იგივე
var total = R.pipe(R.plunk('price'), R.sum)(cart);
აქაც იგივეს ვაკეთებთ რაც წინა მაგალითში იყო R.plunk('price')
იგივეა რაც R.map(R.prop('price'))
და R.sum
იგივეა რაც R.reduce(R.add, 0)
ახლა კი როგორ მუშაობს function composition
დავიწყოთ R.map
იდან
ეს არის ფუნქცია რომელიც ღებულობს ორ პარამეტრს
პირველი პარამეტრი პირობითად fn არის ფუნქცია
და მეორე პარამეტრი პირობითად arr არის მასივი
map აბრუნებს ახალ მასივს რომელშიც ყველა ელემენტი არის ამ ელემენტის fn ში ჩაწოდების შემდეგ მიღებული შედეგი
ანუ როგორც მაგალითად 5x3
არის 3+3+3+3+3
ასევე R.map(fn, [1, 2])
არის [fn(1), fn(2)]
მაგრამ კოდის მაგალითში map-ს გადაეწოდება მხოლოდ ერთი პარამეტრი რის საშვალებასაც იძლევა currying-ი ანუ მაგალითად გვაქვს ფუნქცია add
function add(a, b) {
return a + b;
}
თუ ამ ფუნქციას გამოვიძახებთ და გადადვაწვდით მხოლოდ ერთ პარამეტრს
მივიღებთ ერორს (უფრო სწორეთ მივიღებთ NaN
ს რაც იქნება გადაწოდებული პარამეტრის undefined
ზე მიმატების შედეგი)
ახლა იგივე ფუნქცია currying ით
var add = R.curry(function(a, b) {
return a + b;
});
თუ ამ ფუნქციას გამოვიძახებთ და გადადვაწვდით მხოლოდ ერთ პარამეტრს მაგალითად ასე
var addOne = add(1);
ჩვენ მივიღებთ ფუნქციას რომელიც ელოდება მეორე პარამეტრს
ანუ addOne(3)
იგივეა რაც add(1, 3)
ან add(1)(3)
ახლა დავუბრუნდეთ map-ს რომელიც იყენებს currying-ს, ამის წყალობით ჩვენ შეგვიძლია რომ მას გადავაწოდოთ ფუნქცია და ის დაგვიბრუნებს მაპს რომელსაც უკვე აქვს ფუნქცია და ელოდება მასივს
აქედან გადავიდეთ R.prop
ზე რომელიც ძალიან მარტივ რამეს აკეთებს.
მას გადაეწოდება ორი პარამეტრი: სტრიქონი პირობითად propName
და ობიექტი პირობითად obj
.
ამ ფუნქციასაც აქვს currying რაც იმას ნიშნავს რომ თუ მას გამოვიძახებთ მარტო propName ით
ის დაგვბრუნებს ფუნქციას რომელიც ელოდება obj-ს
თუ ამას გამოვიყენებთ map თან ერთად და მაპს ჩავაწვდით prop-ის მიერ დაბრუნებულ ფუნქციას ასე
var toPrices = R.map(R.prop('price'));
მივიღებთ ფუნქციას რომელიც ელოდება მასივს რომელშიც ყველა ობიექტს ჩაანაცვლებს ამ ობიექტზე არსებული პარამეტრის price
-ის მნიშვნელობით ამგვარად მივიღებთ ფასების მასივს
ფასების მასივიდან გადავდივართ ჯამის დათვლაზე, რასაც ვაკეთტებთ reduce-ით.
reduce-ს გადაეწოდება სამი პარამეტრი
ფუნქცია პირობითად fn
ერთი ნებისმიერი ტიპის ცვლადი პირობითად a
და მასივი პირობითად arr
რედუსი გარბის მასივში და fn ს იძახებს a თი და მიმდინარე მასივის ელემენტით დაბრუნებული მნიშვნელობა ენიჭება a-ს და შემდეგ გამოიძახება მომდევნო ელემენტი სანამ ბოლოში არ გავა, ბოლოს ბრუნდება a
ანუ თუ reduce-ს გამოვიძახებთ ასე
var sum = R.reduce(R.add, 0);
მივიღებთ ფუნქციას რომელიც მასივის მნიშვნელობების ჯამს ითვლის.
reduce-ის a თავიდან უდრის 0 შემდეგ ყველა მასივის ელემენტი ემეტება a-ს და ბოლოს ბრუნდება a
R.add
იგივეა რაც add ფუნქცია რომელიც უკვე ავღწერეთ უბრალოდ ორ გადაწოდებულ პარამეტრს ერთმანეთს უმატებს და ჯამს აბრუნებს
დაგვრჩა R.pipe
pipe ღებულობს N რაოდენობის პარამეტრებს (ფუნქციებს)
და აბრუნებს ფუნქციას რომელიც ელოდება ერთ მნიშვნელობას რომელმაც უნდა გაირბინოს გადაწოდებულ ფუნქციაბში
ანუ
var total = R.pipe(
R.map(R.prop('price')),
R.reduce(R.add, 0)
)(cart);
იგივეა რაც
var prices = R.map(R.prop('price'))(cart);
var total = R.reduce(R.add, 0)(prices);
და
var total = R.pipe(R.plunk('price'), R.sum)(cart);
იგივეა რაც
var total = R.sum(R.plunk('price', cart));
იმედი მაქვს საინტერესო სტატია იყო და დაგაინტერესათ fp-ს შესწავლამ
ცნობარი: