Practical functional Javascript
I have been going through Ramda's source code as a learning exercise and don't understand the following:
Here is a simplified curry3 function
import _curry2 from './fns/_curry2' // copy of Ramda function import _curry3 from './fns/_curry3' // copy of Ramda function export function curry3(fn) { return function f3(a, b, c) { const argsLen = arguments.length log('curry3 argLen', argsLen) switch (argsLen) { case 0: return f3 case 1: return _curry2(function (_b, _c) { return fn(a, _b, _c) }) case 2: return _curry1(function (_c) { return fn(a, b, _c) }) case 3: return fn(a, b, c) } } }
Wrap a function in it
const c3 = curry3(function curryMe3(a, b, c) { return `curryMe3: ${a}, ${b}, ${c}` }) const c3 = curry3(function curryMe3(a, b, c) { return `curryMe3: ${a}, ${b}, ${c}` })
And call it
log('c3-0', c3()) // -> argLen 0 // -> c3 [Function: f3] log('c3-1', c3(1)) // -> argLen 1 // -> c3 [Function: f2] log('c3-2', c3(1, 2)) // -> argLen 2 // -> c3 [Function: f1] log('c3-3', c3(1, 2, 3)) // -> argLen 3 // -> c3 curryMe3: 1, 2, 3
So
c3 receives 1 argument as
fn. What I dont understand is how the arguments passed to
curryMe3 get into
f3 as 0, 1, 2 or 3 separate arguments.
How can I validate that a request is a JSON object? I did something like this:
const getTags = (request) => { if (isEmpty(request) || !is(Object, request)) { throw new TypeError( 'The #request is required and needs to be an JSON object' ) }
But then I realized that
is(Object, []) returns true
export const isNullOrEmpty = (request) => isNil(request) || isEmpty(request) /** * Check if the incoming request is either empty, null, or undefined and if it * is not a JSON object * * @param {*} request - incoming request * @returns {boolean} true when the request is either null, undefined, or empty, * and it is not a JSON object */ export const isEmptyOrNotJSONObject = (request) => isNullOrEmpty(request) || request.constructor !== Object
Hi there!
Got a function combination problem and was wondering if Ramda could help me write it in a point-free style.
Basically, I have 2 functions both which take the same input. One function returns a Promise which resolves to a string and the second function returns a string. I want to join the results of the two functions using
path.join.
I.e, non point-free:
const fn = obj => getString1(obj).then(s1 => path.join(s1, getString2(obj))
Using ramda's
join with a forward-slash instead of
path.join is acceptable. Is there a point-free way of combining these functions?
I thought perhaps
lift could help but I figure it out with the promise-returning function.
pipeWith(f, g, x)i can write
pipeWith(x, f, g) @theqp
:point_up: Edit: but you got the idea 🙂 @theqp
const tagger = curry((tag, text, template) => pipe( when( includes(tag), pipe( replace(tag, text), tagger(tag, text) ) ) )(template)) const applyTags = (tags, template) => pipe( toPairs, map(over(lensIndex(0), s => `{${s}}`)), reduce(pipe(append, apply(tagger)), template) )(tags) const tags = { test: 'tasty test', cheese: 'amazing smoked gouda' } const template = 'this is a {test}. I love {cheese}.' applyTags(tags, template) // "this is a tasty test. I love amazing smoked gouda."
const includedIn: <T>(list: T[]) => (item: T) => boolean = list => item => includes(item)(list)
Hi, I'm new to functional programming and Ramda. How might you improve these functions? Can any be made pointfree? Thank you!
// // elementAfter(el, list) returns the element after el in the list // (wapping to the beginning if needed) // how would you improve these functions? can any be made pointfree? // const indexAfter = (index, list) => mathMod(inc(index), length(list)) const indexAfterElement = (el, list) => indexAfter(indexOf(el, list), list) const elementAfter = (el, list) => nth(indexAfterElement(el, list), list) elementAfter('c', ['a', 'b', 'c']) // 'a'
Ramda REPL:
// This fails cause "reduce: list must be array or iterable" R.transduce(mapfilterComp, R.groupBy(R.prop('programId')), {}, settings)
// This is a function that returns a function with it's arguments re-arranged. // I'm not sure how useful it is, i just wanted to make one. // You specify the new argument order with an integer, with each digit from 1-9 // symbolising the original order. // for example, to switch the order of a binary function like divide, we use 21 // we're counting from 1. // swap(21, divide)(4,2) //--> 0.5 // // More complex now // swap(42133, foo)(these, are, some, args, wow) // equiv. to: foo(args, are, these, some, some) // Note you can repeat numbers to pass to the same value multiple times. // The function applies curryN to the result based on how many digits there are, // giving you partial application, of sorts. const swap = curry((n, f) => { const argMap = Array.from(n.toString()).map(x => parseInt(x) - 1) return curryN(argMap.length, (...args) => f( ...addIndex(map)((a, i) => { const newPos = argMap.indexOf(i) return newPos !== -1 ? args[newPos] : a }, args) ) ) })
Hi, I have the following code that is returning true when it should return false:
const isNotEmpty = R.complement(R.isEmpty) const isNotNil = R.complement(R.isNil) const isNotEmptyFeed = R.and(R.pathSatisfies(isNotEmpty, ['data', 'children']), isNotNil) isNotEmptyFeed({ subreddit: 'abruptchaos', feedCategory: 'posts_Default', feedUrl: '', data: { children: [] }, })
Can anyone tell me where I've gone wrong here?
data.children is empty, so that should be false right?