Haskell-like list comprehension

栏目: IT技术 · 发布时间: 5年前

内容简介:It is a common pattern in functional programming, to the point that some programming languages like Haskell, Clojure, Perl, Python and others do support it directly with syntactic constructs. It allow us to express theLet's take an example:It reflects the

List Comprehension in JS

Install

npm i list-comprehension-in-js

The What

It is a common pattern in functional programming, to the point that some programming languages like Haskell, Clojure, Perl, Python and others do support it directly with syntactic constructs. It allow us to express the set builder-notation into our code.

Let's take an example: S = { 2*x | x € N, x^2 > 100 } , where we are saying "take all the natural number which square is greater than 100 , double them and use these results to create a new set". The resulting set will be: { 22, 24, 26, ... } .

The Why

It reflects the idea of ​​having a set of candidates as solutions to a problem, on which transformations and filtering are applied to narrow the number of them, until right solutions are obtained.

The How

Let's take Haskell as example. The following is the way we can express the previous set comprehension:

[ 2*x | x <- [1..], x^2 > 100 ]

Pretty terse notation, huh? The output will be an infinite, lazy list containing (potentially) all the elements of our set.

Let's take another example. We want to generate all the right triangle that have an even perimeter. This is the Haskell way:

list = [
    {-
        The single element of the resulting list is a triple
        containing the values of the ipothenuse and the two cathets
    -}
    (ipo, cat1, cat2) |

    -- Three ranges for three variables
    ipo <- [1..],
    cat1 <- [1..ipo-1],
    cat2 <-[1..cat1],

    -- Two predicates to satisfy
    ipo^2 == cat1^2 + cat2^2,
    mod (ipo + cat1 + cat2) 2 == 0 ]

Ranges optimizations apart, it's worth noting that:

  • it is possible to have multiple ranges and variables into play
  • it is possible to use the current value taken by a previous defined variable as upper/ lower limit for a following range
  • it is possible to have more predicates to satisfy
  • the output element expression is custom

The How in JavaScript

This library is a custom solution to achieve all of this great possibilities in JS!

It is based on ES6 generators , to achieve the infinite, lazy approach:

const { Comprehension, range } = require("list-comprehension-in-js");

let allRightTrianglesWithEvenPerimeter = new Comprehension(
    // custom output
    (ipo, cat1, cat2) => ({ ipo, cat1, cat2 }),
    [
        // ranges
        () => range(1, Infinity),
        (ipo) => range(1, ipo - 1),
        (_, cat1) => range(1, cat1)
    ],
    [
        // predicates to satisfy
        (ipo, cat1, cat2) => (ipo ** 2 == cat1 ** 2 + cat2 ** 2),
        (ipo, cat1, cat2) => ((ipo + cat1 + cat2) % 2 == 0),
    ]
);

Where range is nothing more than a generator function that provides an iterable of integer numbers and the allRightTrianglesWithEvenPerimeter is itself an iterable too!

So the library perfectly fits in the JavaScript ecosystem.

There is also an utility to extract a finite part of the infinite list, putting the elements into an array:

const { take } = require("list-comprehension-in-js");

const finiteList = take(allRightTrianglesWithEvenPerimeter, 5, 10);

for (const triangle of finiteList) {
    console.log(`hyp: ${triangle.ipo}, c1: ${triangle.cat1}, c2: ${triangle.cat2}`);
}
/*
{hyp: 30, c1: 24, c2: 18}
{hyp: 34, c1: 30, c2: 16}
{hyp: 35, c1: 28, c2: 21}
{hyp: 37, c1: 35, c2: 12}
{hyp: 39, c1: 36, c2: 15}
*/

Utilities API

range

Create an iterable which will output a set of increasing numbers ( start must be <= than end ):

function* range(start, end, step = v => v) {
    // ...
}
  • start : the integer value from which start to generate the numbers
  • end : the last integer value to take
  • step : a mapper function to eventually transform each produced value

rangeReversed

Create an iterable which will output a set of decreasing numbers ( start must be >= than end ):

function* rangeReversed(start, end, step = v => v) {
    // ...
}
  • start : the integer value from which start to generate the numbers
  • end : the last integer value to take
  • step : a mapper function to eventually transform each produced value

take

Take at most nOfElements starting from the index start .

It returns an array containing the elements.

function take(listIterable = [], nOfElements = 0, start = 0) {
    // ...
}
  • listIterable : any iterable, like the one returned by the Comprehension constructor
  • nOfElements : number of elements to pick
  • start : starting index

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

网站项目管理

网站项目管理

[美] 阿什利·弗里德莱因 / 李保庆、杨磊、王增东 / 电子工业出版社 / 2002-11 / 32.00元

这本书全方位地介绍了如何建立和最终交付一个具有很高商业价值的成功网站,讲解从项目管理的角度入手,撇开烦琐的技术细节,更加关注Web项目实施中诸如成本、进度、工作范围等问题,涉及了一个商业网站在实施过程中可能遇到的所有管理细节。书内附国际一流网站开发专家的深邃见解;涵盖了网络项目管理的关键原则及案例研究;通过友情链接,还为读者提供了模板、论坛、术语表、相关链接以及有关因特网知识的测验题。一起来看看 《网站项目管理》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具