# Combinators

#### applyTo

`crocks/combinators/applyTo`

`applyTo :: a -> (a -> b) -> b`

Ever run into a situation where you have a value but do not have a function to apply it to? Well this little bird, named Thrush, is there to help out. Just give it a value and it will give you back a function ready to take a function. Once that function is provided, it will return the result of applying your value to that function.

```
import applyTo from 'crocks/combinators/applyTo'
import First from 'crocks/First'
import Pair from 'crocks/Pair'
import compose from 'crocks/helpers/compose'
import flip from 'crocks/combinators/flip'
import isArray from 'crocks/predicates/isArray'
import isNumber from 'crocks/predicates/isNumber'
import isString from 'crocks/predicates/isString'
import map from 'crocks/pointfree/map'
import merge from 'crocks/pointfree/merge'
import mreduceMap from 'crocks/helpers/mreduceMap'
import safeLift from 'crocks/Maybe/safeLift'
// prices :: [ Number ]
const prices = [ 4.99, 29.99, 15.99 ]
// getPrices :: (a -> b) -> [ Number ]
const getPrices = compose(
applyTo(prices),
map
)
// discount :: Number -> Number -> Number
const discount = percent => price =>
Number((price - percent / 100 * price).toFixed(2))
getPrices(discount(10))
//=> [ 4.49, 26.99, 14.39 ]
getPrices(discount(80))
//=> [ 1, 6, 3.2 ]
// add :: Number -> Number -> Number
const add = x => y =>
x + y
// runAll :: [ (a -> b) ] -> a -> [ b ]
const runAll =
flip(compose(map, applyTo))
runAll([ add(10), add(20) ], 3)
//=> [ 13, 23 ]
// length :: [ a ] -> Number
const length = x =>
x.length
// yell :: String -> String
const yell = x =>
x.toUpperCase()
// Strategy :: Pair (a -> Boolean) (* -> *)
// strategies :: [ Strategy ]
const strategies = [
Pair(isNumber, add(10)),
Pair(isArray, length),
Pair(isString, yell)
]
// options :: [ Strategy ] -> a -> b
const options = flip(
x => mreduceMap(
First,
compose(applyTo(x), merge(safeLift))
)
)
options(strategies, 'hello')
//=> Just "HELLO"
options(strategies, [ 1, 9, 39 ])
//=> Just 3
options(strategies, 13)
//=> Just 23
options(strategies, null)
//=> Nothing
```

#### compose2

`crocks/combinators/compose2`

`compose2 :: (c -> d -> e) -> (a -> c) -> (b -> d) -> a -> b -> e`

`compose2`

allows for composition between a `binary`

function and two `unary`

functions. `compose2`

takes a `binary`

function followed by two `unary`

functions and returns a `binary`

function that maps the first argument with the first `unary`

and the second with the second, passing the results to the given `binary`

and returning the result.

