Crocks

  • Documentation
Docs Menu
  • Getting Started
  • Crocks
    • Arrow
    • Async
    • Const
    • Either
    • Equiv
    • Identity
    • Maybe
    • Pair
    • Pred
    • Reader
    • ReaderT
    • Result
    • State
    • Tuple
  • Monoids
    • All
    • Any
    • Assign
    • Endo
    • First
    • Last
    • Max
    • Min
    • Prod
    • Sum
  • Functions
    • Combinators
    • Helpers
    • Logic Functions
    • Predicate Functions
    • Point-free Functions
    • Transformation Functions

Maybe

Maybe a = Nothing | Just a

Defined as a Sum Type with its left side fixed to () (Nothing), Maybe is well suited for capturing disjunction when the cause of the "error" case does not need to be communicated. For example, providing default values on specific conditions.

A Maybe represents disjunction by using two constructors, Nothing or Just. A Just instance represents the truth case while Nothing is considered false. With the exception of coalesce, all Maybe returning methods on an instance will be applied to a Just returning the result. If an instance is a Nothing, then all application is skipped and another Nothing is returned.

It is recommended to use the available Just and Nothingconstructors to construct Maybe instances in most cases. You can use the Maybe constructor to construct a Just, but it may read better to just use Just.

import Maybe from 'crocks/Maybe'

import chain from 'crocks/pointfree/chain'
import compose from 'crocks/helpers/compose'
import ifElse from 'crocks/logic/ifElse'
import isNumber from 'crocks/predicates/isNumber'

const { Just, Nothing } = Maybe

// gt5 :: Number -> Boolean
const gt5 =
  x => x > 5

// safe :: (a -> Boolean) -> a -> Maybe b
const safe = pred =>
  ifElse(pred, Just, Nothing)

// safeNumber :: a -> Maybe Number
const safeNumber =
  safe(isNumber)

// maybeBig :: Number -> Maybe Number
const maybeBig =
  safe(gt5)

// bigNumber :: a -> Maybe Number
const bigNumber = compose(
  chain(maybeBig), safeNumber
)

safeNumber(45)
//=> Just 45

safeNumber('99')
//=> Nothing

maybeBig(99)
//=> Just 99

maybeBig(2)
//=> Nothing

bigNumber(34)
//=> Just 34

bigNumber('string')
//=> Nothing

bigNumber(3)
//=> Nothing

Implements

Setoid, Semigroup, Functor, Alt, Plus, Apply, Traversable,Chain, Applicative, Alternative, Monad

Construction

Maybe :: a -> Maybe a

Most of the time, Maybe is constructed using helper functions like safe or by employing one of the instance constructors, Just or Nothing. This is due to the nature of Maybe and most other Sum Types.

As a matter of consistency and completion, a Maybe instance can also be constructed using its TypeRep like any other type. The Maybe constructor is a unary function that accepts any type a and returns a Just instance, wrapping the value passed to its argument.

import Maybe from 'crocks/Maybe'
import equals from 'crocks/pointfree/equals'

Maybe('some string')
//=> Just "some string"

Maybe(null)
//=> Just null

Maybe(undefined)
//=> Just undefined

Maybe.of('some string')
//=> Just "some string"

Maybe.of(null)
//=> Just null

Maybe.of(undefined)
//=> Just undefined

Maybe.Just('some string')
//=> Just "some string"

Maybe.Just(null)
//=> Just null

Maybe.Just(undefined)
//=> Just undefined

equals(
  Maybe.Just([ 1, 2, 3 ]),
  Maybe.of([ 1, 2, 3 ])
)
//=> true

equals(
  Maybe.of({ a: 100 }),
  Maybe({ a: 100 })
)
//=> true

Constructor Methods

Nothing

Maybe.Nothing :: () -> Maybe a

Used to construct a Nothing instance that represents the "false" portion of a disjunction. When an instance is a Nothing, most Maybe returning methods will just return another Nothing. Anything passed to the constructor will be thrown out and mapped to ().

import Maybe from 'crocks/Maybe'

import chain from 'crocks/pointfree/chain'
import isNumber from 'crocks/predicates/isNumber'
import safeLift from 'crocks/Maybe/safeLift'

const { Just, Nothing } = Maybe

// add10 :: Number -> Number
const add10 =
  x => x + 10

// safeAdd10 :: a -> Maybe Number
const safeAdd10 =
  safeLift(isNumber, add10)

Just(23)
  .map(add10)
//=> Just 33

Nothing(23)
  .map(add10)
//=> Nothing

chain(safeAdd10, Just(10))
//=> Just 20

chain(safeAdd10, Nothing())
//=> Nothing

Just

Maybe.Just :: a -> Maybe a

Used to construct a Just instance that represents the "true" portion of a disjunction or a valid value. Just will wrap any given value in a Just, signaling the validity of the wrapped value.

import Maybe from 'crocks/Maybe'

import compose from 'crocks/helpers/compose'
import ifElse from 'crocks/logic/ifElse'
import isString from 'crocks/predicates/isString'
import map from 'crocks/pointfree/map'

const { Just, Nothing } = Maybe

// toUpper :: String -> String
const toUpper =
  x => x.toUpperCase()

// safe :: (a -> Boolean) -> a -> Maybe a
const safe =
  pred => ifElse(pred, Just, Nothing)

// safeShout :: a -> Maybe String
const safeShout = compose(
  map(toUpper),
  safe(isString)
)

safeShout(45)
//=> Nothing

safeShout('Hey there!')
//=> Just "HEY THERE!"

of

Maybe.of :: a -> Maybe a

Used to wrap any value into a Maybe as a Just, of is used mostly by helper functions that work "generically" with instances of either Applicative or Monad. When working specifically with the Maybe type, the Just constructor should be used. Reach for of when working with functions that will work with ANY Applicative/Monad.

import Maybe from 'crocks/Maybe'

import curry from 'crocks/helpers/curry'
import isString from 'crocks/predicates/isString'
import safe from 'crocks/Maybe/safe'

const { Just } = Maybe

Maybe(35)
//=> Just 35

Just(35)
//=> Just 35

Maybe.of(35)
//=> Just 35

const safeString =
  safe(isString)

// lift2 :: Applicative m => (a -> b -> c) -> m a -> m b -> m c
const lift2 = curry(
  (fn, x, y) => x.of(fn).ap(x).ap(y)
)

// join :: Applicative m => m String -> m String -> m String
const join =
  lift2(a => b => `${a} ${b}`)

join(safeString('Brad'), safeString('Pitt'))
//=> Just "Brad Pitt"

join(safeString(34), safeString('Pitt'))
//=> Nothing

zero

Maybe.zero :: () -> Maybe a

When working with Alts, zero provides a sort of empty or identity for Maybe when used with alt. zero takes no arguments and returns a Nothing instance. Just like an empty method on a given Monoid, zero can be used to fold a collection of Alts under alt.

import Maybe from 'crocks/Maybe'

import alt from 'crocks/pointfree/alt'
import flip from 'crocks/combinators/flip'
import isNumber from 'crocks/predicates/isNumber'
import mapReduce from 'crocks/helpers/mapReduce'
import safe from 'crocks/Maybe/safe'

const { Nothing, Just, zero } = Maybe

// firstValid :: [ * ] -> Maybe Number
const firstValid =
  mapReduce(safe(isNumber), flip(alt), zero())

Just(33)
  .alt(zero())
//=> Just 33

zero()
  .alt(Just(33))
//=> Just 33

Nothing()
  .alt(zero())
//=> Nothing

zero()
  .alt(Nothing())
//=> Nothing

firstValid([ null, 'nope', 10, 45 ])
//=> Just 10

firstValid([ 75, null, 'nope' ])
//=> Just 75

firstValid([ null, undefined, 'wrong' ])
//=> Nothing

Instance Methods

equals

Maybe a ~> b -> Boolean

Used to compare the underlying values of two Maybe instances for equality by value, equals takes any given argument and returns true if the passed arguments is a Maybe with an underlying value equal to the underlying value of the Maybe the method is being called on. If the passed argument is not a Maybe or the underlying values are not equal, equals will return false.

import Maybe from 'crocks/Maybe'

import equals from 'crocks/pointfree/equals'

const { Nothing, Just } = Maybe

Just(33)
  .equals(Just(33))
//=> true

Nothing()
  .equals(Nothing())
//=> true

Nothing()
  .equals(Just(33))
//=> false

// by value, not reference for most types
Just({ a: 86, b: true })
  .equals(Just({ a: 86, b: true }))
//=> true

equals(Just(95), 95)
//=> false

equals(undefined, Nothing())
//=> false

equals(Just([ 2, 3 ]), Just([ 2, 3 ]))
//=> true

concat

Semigroup s => Maybe s ~> Maybe s -> Maybe s

When an underlying value of a given Maybe is fixed to a Semigroup, concat can be used to concat another Maybe instance with an underlying Semigroup of the same type. Expecting a Maybe wrapping a Semigroup of the same type, concat will give back a new Maybe instance wrapping the result of combining the two underlying Semigroups. When called on a Nothing instance, concat will return a Nothing.

import Maybe from 'crocks/Maybe'

import Sum from 'crocks/Sum'

import compose from 'crocks/helpers/compose'
import concat from 'crocks/pointfree/concat'
import flip from 'crocks/combinators/flip'
import isNumber from 'crocks/predicates/isNumber'
import map from 'crocks/pointfree/map'
import mapReduce from 'crocks/helpers/mapReduce'
import safeLift from 'crocks/Maybe/safeLift'
import valueOf from 'crocks/pointfree/valueOf'

const { Nothing, Just } = Maybe

// safeSum :: a -> Maybe Sum
const safeSum =
  safeLift(isNumber, Sum)

// empty :: Maybe Sum
const empty =
  Just(Sum.empty())

// sumList :: [ * ] -> Maybe Number
const sumList = compose(
  map(valueOf),
  mapReduce(safeSum, flip(concat), empty)
)

Just([ 34 ])
  .concat(Just([ 92 ]))
