DEV Community

Cover image for Documenting JS functions as haskell :P
Damian Cipolat
Damian Cipolat

Posted on

2

Documenting JS functions as haskell :P

Documenting functions in javascript

The idea of this repository is to continue with the last 2 projects that I raised on functional programming in js.

But why?

For some time I have been dedicated to javascript and I see that there is still no standard on how developers should document what data should be passed as parameters. Although JS is not a typed language, somehow we have to specify what data is sent in each parameter.

Currently: Currently this is one of my functions, I have started working with this format.

/*
  Receive currency code and return money simbol.
  Params
    currency : string
  Return
    string
*/
const getSymbol = (currency)=>{

  switch(currency){
    case 'ARS':
      return '$';
    case 'USD':
      return 'U$S';
    default:
      return '$';
  }

}

New format: I'm moving to this new format.

/*
  Receive currency code and return money simbol.
  getSymbol:: string → string
*/
const getSymbol = (currency)=>{...}

Solution - Type Signatures

These type notations are a meta language called Type Signatures, defines the inputs and outputs for the function, sometimes including the number of arguments, the types of arguments and order of arguments contained by a function.

Type Signatures are based on Hindley-Milner Type system as a standard type system which is also followed by ML-influenced languages, including Haskell.

Some examples:

// length :: String → Number
const length = s => s.length;

// length :: [Number] → Number
const length = arr => arr.length;

// join :: (String, [String]) → String
const join = (separator, arr) => arr.join(separator)

Code examples:

The sections are divided in One parameter / Multiple parameters / High order functions.

One parameter:

Examples using 1 parameter as input and one flat return data, f(x) = y.

  • STRING - f(String) = Number:
//length :: String → Number
const length = (a)=>a.length;
  • NUMBER - f(Number) = Number:
//increase :: Number → Number
const increase = value => value+10;
  • BOOLEAN - f(Bool) = Bool.
//inverse :: Bool → Bool
const inverse = value => !value;
  • ARRAY - f([x]) = Number.
//length :: [a] → Number
const length = list => list.length;

//length :: [string] → Number
const length = list => list.length;

//length :: [Number] → Number
const length = list => list.length;
  • DATE - f(date) = Bool.
//expire :: Date → Bool
const expire = expireDate => new Date()<=expireDate;
  • FUNCTION - f(g([a])) = [b].
//map :: (a → b) → [a] → [b]
const map = fn => arr => arr.map(fn)
  • ANY - f(*) = b.
//isNull :: * → Bool.
const isNull = obj => !!obj;
  • OBJECT - f(object) = String.

Generic format

//map :: object → string
const toJson = obj => JSON.stringify(obj);

Custom format

//map :: {name:String, age: Number} → string
const toJson = people => JSON.stringify(people);

Array of objects

//map :: [{name:String, age: Number}] → [string]
const encode = people => people.map(p=>btoa(p));

Multiple parameters:

Examples using 2 parameters as input and one flat return data, f(x,y) = z.

  • STRING:
// join :: (String, [String]) → String
const join = (separator, arr) => arr.join(separator)
  • Number - f(x,y) ) = z.
// sum :: (Number, Number) → Number
const sum = (x,y) => x+y;
  • Array - f([a],b) = c.
//concat :: [*],string → string
const concat = (list,char) => list.join(char).

High order parameters:

When a function is passed as parameter, we wrap it’s signature in a parentheses to present a more meaningful overall Type Signature. f(g(x)) = y

// addOneToAll :: ((Number → Number),[Number]) → [Number]
const addOneToAll = (addOne = x=>x+1 , arr) => arr.map(addOne)

Using in real world JS

Examples converting functions, comments signature.

Example 1

Before, code example.

/*
  Receive two arrays with field, analyze both parameters and return the situation.
  Params
    flowFields   : {fields:[],onboarding_vu:string,document_attached:string}
    clientFields : {fields:[],onboarding_vu:string,document_attached:string}
  Return
    [string] : required fields
*/
const underAge = birth => !birth || (birth && moment().diff(birth, 'years')) < 18;

After, code example using the meta lenguage notation.

/*
  Receive two arrays with field, analyze both parameters and return the situation.
  underAge :: date → bool
*/
const underAge = birth => !birth || (birth && moment().diff(birth, 'years')) < 18;

Example 2

Before, code example.

/*
  GET a file from S3 bucket.
  Params 
    S3 : aws s3 instance,
    params : {Bucket:'xxxx',Key:'xxxx'}
  Return
    promise
*/
const getFile = (s3,params) => s3.getObject(params).promise();

After, code example using the meta lenguage notation.

/*
  GET a file from S3 bucket.
  getFile :: object, {Bucket:string, Key:string} → promise
*/
const getFile = (s3,params) => s3.getObject(params).promise();

Readings:

Postmark Image

Speedy emails, satisfied customers

Are delayed transactional emails costing you user satisfaction? Postmark delivers your emails almost instantly, keeping your customers happy and connected.

Sign up

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay