Let's say we want to write a most simple implementation 'avg' function:

const avg = list => {
let sum = 0;
for(let i = 0; i < list.length; i++) {
sum += list[i]
}
return sum / list.length
}

Basiclly, the 'avg' function doing two things:

  • Calculate sum
  • Divide sum / length

It works fine for tiny / small application, but for the large application, we need to think about reuseablitiy. We want to breakdown one function and think about any reuseable partten, which later can be reused.

In the following examples, We want to bring in two libarays which are commonly used in FP. One is Ramda, another one is Crocks.

Currying:

First, we want to write 'sum' and 'devide' functions by ourselves:

const { curry, reduce, compose } = require("crocks");
const R = require("ramda"); const sum = reduce(R.add, 0);
// divideByLen :: [Number] -> Number -> Number
const divideByLen = curry(
compose(
R.flip(R.divide),
R.length
)
);

'sum' is simple, using 'reduce' from Crocks, you can also write JS reduce, doesn't matter.

What we need to explain is 'divideByLen' function.

  • Why 'curry'?

Basic we want to call divideByLen in two ways:

divideByLen([1,2,3], sum([1,2,3]))
divideByLen([1,2,3])(sum([1,2,3]))

[Notice] You need to bring in 'curry' from Crocks, it is more flexable.

  • Why 'flip'?

Because R.divide(sum, length), we need to feed the divide function with sum as first argement, then length as second arguement. But when we write code, length will be feeded frist, sum will be partially applied, it will come second, therefore we need to call 'flip'.

Bring all together:

const avg = list =>
compose(
divideByLen(list),
sum
)(list);

We notice that, we have to pass 'list' to both Sum(list) and divideByLen(list). The code looks not so good. Whenever you are facing the situation, you need to pass the same arguement to two functions in parallel. You can consider to using 'Partial Application'.

Partial Application:

// Ramda

const avg = R.converge(R.divide, [R.sum, R.length]);

We are using 'Ramda's converge' function, bascilly you have pass in a data, the data will be passed to R.sum(data) & R.length(data), the return results of those two functions, will be passed to R.divide(resOfSum, resOfLength).

//Crocks:

const { curry, fanout, merge, compose } = require("crocks");

const avg = compose(
merge(R.divide),
fanout(R.sum, R.length)
);

We are using the Pair ADT, the data will be passed to R.sum(data) & R.length(data) thought 'fanout' function, it returns Pair(resOfSum, resOfLength).

Then we use 'merge', it works with Pair ADT, we merge two results by R.divide(resOfSum, resOfLength).

[Functional Programming] From simple implementation to Currying to Partial Application的更多相关文章

  1. Currying vs Partial Application

    柯里化相当于函数重构: 偏函数相当于函数适配. So, what is the difference between currying and partial application? As we s ...

  2. [Functional Programming] Write simple Semigroups type

    An introduction to concatting items via the formal Semi-group interface. Semi-groups are simply a ty ...

  3. [Functional Programming] Compose Simple State ADT Transitions into One Complex Transaction

    State is a lazy datatype and as such we can combine many simple transitions into one very complex on ...

  4. Functional Programming without Lambda - Part 1 Functional Composition

    Functions in Java Prior to the introduction of Lambda Expressions feature in version 8, Java had lon ...

  5. Functional Programming without Lambda - Part 2 Lifting, Functor, Monad

    Lifting Now, let's review map from another perspective. map :: (T -> R) -> [T] -> [R] accep ...

  6. Beginning Scala study note(4) Functional Programming in Scala

    1. Functional programming treats computation as the evaluation of mathematical and avoids state and ...

  7. a primary example for Functional programming in javascript

    background In pursuit of a real-world application, let’s say we need an e-commerce web applicationfo ...

  8. Functional programming

    In computer science, functional programming is a programming paradigm, a style of building the struc ...

  9. BETTER SUPPORT FOR FUNCTIONAL PROGRAMMING IN ANGULAR 2

    In this blog post I will talk about the changes coming in Angular 2 that will improve its support fo ...

随机推荐

  1. Deep Learning系统实训之二:梯度下降原理

    基本概念理解: 一个epoch:当前所有数据都跑(迭代)了一遍: 那么两个epoch,就是把所有数据跑了两遍,三个epoch就是把所有数据跑了三遍,以此类推. batch_size:每次迭代多少个数据 ...

  2. Lavarel - 模块间复用代码

    代码复用在项目中早晚会遇到,这不在用 Laravel 给博客增加 Feed 订阅功能 就到了需要将生成网页 description 的函数提取出来,在文章显示与 Feed 生成的两个 Controll ...

  3. SPLAY,LCT学习笔记(三)

    前两篇讲述了SPLAY模板操作,这一篇稍微介绍一下SPLAY的实际应用 (其实只有一道题,因为本蒟蒻就写了这一个) 例:bzoj 1014火星人prefix 由于本蒟蒻不会后缀数组,所以题目中给的提示 ...

  4. python 全栈开发,Day113(方法和函数的区别,yield,反射)

    一.方法和函数的区别 面向对象 初级 class StarkConfig(object): def __init__(self,model_class): self.model_class = mod ...

  5. SqlServer索引碎片

    1.产生碎片的操作 通过sys.dm_index_physical_stats来查看,索引上的页不在具有连续性时就会产生碎片,碎片是索引上页拆分的物理结果. (1).插入操作: INSERT操作在聚集 ...

  6. ATL CAxWindow类创建问题一则

    查看一个浏览器源码实现,发现其中使用了ie的控件,但例子中没有找到任何创建ie浏览器控件的代码,经过仔细跟踪,发现CAxWindow类是可以这么使用滴.. 创建的时候第三个参数直接传入url.调用到C ...

  7. 《Java并发编程的艺术》--Java中的锁

    No1: Lock接口 Lock lock = new ReentrantLock(); lock.lock(); try{ }finally{ lock.unlock(); } No2: 不要讲获取 ...

  8. 条件随机场之CRF++源码详解-训练

    上篇的CRF++源码阅读中, 我们看到CRF++如何处理样本以及如何构造特征.本篇文章将继续探讨CRF++的源码,并且本篇文章将是整个系列的重点,会介绍条件随机场中如何构造无向图.前向后向算法.如何计 ...

  9. Java中递归和循环的优劣

    介绍: 你用你手中的钥匙打开一扇门,结果去发现前方还有一扇门,紧接着你又用钥匙打开了这扇门,然后你又看到一扇门......但是当你开到一扇门时,发现前方是一堵墙无路可走了,你选择原路返回--这就是递归 ...

  10. jvm本地实战

    前言 ​ 由于上次线上full gc,让我这个没有机会实战接触jvm的人,尝到了一定的甜头,同时也觉得自己还有很多东西需要去实战并总结.这是一篇记录jvm配置参数,使用jvisualvm工具来让人对j ...