ravr

Project Url: RedNifre/ravr
More: Author   ReportBugs   
Tags:

ravr logo

This is a partial port of the Ramda.js functional programming library to work with vavr types.

v0.0.11 (experimental, incomplete)

Maven

It's not on Maven Central yet, but you can find it in JCenter. First, add JCenter to the repositories in your pom:

    <repositories>
        <repository>
            <id>jcenter</id>
            <url>http://jcenter.bintray.com </url>
        </repository>
    </repositories>

Then you can import it as usual:

    <dependencies>
        <dependency>
            <groupId>de.michaelzinn.ravr</groupId>
            <artifactId>ravr</artifactId>
            <version>0.0.11</version>
        </dependency>
    </dependencies>

Gradle

compile 'de.michaelzinn.ravr:ravr:0.0.11'

Curried functions & partial function application

Ravr provides two ways to do partial application: Either leave out parameters at the end or use a parameter placeholder:


// All the same
List.of(1, 2, 3).map(x -> add(2, x));
List.of(1, 2, 3).map(add(2, __)); // works but isn't idiomatic
List.of(1, 2, 3).map(add(2)); // use this one instead
// => [3, 4, 5]

// The placeholder should only be used when necessary.
List.of(7, 8, 9).map(subtract(__, 2));
// => [5, 6, 7]

Function composition

You can compose functions in two ways.

Compose

Similar to mathematical composition. This is a vararg function.


// classic Java
map(add(1).compose(multiply(2)).compose(subtract(__, 1)), List(2, 3, 4));
// => [3, 5, 7]

// Ravr style
map(compose(add(1), multiply(2), subtract(__, 1)), List(1, 2, 3));
// => [3, 5, 7]

Pipe

Same as compose, but with the order inverted. This can be more readable when putting functions on separate lines.


List<String> words = List.of("xSIHTx", "xSIx", "xGNITSERETNIx");

assertThat(
    join("... ", words.map(pipe(
        Ravr::reverse,
        Ravr::toLower,
        Ravr::init,
        Ravr::tail
    ))),
    is("this... is... interesting")
);

Functor, Applicative, Monad

Ravr provides map, ap, and flatMap.

Pattern Standard name Ramda name Ravr name Type signature
Functor map map map Functor m => (a -> b) -> m a -> m b
Applicative apply ap ap Applicative m => m (a -> b) -> m a -> m b
Monad bind chain flatMap Monad m => (a -> m b) -> m a -> m b

Due to limits in Java's type system these currently only work on Lists, Options, Traversables and Futures.

Lenses (experimental)

Lenses only work on types that implement the included Copyable interface, which is a simplified version of the Cloneable interface. The simplest way to implement it is wrapping the clone function:

@Getters // lombok
@Setters // lombok
@AllArgsConstructor // lombok
class Thing implements Copyable<Thing> {
    String name;
    int quality;

    @Override
        public Thing copy() {
            return safeClone(() -> clone());
        }
}

Note: Your IDE might tell you to replace the lambda with a method reference. This might not work because of reasons.

You can create a lens using a pair of getters and setters. You can use the lens in combination with get, set and over:

Lens<Thing, String> name = lens(Thing::getName, Thing::setName);
Lens<Thing, Integer> quality = lens(Thing::getQuality, Thing::setQuality);

Thing lookingGlass = new Thing("looking glass", 5);

get(name, lookingGlass); // "looking glass"

Function1<Thing, Thing>
improve = pipe(
    set(name, "ten times better"),
    over(quality, multiply(10))
);

Thing betterThing = improve.apply(lookingGlass);

get(quality, betterThing); // 50
get(quality, lookingGlass); // 5 (not changed)

Other functions

You can concatenate the content of a List\> to List\ with the concatOptions function.

List<String> strings = List(">>>>", "", "====");

pipe(
    head(),    // List.of(Option.some(">"), Option.none(), Option.some("="))
    concatOptions(),    // List.of(">", "=")
    join(">")    // ">>="
).apply(strings);

What's included

Icon Meaning
:white_check_mark: Works
:neutral_face: Works with issues
Not implemented
:heavy_multiplication_x: Not planned
:diamond_shape_with_a_dot_inside: Bonus function not originally included in Ramda.js

This list is generated automatically and slightly inaccurate right now.