//=> Just [ 34, 92 ]

Just([ 34 ])
  .concat(Nothing())
//=> Nothing

sumList([ 3, 4, 5 ])
//=> Just 12

sumList([ 'three', 4, 'five' ])
//=> Nothing

map

Maybe a ~> (a -> b) -> Maybe b

Used to apply transformations to values in the safety of a Maybe, map takes a function that it will lift into the context of the Maybe and apply to it the wrapped value. When ran on a Just instance, map will apply the wrapped value to the provided function and return the result in a new Just instance.

import Maybe from 'crocks/Maybe'

import assign from 'crocks/helpers/assign'
import compose from 'crocks/helpers/compose'
import isObject from 'crocks/predicates/isObject'
import isString from 'crocks/predicates/isString'
import map from 'crocks/pointfree/map'
import safe from 'crocks/Maybe/safe'

const { Nothing, Just } = Maybe

// add10 :: Number -> Number
const add10 =
  x => x + 10

// toUpper :: String -> String
const toUpper = x =>
  x.toUpperCase()

// safeObj :: a -> Maybe Object
const safeObj =
  safe(isObject)

// shout :: a -> Maybe String
const shout = x =>
  safe(isString, x)
    .map(toUpper)

// setProcessed :: a -> Maybe Object
const setProcessed = compose(
  map(assign({ processed: true })),
  safeObj
)

Just(0)
  .map(add10)
//=> Just 10

Nothing()
  .map(add10)
//=> Nothing

shout('good news')
//=> Just "GOOD NEWS"

shout(33)
//=> Nothing

setProcessed({ cheese: true })
//=> Just { cheese: true, processed: true }

setProcessed(null)
//=> Nothing

alt

Maybe a ~> Maybe a -> Maybe a

Providing a means for a fallback or alternative value, alt combines two Maybe instances and will return the first Just it encounters or Nothing if it does not have a Just. This can be used in conjunction with zero to return the first valid value in contained in a Foldable structure.

import Maybe from 'crocks/Maybe'

import alt from 'crocks/pointfree/alt'
import isArray from 'crocks/predicates/isArray'
import flip from 'crocks/combinators/flip'
import mapReduce from 'crocks/helpers/mapReduce'
import safe from 'crocks/Maybe/safe'

const { zero, Nothing, Just } = Maybe

// firstArray :: Foldable f => f * -> Maybe Array
const firstArray =
  mapReduce(safe(isArray), flip(alt), zero())

Nothing()
  .alt(Just(33))
//=> Just 33

Just(42)
  .alt(Nothing())
  .alt(Just(99))
//=> Just 42

firstArray([ 'Not Array', null, [ 2, 3, 4 ], [ 1, 2 ] ])
//=> Just [ 2, 3, 4 ]

firstArray([ null, 5, '76' ])
//=> Nothing

ap

Maybe (a -> b) ~> Maybe a -> Maybe b

Short for apply, ap is used to apply a Maybe instance containing a value to another Maybe instance that contains a function, resulting in new Maybe instance with the result. ap requires that it is called on an instance that is either a Nothing or a Just that wraps a curried polyadic function.

When either Maybe is a Nothing, ap will return a Nothing. This can be used to safely combine multiple values under a given combination function. If any of the inputs results in a Nothing than they will never be applied to the function and not provide exceptions or unexpected results.

import Maybe from 'crocks/Maybe'

import compose from 'crocks/helpers/compose'
import chain from 'crocks/pointfree/chain'
import curry from 'crocks/helpers/curry'
import fanout from 'crocks/Pair/fanout'
import getProp from 'crocks/Maybe/getProp'
import isString from 'crocks/predicates/isString'
import liftA2 from 'crocks/helpers/liftA2'
import merge from 'crocks/pointfree/merge'
import safe from 'crocks/Maybe/safe'

const { Nothing, Just } =  Maybe

// add :: Number -> Number -> Number
const add =
  x => y => x + y

// joinWith :: String -> String -> String -> String
const joinWith = curry(
  (del, x, y) => x + del + y
)

// stringProp :: String -> a -> Maybe String
const stringProp = key => compose(
  chain(safe(isString)),
  getProp(key)
)

// getNames :: a -> Pair (Maybe String) (Maybe String)
const getNames = fanout(
  stringProp('first'),
  stringProp('last')
)

// joinNames :: Pair (Maybe String) (Maybe String) -> Maybe String
const joinNames =
  merge(liftA2(joinWith(' ')))

// fullName :: a -> Maybe String
const fullName =
  compose(joinNames, getNames)

Maybe.of(add)
  .ap(Just(5))
  .ap(Just(27))
//=> Just 32

Just('hello')
  .map(joinWith(' -- '))
  .ap(Just('friend'))
//=> Just "hello -- friend"

Maybe.of(add)
  .ap(Just(29))
  .ap(Nothing())
//=> Nothing

fullName({ first: 'Joey', last: 'Fella' })
//=> Just "Joey Fella"

fullName(null)
//=> Nothing

fullName({ first: 'Lizzy' })
//=> Nothing

sequence

