npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

func-fave

v1.31.0

Published

This is a library that allows use of functional programming in JavaScript by utilizing specialized functions.

Downloads

64

Readme

func-fave

Func-fave is an npm package that allows easy use of functional programming in Javascript by utilizing specialized functions. These specialized functions are called Functionals. The purpose of these functionals are to replace the traditional control-flow statements found in Javascript.

Terminology:

conditional: A conditional is an expression, functional, or value that holds or returns the value of true or false.

example:

  const { FIF } = require( 'func-fave' );

  conditionalExamples = {
    'example_one': (1 >= 2), // false
    'example_two': FIF( this.example_one ), // false
    'example_three': false
  }

functional: A functional is a function that returns a value and can replace or expand on a traditional control-flow statement in usage.

example:

  /* 
    The following are functionals 
    that func-fave provides. 
  */

  /* Control-flow */
  const { FIF } = require( 'func-fave' ); // if
  const { FDEC } = require( 'func-fave' ); // declarative if
  const { FIM } = require( 'func-fave' ); // imperative func
  const { FFOR } = require( 'func-fave' ); // functional for-loop

  /* Operators */
  const { FEQ } = require( 'func-fave' ); // equal to
  const { FGR } = require( 'func-fave' ); // greator than
  const { FLR } = require( 'func-fave' ); // less than

anonymous | anon: An anonymous is a function that takes no parameters and acts as a callback function. The return value of the anonymous is returned by the higher order function in which it is used.

truthy: describes any value, expression, or return value that is expressed as true.

falsey: describes any value, expression, or return value that is expressed as false.

callable: A callable is any function or functional that can be called, regardless of parameter usage.

functor: In functional programming, a functor is a type that implements a map function. This map function applies a function to every element within a context (such as an array or another type of container) and returns a new context with the transformed elements. In JavaScript, arrays are functors because they have a .map() method that fulfills this purpose.

recursion: Recursion is a technique that is unique to functions. A recursive function is one that calls itself in order to break down a problem into smaller, more manageable parts.

state: a collection of information held in a dynamic data-structure.

Installation

  npm install func-fave

Basic Control-Flow

FIF()

description:

FIF() is a functional that replaces the traditional if statement. It allows you to pass three parameters. First it accepts a conditional expression as a parameter. This expression must equate to true or false. The second and third parameters it accepts may be either a value or callback function.


  const { isCallable } = require( 'func-fave' );

  function FIF(
  condition,
  onTrue = () => 1,
  onFalse = () => 0
) {

  if ( isCallable(condition) ) {
    if ( condition() ) {
      if (isCallable(onTrue)) { return onTrue() }
      return onTrue
    }

    if (isCallable(onFalse)) { return onFalse() }
    return onFalse
  }

  if ( condition ) {
    if (isCallable(onTrue)) { return onTrue() }
    return onTrue
  }

  if (isCallable(onFalse)) { return onFalse() }
  return onFalse
  
}

usage:


  const { FIF } = require( 'func-fave' );
  
  const user = 'houdini';
  const password = 'abracadabra';

  const successfulLogin = `Login success!\n Welcome ${user} ...`
  const failedLogin = `Login failed!\n password '${password}' is incorrect ...`
  
  return FIF(
    ( user === 'houdini' || password === 'abracadabra' )
    ,
    () => {
      console.log(successfulLogin)
    },
    () => {
      console.log(failedLogin)
    }
  )

FDEC()

description:

FDEC() is a functional that utilizes the power of the FIF() functional to use the runtime declaratively. It makes decisions based on truthy and falsey conditionals. In this case, conditionals and FIF() conditionals are on and the same.


  const { FIF, isCallable } = require( 'func-fave' );

  function FDEC(
    conditional,
    onSuccess,
    onFailure,
    params = []
  ) {

    return FIF(
      ( isCallable(conditional) )
      ,
      () => {

        return FIF(
          (
            FIF(
              ( params.len > 0 )
              ,
              () => conditional(...params),
              () => conditional()
            )
          )
          ,
          () => onSuccess(),
          () => onFailure()      
        )

      }
      ,
      () => {

        return FIF(
          ( conditional )
          ,
          () => onSuccess(),
          () => onFailure()
        )

      },
    )

  }