```
import compose2 from 'crocks/combinators/compose2'
import and from 'crocks/logic/and'
import applyTo from 'crocks/combinators/applyTo'
import flip from 'crocks/combinators/flip'
import hasProp from 'crocks/predicates/hasProp'
import isNumber from 'crocks/predicates/isNumber'
import liftA2 from 'crocks/helpers/liftA2'
import map from 'crocks/pointfree/map'
import prop from 'crocks/Maybe/prop'
import safe from 'crocks/Maybe/safe'
import safeLift from 'crocks/Maybe/safeLift'
// isNonZero :: Number -> Boolean
const isNonZero = x =>
x !== 0
// isValidDivisor :: Number -> Boolean
const isValidDivisor =
and(isNumber, isNonZero)
// divideBy :: Number -> Number -> Number
const divideBy = x => y =>
y / x
// safeDivide :: Number -> Number -> Maybe Number
const safeDivide = compose2(
liftA2(divideBy),
safe(isValidDivisor),
safe(isNumber)
)
safeDivide(0.5, 21)
//=> Just 42
safeDivide('0.5', 21)
//=> Nothing
safeDivide(0.5, '21')
//=> Nothing
safeDivide(29, 0)
//=> Just 0
safeDivide(0, 29)
//=> Nothing
// Item :: { id: Integer }
// Items :: Array Item
const items =
[ { id: 2 }, { id: 1 } ]
// pluck :: String -> Array Object -> Maybe a
const pluck =
compose2(applyTo, prop, flip(map))
pluck('id', items)
//=> [ Just 2, Just 1 ]
// summarize :: String -> String -> String
const summarize = name => count =>
`${name} purchased ${count} items`
// getLength :: a -> Maybe Number
const getLength = safeLift(
hasProp('length'),
x => x.length
)
// createSummary :: Person -> Array Item -> String
const createSummary = compose2(
liftA2(summarize),
prop('name'),
getLength
)
createSummary({
name: 'Sam Smith'
}, items)
//=> Just "Sam Smith purchased 2 items"
// capitalize :: String -> String
const capitalize = str =>
`${str.charAt(0).toUpperCase()}${str.slice(1)}`
// join :: String -> String -> String -> String
const join = delim => right => left =>
`${left}${delim}${right}`
// toUpper :: String -> String
const toUpper = x =>
x.toUpperCase()
// createName :: String -> String -> String
const createName =
compose2(join(', '), capitalize, toUpper)
createName('Jon', 'doe')
//=> DOE, Jon
createName('sara', 'smith')
//=> SMITH, Sara
```

#### composeB

`crocks/combinators/composeB`

`composeB :: (b -> c) -> (a -> b) -> a -> c`

Provides a means to describe a composition between two functions. it takes two functions and a value. Given `composeB(f, g)`

, which is read `f`

after `g`

, it will return a function that will take value `a`

and apply it to `g`

, passing the result as an argument to `f`

, and will finally return the result of `f`

. This allows only two functions, if you want to avoid things like:`composeB(composeB(f, g), composeB(h, i))`

then check out `compose`

.

```
import composeB from 'crocks/combinators/composeB'
import Either from 'crocks/Either'
import ifElse from 'crocks/logic/ifElse'
import isString from 'crocks/predicates/isString'
const { Left, Right } = Either
// yell :: String -> String
const yell = x =>
`${x.toUpperCase()}!`
// safeYell :: a -> Either a String
const safeYell = ifElse(
isString,
composeB(Right, yell),
Left
)
safeYell('quite')
//=> Right "QUITE!"
safeYell(42)
//=> Left 42
```

#### constant

`crocks/combinators/constant`

`constant :: a -> () -> a`

This is a very handy dandy function, used a lot. Pass it any value and it will give you back a function that will return that same value no matter what you pass it.`constant`

is perfect for those moments where you need to pass a function but do not care about the input. `constant`

will swallow any value given to it and always return the initial value it was given. It is important to note that any function that is passed into `constant`

will get the added benefit of having `curry`

applied to it.

```
import constant from 'crocks/combinators/constant'
import Result from 'crocks/Result'
import bimap from 'crocks/pointfree/bimap'
import composeB from 'crocks/combinators/composeB'
import ifElse from 'crocks/logic/ifElse'
import isString from 'crocks/predicates/isString'
import getPropOr from 'crocks/helpers/getPropOr'
const { Ok, Err } = Result
// whatsTheAnswer :: () -> Number
const whatsTheAnswer =
constant(42)
whatsTheAnswer('to life?')
//=> 42
whatsTheAnswer('to the universe?')
//=> 42
whatsTheAnswer('to everything?')
//=> 42
// ensure :: (a -> Boolean) -> a -> Result a
const ensure = pred =>
ifElse(pred, Ok, Err)
// getLength :: Result a String -> Result Number
const getLength = bimap(
constant(0), getPropOr(0, 'length')
)
// getLengthOfString :: a -> Result a String
const getLengthOfString = composeB(
getLength,
ensure(isString)
)
getLengthOfString('testing')
//=> Ok 7
getLengthOfString(42)
//=> Err 0
getLengthOfString([ 1, 2, 3, 4 ])
//=> Err 0
```