Apply f => Maybe (f a) ~> (b -> f b) -> f (Maybe a)
Applicative f => Maybe (f a) ~> TypeRep f -> f (Maybe a)

When an instance of Maybe wraps an Apply instance, sequence can be used to swap the type sequence. sequence requires either an Applicative TypeRep or an Apply returning function is provided for its argument. This will be used in the case that the Maybe instance is a Nothing.

sequence can be derived from traverse by passing it an identity function (x => x).

import Maybe from 'crocks/Maybe'

import Identity from 'crocks/Identity'
import sequence from 'crocks/pointfree/sequence'

const { Nothing, Just } = Maybe

// seqId :: Maybe Identity a -> Identity Maybe a
const seqId =
  sequence(Identity)

seqId(Just(Identity(34)))
//=> Identity Just 34

seqId(Nothing())
//=> Identity Nothing

traverse

Apply f => Maybe a ~> (c -> f c), (a -> f b)) -> f Maybe b
Applicative f => Maybe a ~> (TypeRep f, (a -> f b)) -> f Maybe b

Used to apply the "effect" of an Apply to a value inside of a Maybe,traverse combines both the "effects" of the Apply and the Maybe by returning a new instance of the Apply, wrapping the result of the Applys "effect" on the value in the Maybe.

traverse requires either an Applicative TypeRep or an Apply returning function as its first argument and a function that is used to apply the "effect" of the target Apply to the value inside of the Maybe. This will be used in the case that the Maybe instance is a Nothing. Both arguments must provide an instance of the target Apply.

import IO from 'crocks/IO'

import compose from 'crocks/helpers/compose'
import isNumber from 'crocks/predicates/isNumber'
import safe from 'crocks/Maybe/safe'
import traverse from 'crocks/pointfree/traverse'

// someGlobal :: Number
let someGlobal = 10

// addToGlobal :: Number -> IO Number
const addToGlobal = x => IO(function() {
  someGlobal = someGlobal + x
  return someGlobal
})

// safeAddToGlobal :: a -> IO (Maybe Number)
const safeAddToGlobal = compose(
  traverse(IO, addToGlobal),
  safe(isNumber)
)

safeAddToGlobal(32)
  .run()
//=> Just 42
//someGlobal => 42

safeAddToGlobal(undefined)
  .run()
//=> Nothing

chain

Maybe a ~> (a -> Maybe b) -> Maybe b

Combining a sequential series of transformations that capture disjunction can be accomplished with chain. chain expects a unary, Maybe returning function as its argument. When invoked on a Nothing, chain will not run the function, but will instead return another Nothing. When called on a Just however, the inner value will be passed to provided function, returning the result as the new instance.

import Maybe from 'crocks/Maybe'

import chain from 'crocks/pointfree/chain'
import compose from 'crocks/helpers/compose'
import getProp from 'crocks/Maybe/getProp'
import isNumber from 'crocks/predicates/isNumber'
import isString from 'crocks/predicates/isString'
import safe from 'crocks/Maybe/safe'
import safeLift from 'crocks/Maybe/safeLift'

const { Nothing, Just } = Maybe

// double :: Number -> Number
const double =
  x => x + x

// chainNumber :: Maybe a -> Maybe Number
const chainNumber =
  chain(safe(isNumber))

// doubleValue :: a -> Maybe Number
const doubleValue = compose(
  chain(safeLift(isNumber, double)),
  getProp('value')
)

chainNumber(Just(45))
//=> Just 45

chainNumber(Nothing())
//=> Nothing

Just(45)
  .chain(safe(isString))
//=> Nothing

doubleValue(undefined)
//=> Nothing

doubleValue({ value: '45' })
//=> Nothing

doubleValue({ number: 45 })
//=> Nothing

doubleValue({ value: 45 })
//=> Just 90

coalesce

Maybe a ~> ((() -> b), (a -> b))) -> Maybe b

When one would like to option a Maybe but would like to remain within a Maybe type, coalesce can be used. coalesce expects two functions for its inputs.

The first function is used when invoked on a Nothing and will return a Just instance wrapping the result of the function. The second function is used when coalesce is invoked on a Just and is used to map the original value, returning a new Just instance wrapping the result of the second function.

import Maybe from 'crocks/Maybe'

import compose from 'crocks/helpers/compose'
import composeK from 'crocks/helpers/composeK'
import coalesce from 'crocks/pointfree/coalesce'
import constant from 'crocks/combinators/constant'
import getProp from 'crocks/Maybe/getProp'
import identity from 'crocks/combinators/identity'
import isString from 'crocks/predicates/isString'
import map from 'crocks/pointfree/map'
import objOf from 'crocks/helpers/objOf'
import safe from 'crocks/Maybe/safe'

const { Nothing, Just } = Maybe

// shout :: String -> String
const shout =
  x => x.toUpperCase()

// defaultString :: Maybe String -> Maybe String
const defaultString =
  coalesce(constant(''), identity)

// shoutOut :: String -> Object
const shoutOut = compose(
  objOf('shout'),
  shout
)