usage:


  const { FDEC, FIF } = require( 'func-fave' );

  const userDataBase = {
    'houdini': 'abracadabra',
    'moriarty': 'ilovesherlock',
    'dr.who': 'done_it',
  }

  const user = Object.keys(userDataBase)[1];
  const password = userDataBase[user];

  const userNotFound = `Login failed!\n user '${user}' not found ...`
  const invalidPassword = `Login failed!\n password '${password}' is incorrect ...`
  const successfulLogin = `Login success!\n Welcome ${user} ...`

  return FDEC(
    (
      FIF(
        ( 
          Object.keys(userDataBase)
          .indexOf(user) > -1 
        )
      ) // returns truthy or falsey based on conditional expression
    )
    ,
    () => {
      return FIF(
        ( password === userDataBase[user] )
        ,
        () => {
          console.log(successfulLogin)
          return 1
        },
        () => {
          console.log(invalidPassword)
          return 0
        }
      )
    },
    () => {
      console.log(userNotFound)
      return 0
    }
  )

FIM()

description:

The FIM() functional's utility is based in its ability to return the value its callback function. It is a tool used to define a callback, operate on parameters passed to said callback, and return the value of the callback itself in the same runtime. This is extremely useful in Functional Programming. This is also a component that allows the FFOR() function to run smoothly.

  const { FIF, isCallable } = require( 'func-fave' );
  
  function FIM(
    func,
    params = []
  ) {
    return FIF(
      ( isCallable(func) )
      , 
      () => func(...params),
      () => 0
    )
  }

usage:

  const { FIM, FIF, FEQ, createNode } = require( 'func-fave' );
  
  const key = 'find-the-secret-node';
  const passkey_attempt = 'find-the-secret';
  
  const Node1 = createNode();
  const Node2 = createNode();
  
  Node1.set({
    edge1: 'do',
    edge2: 're',
    edge3: 'me'
  })

  Node2.set({
    edge1: 'fa',
    edge2: 'so',
    edge3: 'la',
    secretNode: createNode(),
    setNode: (_secretNode) => {
      _secretNode.set({
        edge1: 'ti',
        edge2: 'do',
        secretMsg: 'congrats on finding me!!'
      })
    }
  })
  
  return FIF(
    (
      FEQ(
        (passkey_attempt + '-node'), 
        key
      )
    )
    ,
    FIM(
      (_NODE) => {
        const { 
          edge1, edge2, edge3,
          secretNode, setNode
        } = _NODE;
        
        setNode(secretNode);
        console.log(secretNode.secretMsg);
        
        return {
          body: _NODE,
          endpoints: [edge1, edge2, edge3, secretNode]
        };
      },
      [Node2]
    )
    ,
    FIM(
      (_NODE) => {
        const { edge1, edge2, edge3 } = _NODE;
        console.log(edge1, edge2, edge3);
        return {
          body: _NODE,
          endpoints: [edge1, edge2, edge3]
        };
      },
      [Node1]
    )
  )

Operators

FEQ()

description:

The FEQ() functional tests an equality expression. If the expression is truthy, it returns the first operand that is passed. If the expression is falsey, it returns a falsey value.

  const { FIF } = require( '../fif.cjs' );
  
  function FEQ(
    operandOne,
    operandTwo,
  ) {
  
    return FIF(
      ( operandOne === operandTwo )
      ,
      () => operandOne,
      () => 0
    )
  
  }

FGR()

description:

