zamf
zamf

Reputation: 35

Function that will execute function depending on value. Functional programming

I have two functions and they are executed depending of if statement. E.g.:

if(value) {
    doA()
} else {
    doB()
}

How to write function or object that will take the result and decide whether or not execute each function. I want to receive something like this:

exists(result).doA()
nothing(result).doB()

I want to learn some functional programming in JavaScrit so I woud appreciate any source from which I can learn FP in JavaScript.

Upvotes: 0

Views: 1026

Answers (3)

Mulan
Mulan

Reputation: 135357

continuation passing style

here's an approach using continuation passing style. you'll notice the implementation of main is not far off from your original encoding – once you finish wrapping your head around this, if you haven't already learned about monads, you now know the best one (cont) ^_^

// cont :: a -> (a -> b) -> b
const cont = x =>
  k => k (x)
  
// when :: (a -> boolean, a -> b, a -> b) -> a -> (a -> b) -> b
const when = (f,l,r) => x =>
  f (x) ? cont (l (x)) : cont (r (x))

// isOdd :: number -> boolean  
const isOdd = x =>
  x & 1 === 1
  
// doA :: number -> number    
const doA = x =>
  x + 1

// doB :: number -> number
const doB = x =>
  x * x

// main :: number -> void
const main = x =>
  cont (x) (when (isOdd, doA, doB)) (console.log)
  
main (3) // IO: 4,  doA (3) === 3 + 1
main (4) // IO: 16, doB (4) === 4 * 4


data constructors

here's another approach using simple data constructors Left and Right to represent a Fork sum type – this results in a sort of data-directed style where the control of main is determined by the input type

// type Fork a = Left a | Right a

// Left a :: { fork :: (a -> b, _) -> b }
const Left = x =>
  ({ type: Left, fork: (f,_) => f (x) })

// Right a :: { fork :: (_, a -> b) -> b }  
const Right = x =>
  ({ type: Right, fork: (_,f) => f (x) })

// doA :: number -> number    
const doA = x =>
  x + 1

// doB :: number -> number
const doB = x =>
  x * x

// main :: Fork a -> a
const main = f =>
  // fork applies the left function (doA) to a Left
  // fork applies the right function (doB) to a Right
  f.fork (doA, doB)
  
console.log (main (Left (3)))  // => 4, doA (3) === 3 + 1
console.log (main (Right (3))) // => 9, doB (3) === 3 * 3

Upvotes: 1

Patrick Hund
Patrick Hund

Reputation: 20246

You could write something like this, for example:

function exists(value) {
    return function (func) {
        if (value !== undefined) {
            return func(value);
        }
        return null;
    }
}

function nothing(value) {
    return function (func) {
        if (value === undefined) {
            return func();
        }
        return null;
    }
}

function doA(value) {
    console.log('doing A', value);
}

function doB() {
    console.log('doing B');
}

const foo = 'fool';
const bar = undefined;

exists(foo)(doA);
nothing(bar)(doB);

The exists function gets a value and returns another function. The function that is returned gets yet another function as argument, which is executed if the value passed is defined.

I've used “old school” anonymous functions in the example above to make it easier to understand. With ES6 arrow functions, you can write the exists and nothing functions more consisely, like this:

function exists(value) {
    return func => value !== undefined ? func(value) : null;
}

function nothing(value) {
    return func => value === undefined ? func(value) : null;
}

The “functional programming fun” really starts when you realize you can refactor these two functions by putting the common code in another function, that is then used to create the two functions, like this:

function executeWithCondition(predicate) {
    return value => func => predicate(value) ? func(value) : null;
}

const exists = executeWithCondition(value => value !== undefined);
const nothing = executeWithCondition(value => value === undefined);

This technique is called currying.

Usage of these functions is still the same:

exists(foo)(doA);
nothing(bar)(doB);

Here's the complete runnable code example:

function executeWithCondition(predicate) {
    return value => func => predicate(value) ? func(value) : null;
}

const exists = executeWithCondition(value => value !== undefined);
const nothing = executeWithCondition(value => value === undefined);

function doA(value) {
    console.log('doing A', value);
}

function doB() {
    console.log('doing B');
}

const foo = 'fool';
const bar = undefined;

exists(foo)(doA);
nothing(bar)(doB);

Upvotes: 0

guest271314
guest271314

Reputation: 1

One approach would be to define the properties of an object with values set to functions

const o = {
  exists: function(value) {
    return value ? this.doA() : this.doB()
  },
  doA: function(value) {
    console.log("A")
  },
  doB: function(value) {
    console.log("B")
  }
}

o.exists(void 0);

Upvotes: 0

Related Questions