#### converge

`crocks/combinators/converge`

`converge :: (b -> c -> d) -> (a -> b) -> (a -> c) -> a -> d`

Provides a means of passing an acculumating function and two branching functions. A value can be applied to the resulting function which will then be applied to each branching function, the results of which will be applied to the accumulating function.

```
import converge from 'crocks/combinators/converge'
import alt from 'crocks/pointfree/alt'
import getProp from 'crocks/Maybe/getProp'
import liftA2 from 'crocks/helpers/liftA2'
import getPropOr from 'crocks/helpers/getPropOr'
// data :: [ Number ]
const data = [ 1, 2, 3, 4, 5 ]
// divide :: Number -> Number -> Number
const divide = x => y =>
y / x
// add :: (Number, Number) -> Number
const add = (a, b) =>
b + a
// sum :: [ Number ] -> Number
const sum = xs =>
xs.reduce(add, 0)
// length :: [ a ] -> Number
const length =
getPropOr(0, 'length')
// average :: [ Number ] -> Number
const average =
converge(divide, length, sum)
average(data)
//=> 3
// maybeGetDisplay :: a -> Maybe b
const maybeGetDisplay =
getProp('display')
// maybeGetFirst :: a -> Maybe b
const maybeGetFirst =
getProp('first')
// maybeGetLast :: a -> Maybe b
const maybeGetLast =
getProp('last')
// buildFullName :: String -> String -> String
const buildFullName = surname => firstname =>
`${firstname} ${surname}`
// maybeConcatStrings :: Maybe String -> Maybe String -> Maybe String
const maybeBuildFullName = a => b =>
liftA2(buildFullName, a, b)
.alt(a)
.alt(b)
// maybeMakeDisplay :: a -> Maybe String
const maybeMakeDisplay = converge(
maybeBuildFullName,
maybeGetLast,
maybeGetFirst
)
// maybeGetName :: a -> Maybe b
const maybeGetName =
converge(alt, maybeMakeDisplay, maybeGetDisplay)
maybeGetName({ display: 'Jack Sparrow' })
//=> Just "Jack Sparrow"
maybeGetName({ first: 'J', last: 'S' })
//=> Just "J S"
maybeGetName({ display: 'Jack Sparrow', first: 'J', last: 'S' })
//=> Just "Jack Sparrow"
maybeGetName({ first: 'J' })
//=> Just "J"
maybeGetName({ first: 'S' })
//=> Just "S"
```

#### flip

`crocks/combinators/flip`

`flip :: (a -> b -> c) -> b -> a -> c`

This little function just takes a function and returns a function that takes the first two parameters in reverse. `flip`

is perfectly suited for those moments where you have the context of your function but not the data. Applying `flip`

to the function will allow you to pass in your context and will return a function waiting for the data. This will happen often when you're using composition.

When required, one can compose flip calls down the line to flip all, or some of the other parameters if there are more than two. Mix and match to your heart's desire.

```
import flip from 'crocks/combinators/flip'
import Pred from 'crocks/Pred'
import composeB from 'crocks/combinators/composeB'
import concat from 'crocks/pointfree/concat'
import isNumber from 'crocks/predicates/isNumber'
import mconcat from 'crocks/helpers/mconcat'
import runWith from 'crocks/pointfree/runWith'
concat('first param. ', 'second param. ')
//=> "second param. first param. ""
flip(concat, 'first param. ', 'second param. ')
//=> "first param. second param. ""
// checkAll :: [ a -> Boolean ] -> a -> Boolean
const checkAll =
composeB(flip(runWith), mconcat(Pred))
// lte :: Number -> Number -> Boolean
const lte = a => b =>
b <= a
// gte :: Number -> Number -> Boolean
const gte = a => b =>
b >= a
// between2and10 :: a -> Boolean
const between2and10 = checkAll([
isNumber,
gte(2),
lte(10)
])
between2and10(8)
//=> true
between2and10(11)
//=> false
between2and10(1)
//=> false
between2and10('not a number')
//=> false
```