The FGR() functional tests an inequality expression. If the expression is truthy, it returns the largest operand that is passed. If the expression is truthy, and the treatConditionally boolean is toggled, it returns a truthy value. If the expression is falsey, it returns the largest operand that is passed. If the expression is falsey, and the treatConditionally boolean is toggled, it returns a falsey value. The passed operands can be callable.

  const { FIF, FIM, FEQ, isCallable } = require( 'func-fave' );
  
  function FGR(
    assertGreater,
    assertLesser,
    treatConditionally = 1
  ) {

    FIM(
      () => {

        FIF( ( isCallable(assertGreater) ),
          () => {
            assertGreater = assertGreater()
          }
        )

        FIF( ( isCallable(assertLesser) ),
          () => {
            assertLesser = assertLesser()
          }
        )

      }
    )
    
    const condition = ( assertGreater > assertLesser );
  
    assertGreater = FIF(
      (typeof assertGreater !== 'number')
      ,
      () => {
        
        return FIF(
          (
            FEQ(typeof assertGreater, 'null') || FEQ(typeof assertGreater, 'undefined')
          )
          ,
          () => 0,
          () => assertGreater.length
        );
        
      },
      () => assertGreater
    );
    
    assertLesser = FIF(
      (typeof assertLesser !== 'number')
      ,
      () => {
        
        return FIF(
          (
            FEQ(typeof assertLesser, 'null') || FEQ(typeof assertLesser, 'undefined')
          )
          ,
          () => 0,
          () => assertLesser.length
        );
        
      },
      () => assertLesser
    );
    
    return FIF(
      ( treatConditionally )
      ,
      () => {
        
        return FIF(
          ( condition )
          ,
          () => 1,
          () => 0
        )
        
      }
      ,
      () => {
        
        return FIF(
          ( condition ),
          () => assertGreater,
          () => assertLesser
        )
        
      }
    );
    
  }

FLR()

description:

The FLR() functional tests an inequality expression. If the expression is truthy, it returns the smallest operand that is passed. If the expression is truthy, and the treatConditionally boolean is toggled, it returns a truthy value. If the expression is falsey, it returns the smallest operand that is passed. If the expression is falsey, and the treatConditionally boolean is toggled, it returns a falsey value. The passed operands can be callable.

  const { FIF, FEQ } = require( 'func-fave' );
  
  function FLR(
    assertLesser,
    assertGreater,
    treatConditionally = 1
  ) {
  
    FIM(
      () => {
  
        FIF( ( isCallable(assertLesser) ),
          () => {
            assertLesser = assertLesser()
          }
        )
  
        FIF( ( isCallable(assertGreater) ),
          () => {
            assertGreater = assertGreater()
          }
        )
  
      }
    )
  
    const condition = ( assertLesser < assertGreater );
  
    assertLesser = FIF(
      (typeof assertLesser !== 'number')
      ,
      () => {
  
        return FIF(
          (FEQ(typeof assertLesser, 'null') || FEQ(typeof assertLesser, 'undefined'))
          ,
          () => 0,
          () => assertLesser.length
        );
  
      },
      () => assertLesser
    );
  
    assertGreater = FIF(
      (typeof assertGreater !== 'number')
      ,
      () => {
  
        return FIF(
          (FEQ(typeof assertGreater, 'null') || FEQ(typeof assertGreater, 'undefined'))
          ,
          () => 0,
          () => assertGreater.length
        );
  
      },
      () => assertGreater
    );
  
    return FIF(
      ( treatConditionally )
      ,
      () => {
  
        return FIF(
          ( condition )
          ,
          () => 1,
          () => 0
        )
  
      },
      () => {
  
        return FIF(
          ( condition )
          ,
          () => assertLesser,
          () => assertGreater
        )
  
      }
    );
  
  }

Iterators

FFOR()

description:

