First

First a = First (Maybe a)

First is a Monoid that will always return the first, non-empty value when two First instances are combined. First is able to be a Monoid because it implements a Maybe under the hood. The use of the Maybe allows for an empty First to be represented with a Nothing.

First can be constructed with either a value or a Maybe instance. Any value passed to the constructor will be wrapped in a Just to represent a non-empty instance of First. Any Maybe passed to the constructor will be lifted as is, allowing the ability to "choose" a value based on some disjunction.

While most Monoids only provide a valueOf function used for extraction, First takes advantage of its underlying Maybe to provide an additional option method. Using valueOf will extract the underlying Maybe, while option will extract the underlying value in the Maybe, using the provided default value when the underlying Maybe is a Nothing instance.

import First from 'crocks/First'
import and from 'crocks/logic/and'
import isNumber from 'crocks/predicates/isNumber'
import mconcatMap from 'crocks/helpers/mconcatMap'
import safe from 'crocks/Maybe/safe'
// isEven :: Number -> Boolean
const isEven =
x => !(x % 2)
// isValid :: a -> Boolean
const isValid =
and(isNumber, isEven)
// chooseFirst :: [ * ] -> First Number
const chooseFirst =
mconcatMap(First, safe(isValid))
chooseFirst([ 21, 45, 2, 22, 19 ])
.valueOf()
//=> Just 2
chooseFirst([ 'a', 'b', 'c' ])
.option('')
//=> ""

Implements#

Setoid, Semigroup, Monoid

Construction#

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

A First instance can be constructed by passing either a direct (unwrapped) value a or a Maybe a to the constructor. When a direct value is passed, the constructor will always wrap the value in a Just and return a new First Just a instance.

Alternatively, by passing a Maybe a, the user can programmatically provide an empty case to a given First by passing a Nothing.

import First from 'crocks/First'
import Maybe from 'crocks/Maybe'
const { Just, Nothing } = Maybe
First(Just(22))
//=> First( Just 22 )
First(Nothing())
//=> First( Nothing )
First(undefined)
//=> First( Just undefined )
First('string')
//=> First( Just "string" )

Constructor Methods#

empty#

First.empty :: () -> First a

empty provides the identity for the Monoid in that when the value it provides is concated to any other value, it will return the other value. In the case of First the result of empty is Nothing. empty is available on both the Constructor and the Instance for convenience.

import First from 'crocks/First'
const { empty } = First
First.empty()
//=> First( Nothing )
First(3)
.concat(empty())
//=> First( Just 3 )
empty()
.concat(First(3))
//=> First( Just 3 )

Instance Methods#

equals#

First a ~> b -> Boolean

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

import First from 'crocks/First'
import Maybe from 'crocks/Maybe'
First(33)
.equals(First(33))
//=> true
First(42)
.equals(First(10))
//=> false
First({ a: 5 })
.equals({ a: 5 })
//=> false
First(95)
.equals(95)
//=> false
First(95)
.equals(Maybe.of(95))
//=> false

concat#

First a ~> First a -> First a

concat is used to combine two Semigroups of the same type under an operation specified by the Semigroup. In the case of First, it will always provide the first non-empty value. Any subsequent non-empty values will be thrown away and will always result in the first non-empty value.

import First from 'crocks/First'
import concat from 'crocks/pointfree/concat'
const a = First('a')
const b = First('b')
const c = First('c')
a.concat(b)
//=> First( Just "a" )
b.concat(a)
//=> First( Just "b" )
concat(c, concat(b, a))
//=> First( Just "a" )
concat(concat(c, b), a)
//=> First( Just "a" )
concat(concat(a, b), c)
//=> First( Just "c" )

option#

First a ~> a -> a

First wraps an underlying Maybe which provides the ability to option out a value in the case of an empty instance. Just like option on a Maybe instance, it takes a value as its argument. When run on an empty instance, the provided default will be returned. If option is run on a non-empty instance however, the wrapped value will be extracted not only from the First but also from the underlying Just.

If the underlying Maybe is desired, the valueOf method can be used and will return the Maybe instead.

import First from 'crocks/First'
import compose from 'crocks/helpers/compose'
import chain from 'crocks/pointfree/chain'
import getProp from 'crocks/Maybe/getProp'
import isString from 'crocks/predicates/isString'
import mconcatMap from 'crocks/helpers/mconcatMap'
import safe from 'crocks/Maybe/safe'
// stringVal :: a -> Maybe String
const stringVal = compose(
chain(safe(isString)),
getProp('val')
)
// firstValid :: [ a ] -> First String
const firstValid =
mconcatMap(First, stringVal)
// good :: [ Object ]
const good =
[ { val: 23 }, { val: 'string' }, { val: '23' } ]
// bad :: [ Object ]
const bad =
[ { val: 23 }, { val: null }, {} ]
firstValid(good)
.option('')
//=> "string"
firstValid(bad)
.option('')
//=> ""

valueOf#

First a ~> () -> Maybe a

valueOf is used on all crocks Monoids as a means of extraction. While the extraction is available, types that implement valueOf are not necessarily a Comonad. This function is used primarily for convenience for some of the helper functions that ship with crocks. Calling valueOf on a First instance will result in the underlying Maybe.

import First from 'crocks/First'
import Maybe from 'crocks/Maybe'
import valueOf from 'crocks/pointfree/valueOf'
const { Nothing } = Maybe
valueOf(First(56))
//=> Just 56
valueOf(First.empty())
//=> Nothing
First(37)
.concat(First(99))
.valueOf()
//=> Just 37
First(Nothing())
.concat(First.empty())
.valueOf()
//=> Nothing