#### identity

`crocks/combinators/identity`

`identity :: a -> a`

This function and `constant`

are the workhorses of writing code with this library. It quite simply is just a function that when you pass it something, it returns that thing right back to you. So simple, I will leave it as an exercise to reason about why this is so powerful and important.

#### psi

`crocks/combinators/psi`

`psi :: (b -> b -> c) -> (a -> b) -> a -> a -> c`

`psi`

is a function that can be considered the sister of `converge`

. Where `converge`

takes one argument and maps it through two `unary`

functions, merging the resulting values with a binary function, `psi`

takes two arguments and runs them each through the same `unary`

function before merging them with the given binary function.

`psi`

is often used to `compose`

equality checking functions or when needing to validate two arguments of the same type.

```
import psi from 'crocks/combinators/psi'
import and from 'crocks/logic/and'
import equals from 'crocks/pointfree/equals'
import isNumber from 'crocks/predicates/isNumber'
import liftA2 from 'crocks/helpers/liftA2'
import safe from 'crocks/Maybe/safe'
// isNonZero :: Number -> Boolean
const isNonZero = x =>
x !== 0
// isValidDivisor :: Number -> Boolean
const isValidDivisor =
and(isNumber, isNonZero)
// divideBy :: Number -> Number -> Number
const divideBy = x => y =>
y / x
// safeDivide :: Number -> Number -> Maybe Number
const safeDivide =
psi(liftA2(divideBy), safe(isValidDivisor))
safeDivide(0.5, 21)
//=> Just 42
safeDivide('0.5', 21)
//=> Nothing
safeDivide(0.5, '21')
//=> Nothing
safeDivide(29, 0)
//=> Nothing
// capitalize :: String -> String
const capitalize = str =>
`${str.charAt(0).toUpperCase()}${str.slice(1)}`
// join :: String -> String -> String -> String
const join = delim => right => left =>
`${left}${delim}${right}`
// createName :: String -> String -> String
const createName =
psi(join(', '), capitalize)
createName('Jon', 'doe')
//=> Doe, Jon
createName('sara', 'smith')
//=> Smith, Sara
// toLowerCase :: String -> String
const toLowerCase = str =>
str.toLowerCase()
// equalsIgnoreCase :: String -> String -> Boolean
const equalsIgnoreCase =
psi(equals, toLowerCase)
equalsIgnoreCase('test', 'TEst')
//=> true
equalsIgnoreCase('test', 'not-test')
//=> false
```

#### substitution

`crocks/combinators/substitution`

`substitution :: (a -> b -> c) -> (a -> b) -> a -> c`

While it may seem like a complicated little bugger, `substitution`

can come in very handy from time to time. `substitution`

is used when you have a `binary`

function and you can supply the first argument and can use that value to create the second argument. It first takes a `binary`

function followed by a `unary`

function for it's first two arguments. This will return a function that is ready to take some context, `a`

. Once supplied the fun starts, it will pass the given `a`

to the `binary`

and `unary`

functions, and will then apply the result of the `unary`

function as the second parameter of the `binary`

function. Finally after all that juggling, it will return the result of that `binary`

function.

When used with partial application on that first parameter, a whole new world of combinatory madness is presented!

```
import substitution from 'crocks/combinators/substitution'
import composeB from 'crocks/combinators/composeB'
import curry from 'crocks/core/curry'
// getDetails :: String -> Number -> String
const getDetails = curry((text, length) =>
`The given text "${text}" has a length of ${length}`
)
// getLength :: a -> Number
const getLength = s =>
s.length
substitution(getDetails, getLength, 'testing')
//=> "The given text \"testing\" has a length of 7"
// getLastIndex :: a -> Number
const getLastIndex = composeB(
x => x - 1,
getLength
)
// slice :: Array -> Number -> Array
const slice = curry((arr, index) =>
arr.slice(index))
substitution(slice, getLastIndex, [ 1, 2, 3, 4, 5 ])
//=> [ 5 ]
```

Contribute on Github! Edit this section.