摘要:函數式編程中的的意思就是無參或無值,是一種編程范式,也作,就是無參編程的意思了。的聲明式代碼是函數式編程應該有的樣子。
函數式編程中的pointfree的意思就是“無參”或“無值”,pointfree style是一種編程范式,也作tacit programming,就是“無參編程”的意思了。什么是“無參編程”?
// 這就是有參的,因為有word var snakeCase = word => word.toLowerCase().replace(/s+/ig, "_"); // 這是pointfree var snakeCase = compose(replace(/s+/ig, "_"), toLowerCase);
從另一個角度看,有參的函數的目的是得到一個數據,而pointfree的函數的目的是得到另一個函數。
所以,如下的方程,雖然也有參,也可以認為是pointfree的。
const titlesForYear = year => pipe( filter(publishedInYear(year)), map(book => book.title) )
那這pointfree有什么用?
它可以讓我們把注意力集中在函數上,參數命名的麻煩肯定是省了,代碼也更簡潔優雅。
需要注意的是,一個pointfree的函數可能是由眾多非pointfree的函數組成的,也就是說底層的基礎函數大都是有參的,pointfree體現在用基礎函數組合而成的高級函數上。如果我們使用函數式編程的工具,如ramda,這些基礎函數大都已經被寫好了,這樣我們去寫pointfree的代碼就很容易了。
什么是聲明式編程?它區別于命令式編程
// 命令式 var words = []; for (i = 0; i < otherWords.length; i++) { words.push(otherWords[i].word); } // 聲明式 var words = otherWords.map(function(ele){ return ele.word; });
容易看出,命令式的代碼,我們不但要去遍歷,還要關注如何遍歷。而聲明式的就容易很多,可以節省我們的注意力,代碼也更加簡潔。
其他的命令式的寫法有:使用ifelse進行的條件判斷,使用算數運算符進行的算數運算,使用比較運算符進行的比較運算和使用邏輯運算符進行的邏輯運算。
至于那些說“雖然如此,但使用命令式循環速度要快很多”的人,我建議你們先去學學 JIT 優化代碼的相關知識。這里有一個非常棒的視頻,可能會對你有幫助。
需要注意的是,要實現這種聲明式的編程,首先我們要有這個map方法,這一點與pointfree相同,都是需要我們先對常用的操作做一次封裝,而這些常用的操作本身還是命令式的。
pointfree的聲明式代碼是函數式編程應該有的樣子。
最后用一個來自Scott Sauyet的文章《Favoring Curry》中的例子,使用的函數式工具是ramda。下面的代碼不需要一句一句的看,大概體會一下就可以了。
一組JSON數據
var data = { result: "SUCCESS", interfaceVersion: "1.0.3", requested: "10/17/2013 15:31:20", lastUpdated: "10/16/2013 10:52:39", tasks: [ {id: 104, complete: false, priority: "high", dueDate: "2013-11-29", username: "Scott", title: "Do something", created: "9/22/2013"}, {id: 105, complete: false, priority: "medium", dueDate: "2013-11-22", username: "Lena", title: "Do something else", created: "9/22/2013"}, {id: 107, complete: true, priority: "high", dueDate: "2013-11-22", username: "Mike", title: "Fix the foo", created: "9/22/2013"}, {id: 108, complete: false, priority: "low", dueDate: "2013-11-15", username: "Punam", title: "Adjust the bar", created: "9/25/2013"}, {id: 110, complete: false, priority: "medium", dueDate: "2013-11-15", username: "Scott", title: "Rename everything", created: "10/2/2013"}, {id: 112, complete: true, priority: "high", dueDate: "2013-11-27", username: "Lena", title: "Alter all quuxes", created: "10/5/2013"} // , ... ] };
需求是找到Scott所有未完成的任務,并按照到期日期升序排列。
正確的結果是
[ {id: 110, title: "Rename everything", dueDate: "2013-11-15", priority: "medium"}, {id: 104, title: "Do something", dueDate: "2013-11-29", priority: "high"} ]
命令式的代碼如下
getIncompleteTaskSummaries = function(membername) { return fetchData() .then(function(data) { return data.tasks; }) .then(function(tasks) { var results = []; for (var i = 0, len = tasks.length; i < len; i++) { if (tasks[i].username == membername) { results.push(tasks[i]); } } return results; }) .then(function(tasks) { var results = []; for (var i = 0, len = tasks.length; i < len; i++) { if (!tasks[i].complete) { results.push(tasks[i]); } } return results; }) .then(function(tasks) { var results = [], task; for (var i = 0, len = tasks.length; i < len; i++) { task = tasks[i]; results.push({ id: task.id, dueDate: task.dueDate, title: task.title, priority: task.priority }) } return results; }) .then(function(tasks) { tasks.sort(function(first, second) { var a = first.dueDate, b = second.dueDate; return a < b ? -1 : a > b ? 1 : 0; }); return tasks; }); };
pointfree的代碼
var getIncompleteTaskSummaries = function(membername) { return fetchData() .then(R.prop("tasks")) .then(R.filter(R.propEq("username", membername))) .then(R.reject(R.propEq("complete", true))) .then(R.map(R.pick(["id", "dueDate", "title", "priority"]))) .then(R.sortBy(R.prop("dueDate"))); };
pointfree的聲明式的代碼
// 提取 tasks 屬性 var SelectTasks = R.prop("tasks"); // 過濾出指定的用戶 var filterMember = member => R.filter( R.propEq("username", member) ); // 排除已經完成的任務 var excludeCompletedTasks = R.reject(R.propEq("complete", true)); // 選取指定屬性 var selectFields = R.map( R.pick(["id", "dueDate", "title", "priority"]) ); // 按照到期日期排序 var sortByDueDate = R.sortBy(R.prop("dueDate")); // 合成函數 var getIncompleteTaskSummaries = function(membername) { return fetchData().then( R.pipe( SelectTasks, filterMember(membername), excludeCompletedTasks, selectFields, sortByDueDate, ) ); };
參考文章
Pointfree編程風格指南
Favoring Curry
JS函數式編程指南
Tacit programming
Thinking in Ramda: Pointfree Style
Thinking in Ramda: Declarative Programming
我在github https://github.com/zhuanyongx...
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/94592.html
摘要:組合的概念是非常直觀的,并不是函數式編程獨有的,在我們生活中或者前端開發中處處可見。其實我們函數式編程里面的組合也是類似,函數組合就是一種將已被分解的簡單任務組織成復雜的整體過程。在函數式編程的世界中,有這樣一種很流行的編程風格。 JavaScript函數式編程,真香之認識函數式編程(一) 該系列文章不是針對前端新手,需要有一定的編程經驗,而且了解 JavaScript 里面作用域,閉...
摘要:注意是單一參數柯里化是由以邏輯學家命名的,當然編程語言也是源自他的名字,雖然柯里化是由和發明的。辨別類型和它們的含義是一項重要的技能,這項技能可以讓你在函數式編程的路上走得更遠。 slide 地址 三、可以,這很函數式~ showImg(https://segmentfault.com/img/remote/1460000015978685?w=187&h=160); 3.1.函數是一...
摘要:為此決定自研一個富文本編輯器。例如當要轉化的對象有環存在時子節點屬性賦值了父節點的引用,為了關于函數式編程的思考作者李英杰,美團金融前端團隊成員。只有正確使用作用域,才能使用優秀的設計模式,幫助你規避副作用。 JavaScript 專題之惰性函數 JavaScript 專題系列第十五篇,講解惰性函數 需求 我們現在需要寫一個 foo 函數,這個函數返回首次調用時的 Date 對象,注意...
摘要:期函數式編程中代碼組合如何理解定義顧名思義,在函數式編程中,就是將幾個有特點的函數拼湊在一起,讓它們結合,產生一個嶄新的函數代碼理解一個將小寫轉大寫的函數一個在字符后加的函數將兩個函數組合起來這里假設我們實現了每日一題每日一題顯示結果里上面 20190315期 函數式編程中代碼組合(compose)如何理解? 定義: 顧名思義,在函數式編程中,Compose就是將幾個有特點的函數拼湊在...
閱讀 4624·2021-09-26 09:55
閱讀 1367·2019-12-27 12:16
閱讀 887·2019-08-30 15:56
閱讀 1905·2019-08-30 14:05
閱讀 992·2019-08-30 13:05
閱讀 1269·2019-08-30 10:59
閱讀 1442·2019-08-26 16:19
閱讀 1887·2019-08-26 13:47