Функциональное программирование раньше было нишевой парадигмой программирования, которая в основном использовалась в академических кругах и научных вычислениях, а также в финансовом мире. Идея функционального программирования — функция как объект. Я новичок в функциональном программировании, и я не использовал функциональное программирование за пределами Linq с C # и в JavaScript с использованием lodash и array.map и т. д. Я хочу реализовать некоторые функции, которые удовлетворяют 3 фундаментальным принципам функционального программирования.

Функция выполняет только одну операцию

Функция не изменяет никакого состояния и, таким образом, предотвращает любые побочные эффекты.

Функция должна работать только с входными данными, не изменяя их.

Функция не должна быть пустой, если это возможно, и должна все время возвращать значение, которое можно использовать в качестве входных данных для последующей операции.

В своей повседневной работе я работаю с SharePoint, и в наши дни большая часть разработки SharePoint происходит на стороне клиента с использованием javascript и других фреймворков. Недавно я написал несколько операций чтения с использованием RestAPI, где я хочу реализовать философию функционального программирования, изложенную выше. Поскольку это операция чтения, пункт № 2 выше будет удовлетворен.

Ниже мой код, и операция проста. Все, что я делаю, это читаю список и возвращаю элементы списка на основе запроса. Я ценю ваш комментарий и предложение, если это можно сделать более совместимым с парадигмой функционального программирования.

Функция находится в AngularJs, но в конечном итоге я преобразую ее в Jquery, чтобы она стала независимой от фреймворка. Как видите, я уже в процессе его изменения.