// stringValue :: a -> Maybe String
const stringValue = composeK(
  safe(isString),
  getProp('value')
)

// shoutValue :: a -> Maybe Object
const shoutValue = compose(
  map(shoutOut),
  defaultString,
  stringValue
)

Just(76)
  .coalesce(constant(0), identity)
//=> Just 76

Nothing()
  .coalesce(constant(0), identity)
//=> Just 0

shoutValue({ value: 'hello' })
//=> Just { shout: 'HELLO' }

shoutValue(undefined)
//=> Just { shout: '' }

shoutValue({ value: 49 })
//=> Just { shout: '' }

shoutValue({})
//=> Just { shout: '' }

bichain

Maybe a ~> ((() -> Maybe b), (a -> Maybe b)) -> Maybe b

Combining a sequential series of transformations that capture disjunction can be accomplished with chain. Along the same lines, bichain allows you to do this from both Nothing and Just. bichain expects two unary, Either returning functions as its arguments. When invoked on a Nothing instance, bichain will use the left, or first, function that can return either a Nothing or a Just instance. When called on a Just instance, it will behave exactly as chain would with the right, or second, function.

import Maybe from 'crocks/Maybe'

import bichain from 'crocks/pointfree/bichain'
import constant from 'crocks/combinators/constant'

const { Nothing, Just } = Maybe

// swapMaybe :: Maybe a -> Maybe b
const swapMaybe = bichain(
  constant(Just('nothing')),
  Nothing
)

swapMaybe(Nothing())
//=> Just Nothing

swapMaybe(Just('just'))
//=> Nothing

option

Maybe a ~> a -> a

Used as the primary way to "fold" a value out of a Maybe, option expects a default value. The default value provided will be returned when option is invoked on a Nothing instance. When invoked on a Just, the underlying value is returned, discarding the provided default value. option is typically ran at the "edge" of a flow, to provide default values for complicated representations of disjunction.

When the need to immediately map the result of optioning a Maybe arises, then either may be employed to combine it in one operation.

import Maybe from 'crocks/Maybe'

const { Nothing, Just } = Maybe

Nothing()
  .option(0)
//=> 0

Just(99)
  .option(0)
//=> 99

either

Maybe a ~> ((() -> b), (a -> b)) -> b

Used to provide a means to map a given Maybe instance while optioning out the wrapped value. option can handle most cases for optioning Maybe, but does not provide a means to map a given value at the time of optioning. either expects two functions as its arguments. The first is a pointed function that will be used when invoked on a Nothing. While the second will map the value wrapped in a given Just and return the result of that mapping.

import Maybe from 'crocks/Maybe'

import either from 'crocks/pointfree/either'

const { Nothing, Just } = Maybe

// wrap :: a -> [ a ]
const wrap =
  x => [ x ]

// empty :: () -> [ a ]
const empty =
  () => []

// toArray :: Maybe a -> [ a ]
const toArray =
  either(empty, wrap)

toArray(Just(56))
//=> [ 56 ]

toArray(Nothing())
//=> []

Helper Functions

find

crocks/Maybe/find

find :: Foldable f => ((a -> Boolean) | Pred) -> f a -> Maybe a

Using a provided predicate function or a Pred datatype, find takes a Foldable instance and executes for every value in the Foldable, skipping empty indexes. find then returns the first value it finds that passes the predicate. If found, find returns the value in a Just, otherwise a Nothing is returned.

import find from 'crocks/Maybe/find'
import Pred from 'crocks/Pred'
import isNumber from 'crocks/predicates/isNumber'

// isEven :: Number -> Boolean
const isEven =
  x => x % 2 === 0

// largeNumber :: Pred a
const largeNumber =
  Pred(isNumber)
    .concat(Pred(x => x > 100))

find(largeNumber, [ 10, '12', 150, 200, 2000 ])
//=> Just 150

find(largeNumber, [ 1, 2, 3, 4, 5 ])
//=> Nothing

find(isEven, [ 1, 2, 3, 4, 5 ])
//=> Just 2

getPath

crocks/Maybe/getPath

getPath :: [ (String | Integer) ] -> a -> Maybe b

While getProp is good for simple, single-level structures, there may come a time when you have to work with nested POJOs or Arrays. When you run into this situation, just pull in getPath (formally known as propPath) and pass it a left-to-right traversal path of keys, indices or a combination of both. This will kick you back a function that behaves just like getProp. You pass it some data, and it will attempt to resolve your provided path. If the path is valid, it will return the value residing there (null and NaN included!) in a Just. But, if at any point, that path "breaks", it will give you back a Nothing.

import composeK from 'crocks/helpers/composeK'
import isString from 'crocks/predicates/isString'
import getPath from 'crocks/Maybe/getPath'
import safe from 'crocks/Maybe/safe'

// getFirstValue :: a -> Maybe b
const getFirstValue =
  getPath([ 'value', 0 ])

// getStringFirst :: a -> Maybe String
const getStringFirst = composeK(
  safe(isString),
  getFirstValue
)

getFirstValue({ value: [] })
//=> Nothing

getFirstValue({ value: 84 })
//=> Nothing