The FFOR() conditional is a functor similarly to the traditional .map() method for Javascript arrays. However, the FFOR() conditional has multiple key differences:

  • It supports the functionality of the continue, break keywords that are found in traditional syntax.

    • end.set(true): breaks recursive iteration, and returns result.
    • cont.set(true): continues to next iteration cycle, ignoring current cycle result.
  • It supports backtracking, which is not found in any current iterative tools.

    • back.set(true): implements backtracking per one iteration cycle.
  • It iterates over iterable values by using recursion.

Upon calling the FFOR() functional, a Node is initiated and set with values. The following values may be used in your custom function that is passed into FFOR():

  • index: References the index of the element of the current iteration cycle.
  • elem: References the element of the iteration cycle.
  • jump: References the interval of iteration per cycle.
  • self: References the original iterable value passed into FFOR().
  • history: The return value that is provided at the end of recursion.
  • back: A toggle that enables backtracking.
  • end: A toggle that enables breaking.
  • cont: A toggle that enables continuation.

iterable, the first parameter passed into FFOR() allows users to define the iterable data structure that you wish to operate the functor on.

actionFn, the second parameter passed into FFOR() allows users to operate on an iterable with an arbitrary function.

setNode, the third parameter passed into FFOR() is an object that describes the starting point and interval of iteration. Omission of this parameter sets default values:

  • setNode.startAt: every iteration starts at the -1 index, as this index increments before every iteration cycle. After incrementing, and before the first iteration cycle, this value increments to 0, and is used as the first index.
  • setNode.jump: this allows the user to set the jump interval before the functor operation.
  const { 
    FIF, FDEC,
    createIterator,
    createNode,
    createEdge
  } = require( 'func-fave' );

  function FFOR(
    iterable,
    actionFn,
    setNode = {
      'startAt': -1,
      'jump': 1
    }
  ) {
  
    const node = createNode();
    node.set({
      index: createEdge(setNode.startAt),
      elem: createEdge(),
      jump: createEdge(setNode.jump),
      self: createEdge(iterable),
      history: createEdge([]),
      back: createEdge(false),
      end: createEdge(false),
      cont: createEdge(false)
    });
  
    const { 
      index, elem, jump, 
      self, history, 
      back, end, cont
    } = node.get();
  
    const iterator = createIterator(
      index,
      elem,
      jump,
      
      self,
      history,
      
      back,
      end,
      cont
    )
  
    return FDEC(
      (
        FIF(
          (end.get())
          ,
          () => 1,
          () => 0
        )
      ),
      () => {
  
        /* backtrack to index where end.set(true) was called */
        /* remove last iteration from history */
        iterator.backtracking();
        /* end iteration loop */
        return node.get().history.get();
  
      },
      () => {
  
        return FIF(
          (back.get())
          ,
          () => {
  
            back.set(false);
            return iterator.backtracking(
              actionFn,
              node
            )
  
          },
          () => {
  
            return iterator.iterating(
              actionFn,
              node
            )
  
          }
        )
  
      }
    )
  
  }

NOTE: When using back.set(true) to implement backtracking, be sure to remove the last index of the return value of FFOR(). This last index will contain a circular object reference. If you have no use for this circular reference, implement the following:

  const { FFOR } = require( 'func-fave' );
  const recursiveResult = FFOR(
    /* ... */
  ).slice(0, -1)
  /*  the '.slice()' method provides a clean way to remove the last index. */