Status Function Note
:white_check_mark: add
addIndex
:white_check_mark: adjust
:white_check_mark: all
allPass
:white_check_mark: always
and
:white_check_mark: any
anyPass
:white_check_mark: ap
aperture
:white_check_mark: append
:white_check_mark: apply
applySpec
:white_check_mark: ap_List
:white_check_mark: ap_Option
:white_check_mark: apᐸListᐳ
:white_check_mark: apᐸOptionᐳ
ascend
assoc
:heavy_multiplication_x: assocPath
binary
bind
both
call
chain
clamp
:heavy_multiplication_x: clone
comparator
:white_check_mark: complement
compose
composeK
composeP
:white_check_mark: concat
:diamond_shape_with_a_dot_inside: concatOptions
cond
construct
constructN
:white_check_mark: contains
converge
:diamond_shape_with_a_dot_inside: count
countBy
curry
curryN
:white_check_mark: dec
:white_check_mark: defaultTo
descend
difference
differenceWith
dissoc
dissocPath
divide
drop
dropLast
dropLastWhile
dropRepeats
dropRepeatsWith
dropWhile
either
empty
endsWith
:white_check_mark: eq
eqBy
eqProps
equals
evolve
F
:white_check_mark: filter
find
:white_check_mark: findIndex
findLast
findLastIndex
:white_check_mark: flatMap
:white_check_mark: flatMap_List
:white_check_mark: flatMap_Option
:white_check_mark: flatMapᐸListᐳ
:white_check_mark: flatMapᐸOptionᐳ
flatten
flip
:white_check_mark: forEach
forEachObjIndexed
fromPairs
:white_check_mark: get
:white_check_mark: groupBy
groupWith
gt
gte
has
hasIn
:white_check_mark: head
:white_check_mark: head_String
:white_check_mark: headᐸStringᐳ
identical
:white_check_mark: identity
:white_check_mark: ifElse
:white_check_mark: inc
indexBy
indexOf
init
innerJoin
insert
insertAll
intersection
intersectionWith
intersperse
into
invert
invertObj
invoker
is
isEmpty
isNil
:white_check_mark: isNone Replacement for isNil, returns true for Option.none().
:white_check_mark: isSome Replacement for complement(isNil), returns true for Option.some("whatever").
:white_check_mark: join
:diamond_shape_with_a_dot_inside: joinOption Like join, except that it returns nothing when joining empty lists.
juxt
keys
keysIn
last
lastIndexOf
length
:white_check_mark: lens
lensIndex
lensPath
lensProp
lift
liftN
lt
lte
:white_check_mark: map
mapAccum
mapAccumRight
:diamond_shape_with_a_dot_inside: mapLeft Maps the left side of an Either
:diamond_shape_with_a_dot_inside: mapLeft_Either
:diamond_shape_with_a_dot_inside: mapLeftᐸEitherᐳ
mapObjIndexed
:white_check_mark: map_Either
:white_check_mark: map_List
:white_check_mark: map_Option
:white_check_mark: mapᐸEitherᐳ
:white_check_mark: mapᐸListᐳ
:white_check_mark: mapᐸOptionᐳ
match
mathMod
max
maxBy
mean
median
memoize
memoizeWith
merge
mergeAll
mergeDeepLeft
mergeDeepRight
mergeDeepWith
mergeDeepWithKey
mergeWith
mergeWithKey
min
minBy
modulo
multiply
nAry
negate
:white_check_mark: none
:white_check_mark: not
nth
nthArg
:white_check_mark: nullTo
o
objOf
of
omit
once
or
:white_check_mark: over
pair
partial
partialRight
partition
path
pathEq
pathOr
pathSatisfies
pick
pickAll
pickBy
pipe
pipeK
pipeP
pluck
:white_check_mark: prepend
product
project
prop
propEq
propIs
propOr
props
propSatisfies
:white_check_mark: range
:diamond_shape_with_a_dot_inside: rangeC Closed range
reduce
reduceBy
reduced
reduceRight
reduceWhile
reject
remove
:neutral_face: repeat Can't be curried.
replace
:white_check_mark: reverse
scan
sequence
:white_check_mark: set
slice
sort
:white_check_mark: sortBy
sortWith
split
splitAt
splitEvery
splitWhen
startsWith
subtract
sum
symmetricDifference
symmetricDifferenceWith
T
:white_check_mark: tail
take
takeLast
takeLastWhile
takeWhile
tap
test
times
:white_check_mark: toLower
toPairs
toPairsIn
toString
:white_check_mark: toUpper
transduce
transpose
traverse
trim
tryCatch
:heavy_multiplication_x: type
unapply
unary
uncurryN
unfold
union
unionWith
uniq
uniqBy
uniqWith
unless
unnest
until
update
useWith
values
valuesIn
view
when
where
whereEq
:white_check_mark: without
xprod
:white_check_mark: zip
zipObj
:white_check_mark: zipWith
_isArrayLike

Future plans

Other Ramda functions will be added as needed.

Contributing

The scope of this library is to port Ramda. Extra functions like concatOptions should be the exception. Contact me on Twitter.

Licensed under the LGPL v3, see the LICENSE file for details.

Apps
About Me
GitHub: Trinea
Facebook: Dev Tools