Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
  • Jan 31 2019 22:17
    CrossEye commented #2779
  • Jan 31 2019 21:04
    ArturAralin commented #2779
  • Jan 31 2019 20:08
    CrossEye commented #2779
  • Jan 31 2019 18:56
    buzzdecafe commented #2631
  • Jan 31 2019 18:09
    ArturAralin commented #2779
  • Jan 31 2019 16:18
    CrossEye commented #2779
  • Jan 31 2019 16:10
    CrossEye commented #2631
  • Jan 31 2019 16:06
    CrossEye commented #2777
  • Jan 31 2019 14:44
    ArturAralin opened #2779
  • Jan 31 2019 07:39
    inferusvv commented #2631
  • Jan 31 2019 03:07
    sespinozj commented #2771
  • Jan 31 2019 02:33
    machad0 commented #2771
  • Jan 31 2019 02:26
    JeffreyChan commented #2777
  • Jan 30 2019 14:30
    CrossEye closed #2777
  • Jan 30 2019 12:13
    vanyadymousky updated the wiki
  • Jan 30 2019 01:42
    JeffreyChan commented #2777
  • Jan 29 2019 21:06
    vanyadymousky updated the wiki
  • Jan 29 2019 16:28
    CrossEye commented #2777
  • Jan 29 2019 15:50
    mbostock commented #2772
  • Jan 29 2019 15:48
    CrossEye commented #2772
woss ( Daniel Maricic )
@woss:matrix.org
[m]

i don't think so. maybe you can use R.reverse for the arguments

const pipeWhileNotNil = R.pipeWith((f, res) => R.isNil(res) ? res : f(res));
const f = pipeWhileNotNil(R.reverse[Math.pow, R.negate, R.inc])

Note this code is only for demo, prob it will not work @theqp

woss ( Daniel Maricic )
@woss:matrix.org
[m]

:point_up: Edit: i don't think so. maybe you can use R.reverse for the arguments

const pipeWhileNotNil = R.pipeWith((f, res) => R.isNil(res) ? res : f(res));
const f = pipeWhileNotNil(R.reverse[Math.pow, R.negate, R.inc])

Note this code is only for demo, prob it will not work but you got the idea 🙂 @theqp

Narley Brittes
@narley
Hey folks, I friend of mine released a new javascript repl (https://github.com/tim-crisp/javascript.lol). I know this is not a ramda topic, but the guy is a ramda addicted and this project came out as a away for him to quickly prototype with ramda.
Tim
@tim-crisp
Hi all, I wasn't aware of this community until @narley told me about it, seems like a really awesome place to talk ramda.
I've put the solution @nfantone provided to the question @JamesRamm asked into a javascript.lol REPL to demonstrate it. Feel free to have a look and if you have any feedback raise an issue on the github repo!
woss ( Daniel Maricic )
@woss:matrix.org
[m]
hi @tim-crisp i can't find the source code 🙂 i'd love to see how you built this
Tim
@tim-crisp
Hi @woss:matrix.org I'm not releasing the source code just yet. I'd like to see how the community responds to the app first and in all honesty it needs a bit of a tidy up before it deserves to go public! When the day comes and I decide to release it, the source will be hosted on the github repo that @narley mentioned. Thanks for showing interest, watch this space 😉
woss ( Daniel Maricic )
@woss:matrix.org
[m]
cool. what cought my eye is the dynamic loading of the packages. do you mind a DM?
Tim
@tim-crisp
https://skypack.dev is the magic behind that
woss ( Daniel Maricic )
@woss:matrix.org
[m]
yeah, saw that. it's brilliant
that might actually solve my problem. 😀
Tim
@tim-crisp
In all honesty mate it does all the hard work, I'd highly recommend it
woss ( Daniel Maricic )
@woss:matrix.org
[m]
on this link there is plenty of ramda code for recursive execution and loading. although this works only on node but YES now i can do it in browser https://github.com/anagolay/js-sdk/blob/main/sdk/core/src/executeOperation.ts#L42
Tim
@tim-crisp
Nice. I'm loving some of the comments in that repo :joy:
Charles Hughes
@chughes87
kind of proud of this little tool I made last night:
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."
4 replies
sd
@sdebaun
stupid question. includes is T => T[] => boolean. Is there an equivalent function in ramda that is T[] => T => boolean?
i just add my own:
const includedIn: <T>(list: T[]) => (item: T) => boolean =
    list => item => includes(item)(list)
i just want to make sure that i'm not doing something that ramda already supports that i just cant find in the docs XD
1 reply
Mike Vosseller
@mpv_twitter

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: https://tinyurl.com/yhwpgykj

11 replies
Joshua Travis
@jktravis
Hi! I'm wanting to use a transducer to do a filter, map on a data set and then join then via effectively a groupBy. While I can write my own joiner, I'd like to know if there's a way that I can use the Ramda groupBy instead.
// This fails cause "reduce: list must be array or iterable"
R.transduce(mapfilterComp, R.groupBy(R.prop('programId')), {}, settings)
4 replies
QP
@theqp
@mpv_twitter I could improve indexAfter
https://tinyurl.com/yhkxl5u5
QP
@theqp
@mpv_twitter I could do it even more with reader monad
QP
@theqp
I made it point free with the help of pointfree.io
image.png
QP
@theqp
I made it 100% point free but I couldn't read it lol
https://tinyurl.com/yfpvf2cu
QP
@theqp
i just noticed someone solved it, also there is reader monad in ramda
https://tinyurl.com/ydst7myu
Mike Vosseller
@mpv_twitter
@theqp Thank you!
Andy Mac
@zxol

// 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)
    )
  )
})
Coop
@CoopCoding_twitter

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: 'https://www.reddit.com/r/abruptchaos/.json?limit=100&count=100&after=null',
  data: { children: [] },
})