getFirstValue(undefined)
//=> Nothing

getFirstValue({ value: [ 'a', 'b' ] })
//=> Just "a"

getStringFirst(false)
//=> Nothing

getStringFirst({ towel: true })
//=> Nothing

getStringFirst({ value: [ 0, 54 ] })
//=> Nothing

getStringFirst({ value: [ 'nice', 'jobb' ] })
//=> Just "nice"

getProp

crocks/Maybe/getProp

getProp :: (String | Integer) -> a -> Maybe b

If you want some safety around pulling a value out of an Object or Array with a single key or index, you can always reach for getProp, previously known as prop. Well, as long as you are working with non-nested data that is. Just tell getProp either the key or index you are interested in, and you will get back a function that will take anything and return a Just with the wrapped value if the key/index is defined. If the key/index is not defined, you will get back a Nothing.

import composeK from 'crocks/helpers/composeK'
import getProp from 'crocks/Maybe/getProp'

// getValue :: a -> Maybe b
const getValue =
  getProp('value')

// getHead :: a -> Maybe b
const getHead =
  getProp(0)

// getFirstValue :: a -> Maybe b
const getFirstValue = composeK(
  getHead,
  getValue
)

getValue({ some: false })
//=> Nothing

getValue(undefined)
//=> Nothing

getValue({ value: 'correct' })
//=> Just "correct"

getFirstValue({ value: [] })
//=> Nothing

getFirstValue({ value: 84 })
//=> Nothing

getFirstValue(null)
//=> Nothing

getFirstValue({ value: [ 'a', 'b' ] })
//=> Just "a"

safe

crocks/Maybe/safe

safe :: ((b -> Boolean) | Pred) -> b -> Maybe a

When using a Maybe, it is a common practice to lift into a Just or a Nothing depending on a condition on the value to be lifted. It is so common that it warrants a function, and that function is called safe. Provide a predicate (a function that returns a Boolean) or a Pred datatypea and the value to be lifted. The value will be evaluated against the predicate, and will lift it into a Just if true and a Nothing if false.

import Pred from 'crocks/Pred'

import isArray from 'crocks/predicates/isArray'
import safe from 'crocks/Maybe/safe'

// length :: Array -> Number
const length =
  x => x.length

// lte2 :: Number -> Boolean
const lte2 =
  x => x <= 2

// isSmall :: Pred a
const isSmall =
  Pred(isArray)
    .concat(Pred(lte2).contramap(length))

safe(lte2, 87)
//=> Nothing

safe(lte2, 1)
//=> Just 1

safe(isArray, {})
//=> Nothing

safe(isArray, [ 1, 2, 3 ])
//=> Just [ 1, 2, 3 ]

safe(isSmall, [ 1, 2, 3 ])
//=> Nothing

safe(isSmall, { ar: [ 1, 2, 3 ] })
//=> Nothing

safe(isSmall, null)
//=> Nothing

safe(isSmall, [ 1, 2 ])
//=> Just [ 1, 2 ]

safeAfter

crocks/Maybe/safeAfter

safeAfter :: ((b -> Boolean) | Pred) -> (a -> b) -> a -> Maybe b

Many times, you might want to lift the result of a function into a Maybe based on some predicate. This may be because some parts of our code might return unsafe values for further computations we may like to perform. Similar to safe, you pass either aPred or a predicate function, along with a unary function. safeAfter then gives you a new function, which when invoked evaluates the predicate against the result of executing the unary function. This result is then lifted into a Just if the predicate evaluates to true, or a Nothing if it returns false

import Pred from 'crocks/Pred'
import curry from 'crocks/helpers/curry'
import isDefined from 'crocks/predicates/isDefined'
import isNumber from 'crocks/predicates/isNumber'
import safeAfter from 'crocks/Maybe/safeAfter'

// prop :: String -> Object -> a | undefined
const prop = curry(
  (key, x) => x[key]
)

// divide :: Number -> Number -> Number
const divide = curry(
  (x, y) => x / y
)

// safeDivide :: Number -> Number -> Maybe FiniteNumber
const safeDivide = curry(
  x => safeAfter(isFinite, divide(x))
)

// isValid :: Pred a
const isValid =
  Pred(isDefined)
    .concat(Pred(isNumber))

// safePropNumber :: String -> Object -> Maybe Number
const validProp = curry(
  key => safeAfter(isValid, prop(key))
)

divide(3, 0)
//=> Infinity

safeDivide(3, 0)
//=> Nothing

divide(3, 1)
//=> 3

safeDivide(3, 1)
//=> Just 3

prop('a', { b: 32 })
//=> undefined

prop('a', { a: 'thirty-two' })
//=> 'thirty-two'

prop('a', { a: 32 })
//=> 32

validProp('a', { a: 'thirty-two' })
//=> Nothing

validProp('a', { b: 32 })
//=> Nothing

validProp('a', { a: 32 })
//=> Just 32

safeLift

crocks/Maybe/safeLift

safeLift :: ((c -> Boolean) | Pred) -> (a -> b) -> c -> Maybe b