Transformation Functions#

eitherToFirst#

crocks/First/eitherToFirst

eitherToFirst :: Either b a -> First a
eitherToFirst :: (a -> Either c b) -> a -> First b

Used to transform a given Either instance to a First instance, eitherToFirst will turn a Right instance into a non-empty First, wrapping the original value contained in the Right. All Left instances will map to an empty First, 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, eitherToFirst 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 First is returned. When passed an Either returning function, a function will be returned that takes a given value and returns a First.

import First from 'crocks/First'
import Either from 'crocks/Either'
import eitherToFirst from 'crocks/First/eitherToFirst'
import concat from 'crocks/pointfree/concat'
import constant from 'crocks/combinators/constant'
import flip from 'crocks/combinators/flip'
import ifElse from 'crocks/logic/ifElse'
import isNumber from 'crocks/predicates/isNumber'
import mapReduce from 'crocks/helpers/mapReduce'
const { Left, Right } = Either
// someNumber :: a -> Either String Number
const someNumber = ifElse(
isNumber,
Right,
constant(Left('Nope'))
)
// firstNumber :: [ a ] -> First Number
const firstNumber = mapReduce(
eitherToFirst(someNumber),
flip(concat),
First.empty()
)
// "Bad Times" is lost, mapped to Nothing
eitherToFirst(Left('Bad Times'))
//=> First( Nothing )
eitherToFirst(Right('correct'))
//=> First( Just "correct" )
firstNumber([ 'string', null, 34, 76 ])
//=> First( Just 34 )
firstNumber([ 'string', null, true ])
//=> First( Nothing )

lastToFirst#

crocks/First/lastToFirst

lastToFirst :: Last a -> First a
lastToFirst :: (a -> Last b) -> a -> First b

Used to transform a given Last instance to a First instance, lastToFirst will turn a non-empty instance into a non-empty First wrapping the original value contained within the Last. All empty instances will map to an empty First.

Like all crocks transformation functions, lastToFirst 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 First is returned. When passed a Last returning function, a function will be returned that takes a given value and returns a First.

import First from 'crocks/First'
import Last from 'crocks/Last'
import lastToFirst from 'crocks/First/lastToFirst'
import isString from 'crocks/predicates/isString'
import mconcatMap from 'crocks/helpers/mconcatMap'
import safe from 'crocks/Maybe/safe'
// lastString :: [ a ] -> Last String
const lastString =
mconcatMap(Last, safe(isString))
// fixLastString :: [ a ] -> First String
const fixLastString =
lastToFirst(lastString)
lastToFirst(Last.empty())
//=> First( Nothing )
lastToFirst(Last(false))
//=> First( Just false )
fixLastString([ 'one', 2, 'Three', 4 ])
.concat(First('another string'))
//=> First( Just "Three" )
fixLastString([ 1, 2, 3, 4 ])
.concat(First('First String'))
//=> First( Just "First String" )

maybeToFirst#

crocks/First/maybeToFirst

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

Used to transform a given Maybe instance to a First instance, maybeToFirst will turn a Just into a non-empty First instance, wrapping the original value contained within the First. All Nothing instances will map to an empty First instance.

This function is available mostly for completion sake, as First can always take a Maybe as its argument during construction. So while there is not a real need for this to be used for transforming instances, it can come in handy for lifting Maybe returning functions.

Like all crocks transformation functions, maybeToFirst 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 First is returned. When passed a Maybe returning function, a function will be returned that takes a given value and returns a First.

import First from 'crocks/First'
import Maybe from 'crocks/Maybe'
import maybeToFirst from 'crocks/First/maybeToFirst'
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 safe from 'crocks/Maybe/safe'
const { Nothing, Just } = Maybe
// numVal :: a -> Maybe Number
const numVal = compose(
chain(safe(isNumber)),
getProp('val')
)
// firstNumVal :: a -> First Number
const firstNumVal =
maybeToFirst(numVal)
maybeToFirst(Just(99))
//=> First( Just 99 )
maybeToFirst(Nothing())
//=> First( Nothing )
First(Just(99))
//=> First( Just 99 )
First(Nothing())
//=> First( Nothing )
firstNumVal({ val: 97 })
.concat(First(80))
//=> First( Just 97 )
firstNumVal({ val: '97' })
.concat(First(80))
//=> First( Just 80 )
firstNumVal(null)
.concat(First(80))
//=> First( Just 80 )

resultToFirst#

crocks/First/resultToFirst

resultToFirst :: Result e a -> First a
resultToFirst :: (a -> Result e b) -> a -> First b

Used to transform a given Result instance to a First instance, resultToFirst will turn an Ok instance into a non-empty First, wrapping the original value contained in the Ok. All Err instances will map to an empty First, 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, resultToFirst 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 First is returned. When passed a Result returning function, a function will be returned that takes a given value and returns a First.

import First from 'crocks/First'
import Result from 'crocks/Result'
import resultToFirst from 'crocks/First/resultToFirst'
import isNumber from 'crocks/predicates/isNumber'
import tryCatch from 'crocks/Result/tryCatch'
const { Err, Ok } = Result
function onlyNums(x) {
if(!isNumber(x)) {
throw new Error('something amiss')
}
return x
}
// firstNum :: a -> First Number
const firstNum =
resultToFirst(tryCatch(onlyNums))
// "this is bad" is lost, mapped to Nothing
resultToFirst(Err('this is bad'))
//=> First( Nothing )
resultToFirst(Ok('this is great'))
//=> First( Just "this is great" )
firstNum(90)
.concat(First(0))
//=> First( Just 90 )
firstNum(null)
.concat(First(0))
//=> First( Just 0 )