module My.Common.Services {
import entities = My.Entities;
export interface IRequestDigest {
        requestDigest: string;
        requestDigestExpiration: moment.Moment;
    }
interface ISharePointRestConnection {
        getRequestDigest(string);
    }
export class SharePointRestConnection implements ISharePointRestConnection {
private siteBaseUrl: string;
        private requestDigest: IRequestDigest;
static $inject: string[] = ["$q", "$http", "$interval"];
constructor(
            private $q: ng.IQService,
            private $http: ng.IHttpService,
            private $interval: ng.IIntervalService) {
        }
private parseRequestDigest(data: any, headers: Object): void {
            this.requestDigest = {
                requestDigest: data.d.GetContextWebInformation.FormDigestValue,
                requestDigestExpiration: moment().add(data.d.GetContextWebInformation.FormDigestTimeoutSeconds, "seconds")
            };
        }
private parseRequestDigest4mJquery(data: any, headers: Object): void {
            this.requestDigest = {
                requestDigest: data.GetContextWebInformation.FormDigestValue,
                requestDigestExpiration: moment().add(data.GetContextWebInformation.FormDigestTimeoutSeconds, "seconds")
            };
        }
public getRequestDigest(siteUrl: string): ng.IPromise<IRequestDigest> {
            this.siteBaseUrl = siteUrl;
var url = siteUrl + "/_api/contextinfo";
            var deferred: ng.IDeferred<IRequestDigest> = this.$q.defer<IRequestDigest>();
if (!this.requestDigest) {
                this.$interval(() => {
                    this.getRequestDigest(this.siteBaseUrl);
                }, 900000); //900000 ms = 15 minutes, or half of the default expiration
            }
// if the expiration is in the past, or if it doesn't exist yet, then fetch a new one and resolve when complete
            if ((!this.requestDigest) || (this.requestDigest.requestDigestExpiration < moment())) {
                var request = {
                    url: url,
                    method: "POST",
                    headers: {
                        "Content-Type": "application/json; odata=verbose",
                        "Accept": "application/json; odata=verbose"
                    }
                }
this.$http(request).then((response: ng.IHttpPromiseCallbackArg<any>) => {
                    this.parseRequestDigest(response.data, response.headers);
                    deferred.resolve(this.requestDigest);
                })
                    .catch((response: ng.IHttpPromiseCallbackArg<any>) => {
                        console.log("Failed to get request digest");
                        deferred.reject(response);
                    });
            }
            else { 
                // if the expiration is in the future
                deferred.resolve(this.requestDigest);
            }
return deferred.promise;
        };
public GetStandardSharePointPostHeaders(digest: IRequestDigest): any {
            return {
                "Content-Type": "application/json; odata=verbose",
                "Accept": "application/json; odata=verbose",
                "X-RequestDigest": digest.requestDigest
            };
        }
public GetStandardSharePointMergeHeaders(digest: IRequestDigest): any {
          return {
            "Content-Type": "application/json; odata=verbose",
            "Accept": "application/json; odata=verbose",
            "X-RequestDigest": digest.requestDigest,
            "X-HTTP-Method": "MERGE",
            "IF-MATCH": "*"
          };
        }
public GetStandardSharePointDeleteHeaders(digest: IRequestDigest): any {
          return {
            "Content-Type": "application/json; odata=verbose",
            "Accept": "application/json; odata=verbose",
            "X-RequestDigest": digest.requestDigest,
            "X-HTTP-Method": "DELETE",
            "IF-MATCH": "*"
          };
        }
public getListItems(url: string, listname: string, query: string): ng.IPromise<any> {
var deferred: ng.IDeferred<any> = this.$q.defer<any>();
let requestUrl = url + "/_api/web/lists/getbytitle('" + listname + "')/items" + query;
this.getRequestDigest(url).then((digest: IRequestDigest) => {
                let request: ng.IRequestConfig = {
                    url: requestUrl,
                    method: "GET",
                    headers: {
                        "X-RequestDigest": digest.requestDigest
                    },
                };
                this.$http(request).then((results: any) => {
                    deferred.resolve(results);
                }, (error: any) => {
                    console.log("SharePoint Rest Service", "error fetching list items for the list " + listname + " with the query " + query, error);
                    deferred.reject(error);
                });
            }, (error: any) => {
                console.log("SharePoint Rest Service", "error retrieving SP context", error);
                deferred.reject(error);
            });
return deferred.promise;
}
public getCurrentUser(url: string): ng.IPromise<entities.ISPUser> {
var deferred: ng.IDeferred<entities.ISPUser> = this.$q.defer<entities.ISPUser>();
let requestUrl = url + "/_api/web/currentUser";
            this.getRequestDigest(url).then((digest: IRequestDigest) => {
                let request: ng.IRequestConfig = {
                    url: requestUrl,
                    method: "GET",
                    headers: {
                        "X-RequestDigest": digest.requestDigest,
                        "Accept": "application/json; odata=verbose"
                    },
                };
                this.$http(request).then((results: any) => {
                    let toReturn: My.Entities.SPUser = My.Entities.SPUser.parse(results.data.d);
                    deferred.resolve(My.Entities.SPUser.parse(results.data.d));
                }, (error: any) => {
                    console.log("SharePoint Rest Service", "error fetching current user");
                    deferred.reject(error);
                });
            }, (error: any) => {
                console.log("SharePoint Rest Service", "error retrieving SP context", error);
                deferred.reject(error);
            });
return deferred.promise;
}
public getListItemsWithCAML(url: string, listname: string, camlQuery: string): ng.IPromise<any> {
var deferred: ng.IDeferred<any> = this.$q.defer<any>();
let requestUrl = url + "/_api/web/lists/getbytitle('" + listname + "')/GetItems(query=@v1)?@v1=" + camlQuery;
this.getRequestDigest(url).then((digest: IRequestDigest) => {
                let request: ng.IRequestConfig = {
                    url: requestUrl,
                    method: "POST",
                    headers: {
                        "X-RequestDigest": digest.requestDigest
                    },
                };
                this.$http(request).then((results: any) => {
                    deferred.resolve(results);
                }, (error: any) => {
                    console.log("SharePoint Rest Service", "error fetching list items for the list " + listname + " with the query " + camlQuery, error);
                    deferred.reject(error);
                });
            }, (error: any) => {
                console.log("SharePoint Rest Service", "error retrieving SP context", error);
                deferred.reject(error);
            });
return deferred.promise;
}
public getCurrentUser4mJquery(url: string): any {
let deferred = $.Deferred();
            let requestUrl = url + "/_api/web/currentUser";
            let request: any = {
                url: requestUrl,
                method: "GET",
                headers: {
                    "Accept": "application/json; odata=verbose"
                },
            };
            $.get(request).then((results) => {
// let toReturn: My.Entities.SPUser = My.SPUser.parse(results.d);
                deferred.resolve(My.Entities.SPUser.parse(results.d))
}, (error: any) => {
                console.log("SharePoint Rest Service", "error fetching current user");
                deferred.reject(error);
            });
            return deferred.promise();
}
public getRequestDigest4mJquery(siteUrl: string): JQueryPromise<IRequestDigest> {
            this.siteBaseUrl = siteUrl;
var url = siteUrl + "/_api/contextinfo";
            let deferred = $.Deferred < IRequestDigest>();
if (!this.requestDigest) {
                setInterval(() => {
                    this.getRequestDigest4mJquery(this.siteBaseUrl);
                }, 900000); //900000 ms = minutes, or half of the default expiration
            }
// if the expiration is in the past, or if it doesn't exist yet, then fetch a new one and resolve when complete
            if ((!this.requestDigest) || (this.requestDigest.requestDigestExpiration < moment())) {
                var request = {
                    url: url,
                    method: "POST",
                    headers: {
                        "Content-Type": "application/json; odata=verbose",
                        "Accept": "application/json; odata=verbose"
                    }
                }
$.get(request).then((response: any) => {
                    console.log(response);
                    this.parseRequestDigest4mJquery(response.d, response.headers);
                    deferred.resolve(this.requestDigest);
                })
                    
            }
            else {
                // if the expiration is in the future
                deferred.resolve(this.requestDigest);
            }
return deferred.promise;
        };
public getListItemsWithCAML4mJquery(url: string, listname: string, camlQuery: string):any {
var deferred = $.Deferred();
let requestUrl = url + "/_api/web/lists/getbytitle('" + listname + "')/GetItems(query=@v1)?@v1=" + camlQuery;
$.when(this.getRequestDigest4mJquery(url)).then((digest: IRequestDigest) => {
                let request: any = {
                    url: requestUrl,
                    method: "POST",
                    headers: {
                        "X-RequestDigest": digest.requestDigest
                    },
                };
                $.post(request).then((results: any) => {
                    deferred.resolve(results);
                }, (error: any) => {
                    console.log("SharePoint Rest Service", "error fetching list items for the list " + listname + " with the query " + camlQuery, error);
                    deferred.reject(error);
                });
            }, (error: any) => {
                console.log("SharePoint Rest Service", "error retrieving SP context", error);
                deferred.reject(error);
            });
return deferred.promise;
}
}
angular.module('app').
        service("My.Common.Services.sharepointrestconnection", SharePointRestConnection);
}

Вот как я его потребляю

this.spRestUtilityService.getCurrentUser(this.BaseWebUrl()).then((results: My.Entities.ISPUser) => {
                this.spRestUtilityService.getListItemsWithCAML(this.BaseWebUrl(), "ListA", utils.createQuery4UserProfileItem(results)).then((results: any) => {
                    let userProfileItemValue = utils.getSPUserProfileItem(results);
                    this.spRestUtilityService.getListItemsWithCAML(this.BaseWebUrl(), "ListB", this._createQuery4ListB(userProfileItemValue)).then((results: any) => {
                    this.spRestUtilityService.getListItemsWithCAML(this.BaseWebUrl(), "ListB", this._createQuery4ListB4Null(userProfileItemValue)).then((nullResults:any) =>{
                            deferred.resolve(this._processTableauReportItems(_.uniqBy(_.union(results,nullResults),'Id')));
                        });
                     });
                });
            });

Счастливой пятницы. Ищу ваш комментарий.