While safe is used to lift a value into a Maybe, you can reach for safeLift when you want to run a function in the safety of the Maybe context. Just like safe, you pass it either a Pred or a predicate function to determine if you get a Just or a Nothing, but then instead of a value, you pass it a unary function. safeLift will then give you back a new function that will first lift its argument into a Maybe and then maps your original function over the result.

import Pred from 'crocks/Pred'

import isNumber from 'crocks/predicates/isNumber'
import safeLift from 'crocks/Maybe/safeLift'

// doubleOf :: Number -> Number
const doubleOf =
  x => x * 2

// halfOf :: Number -> Number
const halfOf =
  x => x / 2

// gt100 :: Number -> Boolean
const gt100 =
  x => x > 100

// safeDouble :: a -> Maybe Number
const safeDouble =
  safeLift(isNumber, doubleOf)

// isLargeNumber :: Pred a
const isLargeNumber =
  Pred(isNumber)
    .concat(Pred(gt100))

// halfLarge :: a -> Maybe Number
const halfLarge =
  safeLift(isLargeNumber, halfOf)

safeDouble(null)
// Nothing

safeDouble('33')
// Nothing

safeDouble(33)
// Just 66

halfLarge('1000')
// Nothing

halfLarge(100)
// Nothing

halfLarge(false)
// Nothing

halfLarge(786)
// Just 383

halfLarge(100)
// Nothing

halfLarge(false)
// Nothing

Transformation Functions

eitherToMaybe

crocks/Maybe/eitherToMaybe

eitherToMaybe :: Either b a -> Maybe a
eitherToMaybe :: (a -> Either c b) -> a -> Maybe b

Used to transform a given Either instance to a Maybe instance or flatten a Maybe of Either into a Maybe when chained, eitherToMaybe will turn a Right instance into a Just wrapping the original value contained in the Right. All Left instances will map to a Nothing, mapping the originally contained value to a Unit. Values on the Left will be lost and as such this transformation is considered lossy in that regard.

Like all crocks transformation functions, eitherToMaybe has two possible signatures and will behave differently when passed either an Either instance or a function that returns an instance of Either. When passed the instance, a transformed Maybe is returned. When passed an Either returning function, a function will be returned that takes a given value and returns a Maybe.

import Maybe from 'crocks/Maybe'

import Either from 'crocks/Either'

import eitherToMaybe from 'crocks/Maybe/eitherToMaybe'

import constant from 'crocks/combinators/constant'
import ifElse from 'crocks/logic/ifElse'
import isNumber from 'crocks/predicates/isNumber'

const { Nothing, Just } = Maybe

const { Left, Right } = Either

// someNumber :: a -> Either String Number
const someNumber = ifElse(
  isNumber,
  Right,
  constant(Left('Nope'))
)

eitherToMaybe(Left(56))
//=> Nothing

eitherToMaybe(Right('correct'))
//=> Just "correct"

Just('ten')
  .chain(eitherToMaybe(someNumber))
//=> Nothing

Nothing()
  .chain(eitherToMaybe(someNumber))
//=> Nothing

Just(99)
  .chain(eitherToMaybe(someNumber))
//=> Just 99

Just(Right(42))
  .chain(eitherToMaybe)
// Just 42

Just(Left(24))
  .chain(eitherToMaybe)
// Nothing

firstToMaybe

crocks/Maybe/firstToMaybe

firstToMaybe :: First a -> Maybe a
firstToMaybe :: (a -> First b) -> a -> Maybe b

Used to transform a given First instance to a Maybe instance or flatten a Maybe of First into a Maybe when chained, firstToMaybe will turn a non-empty instance into a Just wrapping the original value contained within the First. All empty instances will map to a Nothing.

Like all crocks transformation functions, firstToMaybe has two possible signatures and will behave differently when passed either a First instance or a function that returns an instance of First. When passed the instance, a transformed Maybe is returned. When passed a First returning function, a function will be returned that takes a given value and returns a Maybe.

import Maybe from 'crocks/Maybe'

import First from 'crocks/First'
import firstToMaybe from 'crocks/Maybe/firstToMaybe'

import mconcat from 'crocks/helpers/mconcat'

const { Nothing, Just } = Maybe

// firstValue :: [ a ] -> First a
const firstValue =
  mconcat(First)

firstToMaybe(First.empty())
//=> Nothing

firstToMaybe(First('winner'))
//=> Just "Winner"

Nothing()
  .chain(firstToMaybe(firstValue))
//=> Nothing

Just([])
  .chain(firstToMaybe(firstValue))
//=> Nothing

Just([ 'first', 'second', 'third' ])
  .chain(firstToMaybe(firstValue))
//=> Just "first"

Just(First('first'))
  .chain(firstToMaybe)
//=> Just "first"

Just(First.empty())
  .chain(firstToMaybe)
//=> Nothing

lastToMaybe

crocks/Maybe/lastToMaybe

lastToMaybe :: Last a -> Maybe a
lastToMaybe :: (a -> Last b) -> a -> Maybe b