usage:

  const { FFOR, FIF } = require('func-fave')
  
  const cFBT = { //-- cFBT = checkForBackTrack
    'a': 0, 'd': 0, 'j': 0, 'o': 0, 
    'r': 0, 'n': 0, 'e': 0, 'd': 0,
    '_': 0,
  }

  const cFBT_limit = 50;
  
  const startTime = performance.now();
  
  const recursiveResult = FFOR(
    ("adjorned_1_3_5_8"),
    (Node) => {
  
      const { 
        index, elem, 
        jump, self,
        back, end, 
        cont,
      } = Node.get();
  
      return FIF(
        ( cFBT[elem.get().toString()] < cFBT_limit ),
        () => {
  
          cFBT[elem.get().toString()]++
  
          back.set(true)
          //end.set(true)
          //cont.set(true)
  
          return {"elem": elem.get()}
  
        },
        () => { return {"index": index.get()} }
      )
  
    },
  ).slice(0, -1)
  
  const endTime = performance.now();
  
  console.log(` time elapsed (ms): ${Math.floor(endTime - startTime)} `)
  console.log(`\nFFOR() return value: `)
  console.log(recursiveResult)
  console.log(`\ncheck for backtracking: (limit --> ${cFBT_limit}) `)
  console.log(cFBT)

createIterator()

description:

The createIterator() function initiates and returns a new instance of the Functional Iterator class. This class is what allows the FFOR() functor to iterate, backtrack, break, and continue. The functional iterator, abbrev FIT, recursively iterates over a specified iterable. The State Managers maintain the state of each iteration cycle over the specified iterable.


  class FunctionalIterator {
    /* meat and potatoes... */
  }

  function createIterator(
    Index,
    Iterand,
    Interval,
    Body,
    History,
    Back,
    End,
    Cont
  ) {

    return new FunctionalIterator(
      Index,
      Iterand,
      Interval,
      Body,
      History,
      Back,
      End,
      Cont
    )

  }

State Managers

createEdge()

description:

The createEdge() function initiates and returns a class that contains and records changes to the value it holds.

  const { FIM } = require( 'func-fave' );
  const { 
    createStack, 
    createIdentifier,
    ID
  } = require( 'private-func-fave' ); // private meaning unreachable
  
  class Edge {
    constructor(value) {
      this.id = ID.generate('edge')
      this.value = value;
      this.origin = value;
      this.history = createStack([value]);
      this.folds = [];
    }
  
    get = () => this.value;
    set = (value) => {
      this.value = value;
      this.history.add(value);
    }
    reset = () => {
      this.value = this.history[0];
      this.origin = this.history[0];
      this.history = [this.value];
      this.folds = [];
    }
    getHistory = () => this.history;
    getOrigin = () => this.origin;
    getLength = () => this.history.length;
    getFolds = () => this.folds;
    setFolds = (value) => { this.folds = value; }
    resetFolds = () => { this.folds = []; }
    pushFolds = (value) => { this.folds.push([value]) }
    foldWith = (counterEdge) => {
  
      return FIM(
        () => {
          const generateFolds = (self, entity) => {
            return {
              origin: self,
              value: [self.getHistory(), entity.getHistory()],
              heads: [ self.get(), entity.get() ],
              tails: [ self.getHistory()[0], entity.getHistory()[0] ]
            }
          }
  
          counterEdge.pushFolds(generateFolds(counterEdge, this))
          const foldedEdges = generateFolds(this, counterEdge)
          this.pushFolds(foldedEdges)
  
          return foldedEdges;
        }
      )
  
    }
  
    unfold = (fold, counterFold) => {
  
      const fold_arr = [fold, counterFold];
      for (let fold of fold_arr) { fold.origin.resetFolds() }
  
    }
  
  }
  
  function createEdge(value) {
    return new Edge(value);
  }

createNode()

description:

The createNode() function initiates and returns a class that contains and records any state, which is a combination of Edges. Just as any State is a collection of information, any Node State is a collection of Edges.

In theory, a 'State Space' is a collection of Node States. These levels of abstraction can keep going upwards if there is information to be recorded and changed, and there are efficient and appropriate use cases for these abstractions.

  const {
    createIdentifier,
    ID
  } = require( 'private-func-fave' ); // private meaning unreachable
  
  class Node {
  
    constructor(body) {
      this.body = body;
      this.id = ID.generate('node');
    }
  
    get = () => this.body;
    set = (value) => this.body = value;
  
  }
  
  function createNode(body = []) {
    return new Node(body);
  }