https://tinyurl.com/ydmqb9ls
Can anyone tell me where I've gone wrong here? data.children is empty, so that should be false right?

Andy Mac
@zxol
@CoopCoding_twitter Try both instead of and
Coop
@CoopCoding_twitter
Thanks, that works.
Andy Mac
@zxol
When you're having trouble like this, check the function signature in the docs to make sure the types match up.
Akira Cai
@blackwindforce

Hi there, does the following combinator have a name? Or, on the other hand, how we usually deal this pattern instead of composing with the combinator? For example:

// ???
const combinator = R.curry((f, g, x, y) => f (  g(x)  )  (  y  )  )

// findById :: ((Record K V -> Boolean) -> [Record K V] -> Maybe Record K V) -> (V -> Record K V -> Boolean) -> V -> [Record K V] -> Maybe Record K V
const findById = combinator(R.find, R.propEq("id"))

findById(1)([{id: 1}])
//> {id: 1}

I know the combinator can be derived from the following 2 functions, where g is identity.
https://github.com/ramda/ramda/blob/ed191e6a476330e37db259a5c2d04bfba0b2d63d/source/useWith.js#L21
https://github.com/fantasyland/fantasy-birds/blob/6f37c6e7daf31f1c31860f0f307555f4c7922ec2/src/dovekie.js#L4

But, is there a more elegant way to deal with it? Any suggestions or perspectives are welcome.

Andy Mac
@zxol
Akira Cai
@blackwindforce

@zxol Thank you, it is exactly the same beta-reduction as mine. And then my following question comes up:
If the function is variadic, then I need a I** combinator to achieve the same functionality, does it make sense?

const idstarstar = R.curry((f, x, y) => f(x)(y))

// right associative
// findById :: (Pred -> [a] -> Maybe a) -> (v -> Pred) -> v -> ([a] -> Maybe a)
const findById = R.compose(R.find, R.propEq("id"))

idstarstar(findById)(1, [{id: 1}])

https://github.com/fantasyland/fantasy-birds/blob/6f37c6e7daf31f1c31860f0f307555f4c7922ec2/src/idstarstar.js#L4
I think the problem is that f(g(x)) returns another function, so I can not give 2 arguments at once and apply to v -> ([a] -> Maybe a).
Is there a more elegant way to deal with it? Any suggestions or perspectives are welcome.

Andy Mac
@zxol
@blackwindforce i don't know of any combinator in the ramda lib, unfortunately. Perhaps the best thing to do is try to structure your program's API so the functor you're operating on is always at the end of a function call on it's own like you used in the first example. Or do the useWith identity trick. Perhaps someone else has a neat answer for you
Akira Cai
@blackwindforce
@zxol Thank you, that make sense to me.
Mike Vosseller
@mpv_twitter

Hi, I'm creating a simple tic-tac-toe style game and game state is stored in a game object.

I've noticed two problems:
1- most of my functions need access to the game object so I need to repeatedly pass it down.
2- because of #1 when I try to compose with a pipeline I often need to curry some functions with the game object.

Both seem like code smells. Is this typical? Any advice to improve?

(This code uses folktale Result)

import {
  pipeWith,
  chain,
  curry,
  add,
  multiply,
  update,
  evolve,
} from "ramda";
import folktale from "folktale";
const { result: Result } = folktale;

const createGame = ({ width, height } = {}) => ({
  size: {
    width,
    height,
  },
  grid: Array(width * height), // game is a grid but stored as a flat array
  // additional game state goes here
});