Used to transform a given Last instance to a Maybe instance or flatten a Maybe of Last into a Maybe when chained, lastToMaybe will turn a non-empty instance into a Just wrapping the original value contained within the Last. All empty instances will map to aNothing.

Like all crocks transformation functions, lastToMaybe has two possible signatures and will behave differently when passed either a Last instance or a function that returns an instance of Last. When passed the instance, a transformed Maybe is returned. When passed a Last returning function, a function will be returned that takes a given value and returns a Maybe.

import Maybe from 'crocks/Maybe'

import Last from 'crocks/Last'
import lastToMaybe from 'crocks/Maybe/lastToMaybe'

import mconcat from 'crocks/helpers/mconcat'

const { Nothing, Just } = Maybe

// lastValue :: [ a ] -> Last a
const lastValue =
  mconcat(Last)

lastToMaybe(Last.empty())
//=> Nothing

lastToMaybe(Last('the end'))
//=> Just "the end"

Nothing()
  .chain(lastToMaybe(lastValue))
//=> Nothing

Just([])
  .chain(lastToMaybe(lastValue))
//=> Nothing

Just([ 'first', 'second', 'third' ])
  .chain(lastToMaybe(lastValue))
//=> Just "third"

Just(Last('last'))
  .chain(lastToMaybe)
//=> Just "last"

Just(Last.empty())
  .chain(lastToMaybe)
//=> Nothing

maybeToArray

crocks/Maybe/maybeToArray

maybeToArray :: Maybe a -> [ a ]
maybeToArray :: (a -> Maybe b) -> a -> [ b ]

Used to transform a given Maybe instance to an Array or flatten an Array of Maybe into an Array when chained, maybeToArray will turn a Just instance into a single element Array, wrapping the original value contained within the Just instance. All Nothing instances will map to an empty Array.

Like all crocks transformation functions, maybeToArray has two possible signatures and will behave differently when passed either a Maybe instance or a function that returns an instance of Maybe. When passed the instance, a transformed Array is returned. When passed a Maybe returning function, a function will be returned that takes a given value and returns an Array.

import Maybe from 'crocks/Maybe'

import chain from 'crocks/pointfree/chain'
import composeK from 'crocks/helpers/composeK'
import getProp from 'crocks/Maybe/getProp'
import isString from 'crocks/predicates/isString'
import safe from 'crocks/Maybe/safe'

import maybeToArray from 'crocks/Maybe/maybeToArray'

const { Nothing, Just } = Maybe

maybeToArray(Nothing())
//=> []

maybeToArray(Just(33))
//=> [ 33 ]

// flatten :: [ Maybe a ] -> [ a ]
const flatten =
  chain(maybeToArray)

flatten([ Just(33), Just('text') ])
//=> [ 33, 'text' ]

flatten([ Just('left'), Nothing(), Just('right') ])
//=> [ 'left', 'right' ]

// getUser :: a -> Maybe String
const getUser = composeK(
  safe(isString),
  getProp('user')
)

// getUsers :: [ * ] -> [ String ]
const getUsers =
  chain(maybeToArray(getUser))

// data :: [ * ]
const data = [
  { user: 'Allison' },
  'Ben',
  { user: 'Beth' },
  null,
  { user: 'Claire' }
]

getUsers(data)
//=> [ 'Allison', 'Beth', 'Claire' ]

resultToMaybe

crocks/Maybe/resultToMaybe

resultToMaybe :: Result e a -> Maybe a
resultToMaybe :: (a -> Result e b) -> a -> Maybe b

Used to transform a given Result instance to a Maybe instance or flatten a Maybe of Result into a Maybe when chained, resultToMaybe will turn an Ok instance into a Just wrapping the original value contained in the Ok. All Err instances will map to a Nothing, mapping the originally contained value to a Unit. Values on the Err will be lost and as such this transformation is considered lossy in that regard.

Like all crocks transformation functions, resultToMaybe has two possible signatures and will behave differently when passed either an Result instance or a function that returns an instance of Result. When passed the instance, a transformed Maybe is returned. When passed a Result returning function, a function will be returned that takes a given value and returns a Maybe.

import Maybe from 'crocks/Maybe'

import Result from 'crocks/Result'

import resultToMaybe from 'crocks/Maybe/resultToMaybe'

import identity from 'crocks/combinators/identity'
import tryCatch from 'crocks/Result/tryCatch'

const { Nothing, Just } = Maybe

const { Err, Ok } = Result

function datErrTho() {
  throw new Error('something amiss')
}

resultToMaybe(Err('this is bad'))
//=> Nothing

resultToMaybe(Ok('this is great'))
//=> Just "this is great"

Nothing()
  .chain(resultToMaybe(identity))
//=> Nothing

Just('so good')
  .chain(resultToMaybe(tryCatch(datErrTho)))
//=> Nothing

Just('so good')
  .chain(resultToMaybe(Ok))
//=> Just "so good"

Just(Result('in time!'))
  .chain(resultToMaybe)
//=> Just "in time!"

Just(Err('to be human'))
  .chain(resultToMaybe)
//=> Nothing

Contribute on Github! Edit this section.