//
// 1) most of my functions need access to the game object so I'm repeatedly passing it down. is this typical?
//
const gridIndex = (game, pos) => add(pos[0], multiply(pos[1], game.size.width));
const cell = (game, pos) => game.grid[gridIndex(game, pos)];
const updateCell = (game, pos, val) =>
  evolve({
    grid: (g) => update(gridIndex(game, pos), val, g),
  })(game);

// two contrived validators that don't require the game object
const validateColGte0 = (pos) =>
  pos[0] >= 0 ? Result.Ok(pos) : Result.Error(`col must be >= 0: ${pos[0]}`);
const validateRowGte0 = (pos) =>
  pos[1] >= 0 ? Result.Ok(pos) : Result.Error(`row must be >= 0: ${pos[1]}`);
// three validators that need the game object
const validateColLtWidth = curry((game, pos) =>
  pos[0] < game.size.width
    ? Result.Ok(pos)
    : Result.Error(`col must be < ${game.size.width}: ${pos[0]}`)
);
const validateRowLtHeight = curry((game, pos) =>
  pos[1] < game.size.height
    ? Result.Ok(pos)
    : Result.Error(`row must be < ${game.size.height}: ${pos[1]}`)
);
const validateCellIsEmpty = curry((game, pos) =>
  !cell(game, pos)
    ? Result.Ok(pos)
    : Result.Error(`position is not empty: ${pos}`)
);
//
// 2) To compose functions in a pipline I need to curry them with the game object
//    would it be better to make the validator signatures take a single object 
//    with all possible paramaters? e.g. { game, pos }
//
const validatePosition = (game, pos) =>
  pipeWith(chain)([
    validateColGte0,
    validateRowGte0,
    validateColLtWidth(game),
    validateRowLtHeight(game),
    validateCellIsEmpty(game),
  ])(pos);
const performMove = (game, pos, val) =>
  validatePosition(game, pos).matchWith({
    Ok: ({ value: validatedPosition }) =>
      updateCell(game, validatedPosition, val),
    Error: ({ value: error }) => {
      console.log(error);
      return game;
    },
  });

// create and run the game
let game = createGame({ width: 3, height: 3 });
console.log(game);
game = performMove(game, [1, 1], "X"); // works
console.log(game);
game = performMove(game, [1, 1], "O"); // position is not empty: 1,1
console.log(game);
6 replies
Charles Hughes
@chughes87
Is there a more elegant way to do this?
compose(join(''), converge(Array, [getDateTitle, always('\n\n'), getBodyWithoutMarkup])
4 replies
QP
@theqp
any developer for @types/ramda here?
1 reply
I have made a more accurate cond type definition but I don't want to download the whole @types repo
export function cond<A, B>(fns: Array<[SafePred<A>, (...a: readonly A[]) => B]>): (...a: readonly A[]) => B | undefined;
export function cond<A, B>(
    fns: [
      ...[SafePred<A>, (...a: readonly A[]) => B],
      [(...a: readonly A[]) => true, (...a: readonly A[]) => B],
      ...[SafePred<A>, (...a: readonly A[]) => B]
    ]
  ): (...a: readonly A[]) => B;
also the one with any makes no sense to me, B can be any
Mike Vosseller
@mpv_twitter

Looks like Ramda doesn't include implementations of the various Fantasy Land "algebraic structures" like
Result, Either, Maybe, State, Reader, Future

Do folks typically just use the libraries listed on the Fantasy Land website here:
https://github.com/fantasyland/fantasy-land/blob/master/implementations.md

So If I wanted all of the above structures maybe I'd include and use:

Folktale: Result, Future
Sanctuary: Either, Maybe
Monastic: State
Zion: Reader

Just want to make sure there is no obvious single library that I should be using.

Thanks!

6 replies
Nils Riedemann
@nocksock

I'm sure there's a more elegant way to write this:

const seq = list => fns => r.call(r.apply(r.pipe, fns), list);

Still trying to wrap my head around currying, composing, piping etc.

wangzengdi
@adispring
@nocksock You can use R.pipeWith(R.identity) to do almost the same thing, but I think writing simple and readable code is more important than pursuing for point-free/curry code.
more readable version :)
const seq = R.curry((list, fns) => R.pipe(...fns)(list))
Nils Riedemann
@nocksock

writing simple and readable code is more important than pursuing for point-free/curry code.

@adispring Absolutely! However in my case it's just about embracing the pointfree style to fully grok it. This is just for a small utility package in a side project of mine that I specifically started to learn the ins and outs of FP. :D Using spread gave me a TS Error earlier, going to try yours after lunch! Thanks!