Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Define Just/Maybe in doc examples #1610

Closed
MattMS opened this issue Jan 25, 2016 · 60 comments
Closed

Define Just/Maybe in doc examples #1610

MattMS opened this issue Jan 25, 2016 · 60 comments
Assignees

Comments

@MattMS
Copy link
Member

MattMS commented Jan 25, 2016

Since they are used in example code, would it be possible to add definitions of Just and Maybe to the documentation?

Alternatively, maybe those examples could be replaced with plain JS types or Ramda functions?

@buzzdecafe
Copy link
Member

I think the changes to the repl should take care of this, next time the docs are built. In that case we will have to be sure we fully qualify which Just/Nothing we mean in the docs

@CrossEye
Copy link
Member

This is on my list of things to do in the documentation. I think we should document all external types used, such as Ord, Lens, Filterable, etc. Since we're using Maybe and its Just and Nothing subtypes in examples, they should also be documented. This is not something I think is hard to do; it's simply never bubbled to the top of the list.

@MattMS: Is this something you'd care to take a crack at? The documentation is maintained in a separate project if you are.

@MattMS
Copy link
Member Author

MattMS commented Jan 26, 2016

I'd love to help out with the documentation but my only hesitation is not being familiar enough with functional programming and the libraries described to do it properly.

Can provide any links to resources I should check out (like the types described)?
I'll also open any other documentation-related issues in that repo.

@MattMS
Copy link
Member Author

MattMS commented Jan 26, 2016

The examples that spawned this question are sequence and traverse.

Any chance of a plain JS example of their usage?
I have no idea what they are meant to do.

@buzzdecafe
Copy link
Member

Unfortunately the "plain JS" examples are not as useful as the ADT examples, which is why we chose to use those for illustration.

For example(s): http://goo.gl/ymj54P

@MattMS
Copy link
Member Author

MattMS commented Jan 26, 2016

Actually the last example (R.sequence(R.of, [[1, 2], [3, 4], [5, 6]]) == [[1, 3, 5], [1, 3, 6], [1, 4, 5], [1, 4, 6], [2, 3, 5], [2, 3, 6], [2, 4, 5], [2, 4, 6]]) helped me finally see what I could do with it.

Are there issues with having simple examples like that following the current ones?

@buzzdecafe
Copy link
Member

Are there issues with having simple examples like that following the current ones?

no problem at all. let's make it clearer if we can.

(btw traverse is just sequence with a mapping function thrown in.)

@MattMS
Copy link
Member Author

MattMS commented Jan 26, 2016

Awesome! I'll be able to play around with them now. 😄

Unfortunately, it's 1am here so my play time will need to be later.

@davidchambers
Copy link
Member

Examples should depict common usage. R.sequence and R.traverse are primarily useful for getting from an A of B to a B of A. Transforming a list of lists into a list of lists doesn't exemplify this inversion.

@CrossEye
Copy link
Member

Examples should depict common usage. R.sequence and R.traverse are primarily useful for getting from an A of B to a B of A. Transforming a list of lists into a list of lists doesn't exemplify this inversion.

I think this is the problem. The main usage of, say, sequence is probably for something like the first example1 in the documentation:

R.sequence(Maybe.of, [Just(1), Just(2), Just(3)]);   //=> Just([1, 2, 3])

But that is likely to confuse someone who's never seen Maybe. But examples with the only other type we can comfortably use, lists, don't really show what it's all about.

One suggestion floated recently would be for there to be two levels of documentation for some or all functions, a quick gloss that explains the type signature and gives a brief example or two and a separate, much more in-depth explanation. While that sounds great, I'm not sure how to accomplish it, or even if it would really solve this problem.


1 The second example actually seems to be wrong. (http://goo.gl/ZzlJw9

@raine
Copy link
Member

raine commented Jan 26, 2016

But that is likely to confuse someone who's never seen Maybe.

In that case one is probably not going to find the function useful.

@MattMS
Copy link
Member Author

MattMS commented Jan 27, 2016

To complete the circle: would it be possible to define Just and Maybe somewhere that is linked from the examples? 😜

I would need some links to where I could learn this stuff before I could offer better suggestions.

@buzzdecafe
Copy link
Member

Sanctuary's S.Just and S.Nothing and ramda-fantasy's Maybe.Just and Maybe.Nothing are defined in the repl

@MattMS
Copy link
Member Author

MattMS commented Jan 27, 2016

I assume these are what you mean:

Definitely seems like useful reading.

@dalgard
Copy link

dalgard commented Feb 15, 2016

Any chance that descriptions of how concepts like Maybe, Just, and Nothing integrates with Ramda will be added to the wiki page on Type Signatures?

This is what I was originally seeking when creating issue #1627.

@arcseldon
Copy link
Contributor

@dalgard - your request is a good one. In meantime, have you taken a look at the ramda-fantasy docs, for example Maybe Here, ramda and Maybe are being used freely together.

@dalgard
Copy link

dalgard commented Feb 15, 2016

@arcseldon: Yeah, thanks. I actually understand the concept of Maybe already – what I'd like to know more about is Ramdas relationship with the types.

I'd like an explicit account of:

  • How the types are used (duck typing). Can they come from any library? Differences between Ramda Fantasy and Sanctuary types?
  • How the parallel development of Ramda and any specific type library is organized, assuring me that I can depend on their integration.
  • And especially, recommendations from the developers in regard to their use.

@arcseldon
Copy link
Contributor

@dalgard - how are you currently trying to use them ? Can you offer some code example.

@dalgard
Copy link

dalgard commented Feb 15, 2016

That's the thing, I'd like to know the answers to my questions above before I begin using them in a serious way.

@arcseldon
Copy link
Contributor

@dalgard - I sympathise completely - currently things are not clear for all the aforementioned reasons in this and previous issues. Let's use Maybe as an example, to illustrate my take on things. I am in the same boat as you. Understand the concepts, have little practical experience applying the fantasy types to daily code in JS - have done so in Scala quite a bit using similar API.

Here we shall ignore Sanctuary completely. Lets consider ramda-fantasy as our extension NPM package for ramda in order to get some types such as Maybe. In fact, lets just pick on Maybe and use it with say (randomly choosing a useful everyday function from Ramda) R.find

So simple, vanilla example:

'use strict';

const R = require('ramda');

const numbersA = [1, 2, 3, 4, 5];
const numbersB = [1, 1, 1, 1, 1];

const greaterThanTwo = (a) => a > 2;

const resultA = R.find(greaterThanTwo, numbersA);
console.log(resultA);
//=> 3

const resultB = R.find(greaterThanTwo, numbersB);
console.log(resultB);
//=> undefined

Ok, so all good, but that undefined is a real problem (isn't it?)...

We can introduce Maybe to solve this one as follows, but R.find doesn't know anything about Maybe so lets see if we can bolt it onto the end using composition. First attempt:

const R = require('ramda'),
  RF = require('ramda-fantasy'),
  Maybe = RF.Maybe,
  Just    = Maybe.Just,
  Nothing = Maybe.Nothing;

const numbersA = [1, 2, 3, 4, 5];
const numbersB = [1, 1, 1, 1, 1];

const greaterThanTwo = (a) => a > 2;

const maybeFound = R.compose(Maybe.of, R.find(greaterThanTwo));

const resultA = maybeFound(numbersA).getOrElse(2);
console.log(resultA);
//=> 3

const resultB = maybeFound(numbersB).getOrElse(2);
console.log(resultB);
//=> undefined

Close, but no cigar. Notice that unfortunately we can't just compose with Maybe.of because that would result in a Just(undefined) instead of a Nothing when no result was found...

So, lets bin using Ramda find, and roll our own with baked in support for Maybe.

'use strict';

const R = require('ramda'),
  RF = require('ramda-fantasy'),
  Maybe = RF.Maybe,
  Just    = Maybe.Just,
  Nothing = Maybe.Nothing;

// Returns Maybe.Just(x) if some `x` passes the predicate test
// Otherwise returns Maybe.Nothing()
function find(predicate, xs) {
  return R.reduce(function(result, x) {
    return result.isJust() ? result :
      predicate(x) ? Just(x) : Nothing()
    }, Nothing());
}

const numbersA = [1, 2, 3, 4, 5];
const numbersB = [1, 1, 1, 1, 1];

const greaterThanTwo = (a) => a > 2;

const maybeFound = find(greaterThanTwo);

const resultA = maybeFound(numbersA).getOrElse(2);
console.log(resultA);
//=> 3

const resultB = maybeFound(numbersB).getOrElse(2);
console.log(resultB);
//=> 2

Ok, that works. There must be a better way right?

@CrossEye @buzzdecafe - please can you enlighten us? Or is it that we should roll our own recipes to get the Just / Nothing decision logic in there...

@raine
Copy link
Member

raine commented Feb 15, 2016

Quick peek in src/Maybe.js shows

function Maybe(x) {
  return x == null ? _nothing : Maybe.Just(x);
}

So you can use that constructor,

Installed into REPL context:
 - ramda@0.19.1 as R
 - ramda-fantasy@0.4.1 as RF
> RF.Maybe(R.find((a) => a > 2, [1, 1, 1, 1, 1]))
_Nothing {}
> RF.Maybe(R.find((a) => a > 2, [1, 1, 1, 1, 3]))
_Just { value: 3 }

data.maybe has Maybe.fromNullable for this purpose.

@dalgard
Copy link

dalgard commented Feb 15, 2016

@arcseldon: Thanks for that. We're definitely in the same boat!

@raine: What about the composition example that @arcseldon just posted?

Please note that I have a few other points above that I'd love to see answered by the developers, preferably as part of the documentation for Ramda.

@arcseldon
Copy link
Contributor

@dalgard - At least we are in a boat, and not drowning 😄

@raine - thanks for pointing out the Constructor usage! Wow, I think we have just written the requested documentation.. 😄

@raine
Copy link
Member

raine commented Feb 15, 2016

@raine: What about the composition example that @arcseldon just posted?

> const safeFind = pipe(find, Maybe)
> safeFind(gt(__, 2), [1,1,1])
_Nothing {}
> safeFind(gt(__, 2), [1,1,3])
_Just { value: 3 }

@buzzdecafe
Copy link
Member

here's a quick example of safeFind:

const Just = Maybe.Just;
const Nothing = Maybe.Nothing;

var ones = [1,1,1,1,1,1,1];

const safeFind = compose(Maybe, find);

safeFind(gt(__, 0), ones); //=> Just(1)
safeFind(gt(__, 1), ones); //=> Nothing

@buzzdecafe
Copy link
Member

too late, @raine beat me to an almost identical example

@arcseldon
Copy link
Contributor

@buzzdecafe - yep, but thank you anyhow - and now we have a Maybe in play, we can just map our way through further compositions etc.

@buzzdecafe
Copy link
Member

right, the problem is once you are inside that functor you are committed to it. You could stay at a more primitive level by composing with defaultTo or tryCatch

@arcseldon
Copy link
Contributor

@buzzdecafe - Right.

Seeing as we have made great inroads in this issue towards fully exploring and understanding Ramda and its interplay with Maybe (in this case from ramda-fantasy) - I wanted to go a little further by way of examples, and pull in some valuable commentary from another issue - do tend to plagiarize the core team alot when it comes to explaining this stuff - on this occasion from @CrossEye..

Stated as is:

Although what is specified by FantasyLand is what Haskell calls typeclasses the basic notion is simply one of algebraic types, types defined by a collection of functions/methods that apply to them and laws about how those functions interact.

The specific types are ones that have shown themselves to be quite useful for many developers over a long time. They are generally fairly abstract, but the laws specifying their interaction make them quite useful. For instance, Functor defines map, and the composition law of Functor says that (in Ramda terms)

compose(map(f), map(g)) ≍ map(compose(f, g))

A number of libraries create types that implement some of these algebraic specifications, including Folktale, RamdaFantasy, and Sanctuary. Ramda itself does not try to implement any of these specifications. But many of its functions delegate to named methods on the relevant objects, and this include almost all of the functions specified by the various algebraic types of FantasyLand.

So taking @buzzdecafe example of safeFind, lets see what happens if we wish to compose a few (contrived in this example) more Ramda functions off the back of the Maybe result. The question is, how do we continue the interplay between vanilla Ramda and Ramda-Fantasy. Well, my first take on this is we just map each of the functions along the pipeline, which is like opening up the Maybe box, applying the needed function on the contents, and then wrapping backup in a Maybe box. Note in this example, there isn't the possibility of a Nothing decision, it is more about working with Maybe as-is - either passing on the Nothing result unchanged, or else updating the Just value.

'use strict';

const R = require('ramda'),
  compose = R.compose,
  map = R.map,
  find = R.find,
  gt = R.gt,
  increment = R.inc,
  double = R.multiply(2),
  decrement = R.dec,
  flip = R.flip,
  RF = require('ramda-fantasy'),
  Maybe = RF.Maybe,
  Just    = Maybe.Just,
  Nothing = Maybe.Nothing;


var ones = [1,1,1,1,1,1,1];

const findGtZero = find(flip(gt)(0));
const findGtOne = find(flip(gt)(1));

const safeFindGtZero = compose(Maybe, findGtZero);

const safeIncrement = map(increment);
const safeDouble = map(double);
const safeDecrement = map(decrement);

const safeFindAndCalcGtZero = compose(safeDecrement, safeDouble, safeIncrement, safeFindGtZero);

safeFindAndCalcGtZero(ones);
//=> Just(3)

const safeFindGtOne = compose(Maybe, findGtOne);

const safeFindAndCalcGtOne = compose(safeDecrement, safeDouble, safeIncrement, safeFindGtOne);

safeFindAndCalcGtOne(ones);
//=> Nothing

I don't know about you, but that looks horrid to me, so many intermediary functions or map wrapping going on... Can we do better?

Sure, remember this:

compose(map(f), map(g)) ≍ map(compose(f, g))

Well, lets try it out. What we'd expect is:

compose(map(decrement), map(double), map(increment);

to be the same as:

map(compose(decrement, double, increment));

Ok, lets give that a spin:

const safeCalc = map(compose(decrement, double, increment));

const safeFindAndCalcGtZero_delta = compose(safeCalc, safeFindGtZero);

safeFindAndCalcGtZero_delta(ones);
//=> Just(3)

const safeFindAndCalcGtOne_delta = compose(safeCalc, safeFindGtOne);
safeFindAndCalcGtOne_delta(ones);
//=> Nothing

It worked. Amen.

Still not sure I am sold on this style of coding, but going back to what @CrossEye explains:

The specific types are ones that have shown themselves to be quite useful for many developers over a long time

So perhaps the people have already spoken, and my personal bias is more down to what I am familiar with rather than what is truly useful.

I'd be grateful if others could offer up whether they actively program with implementations of fantasy land specs, or whether this stuff (in JavaScript world, where the language doesn't offer baked in support) really is just that - a fantasy?

@CrossEye
Copy link
Member

Am starting to see the argument for default implementations, and even consider collapsing ramda-fantasy package into ramda core.

There is a real argument to be made for that. (Just ask @davidchambers! 😄) And this has discussed at least as far back as #683. The reason I've been against doing it goes back to the fundamentals of Ramda. David described it very well in #1218 (comment):

Sanctuary embraces correctness in a way that Ramda cannot, given Ramda's goal of remaining approachable to JavaScript programmers with no FP experience. This is a worthwhile goal, as we can't expect such programmers to jump directly to PureScript. This is a smoother upgrade path:

Vanilla JavaScript → Underscore/lodash → Ramda → Sanctuary → PureScript

Remaining approachable involves especially returning from our functions something immediately useful to work-a-day programmers. head([1, 2, 3]) returns 1. I can just use that directly, and I don't have to worry about anyone's odd container type to do so. If it returned Just(1), then it is definitely safer. The same code could handle the undefined equivalent of head([]) returning Nothing(), but it's far less approachable. map? chain? Huh?

Are there any reservations around ramda-fantasy and prd usage? Should I opt for Sanctuary / Folktale (in the near term at least)?

I can't really tell you how battle-tested it is. To me, it's been more of a playground. @TheLudd or @buzzdecafe or others might be able to give you a clearer view. If all you're looking for is the safer versions of Ramda functions, especially Maybe wrappers around potentially unsafe calls, then I would definitely go with Sanctuary.

But Sanctuary is not attempting to do what R-F or Folktale are doing, which is to supply substantial useful implementation of various common types. So if you want to use some of those (Reader, IO, Future/Task, Validator) then you should consider one of these libraries.

@arcseldon
Copy link
Contributor

@CrossEye - cannot argue against the upgrade path analogy.

head([1, 2, 3]) returns 1 - yep, that is already starting to look suspect now.

Shall continue to mix ramda and sanctuary when required, should suffice.

Thank you also for pointing out that a Fantasy land implementation is still required for some of the other implementations. I am unclear whether I really need IO or Reader at this point, but Future I could see being useful on occasion. I really like the pure way in which nothing happens until you call fork on them - that to me is an advantage over vanilla promise usage.

For instance, wrapping readFile etc might be one way to solve callback syntax - not really had enough practical experience to comment though.

//+ readFile :: String -> Future(Error, String)
const readFile = (filename) => {
    return Future((rej, res) => {
        fs.readFile(filename, 'utf-8', (err, data) => {
            err ? rej(err) : res(data);
          });
      });
  };

with incorporated pipeline creation:

  //+ fiveLines :: String -> String
  const fiveLines = compose(join('\n'), take(5), split('\n'));

  //+previewFile :: String -> Future(Error, String)
  const previewFile = compose(map(append('...')), map(fiveLines), readFile)

Or perhaps to wrap http calls:

 //+ getJSON :: String -> Object -> Future(Error, JSON)
  const getJSON = curry((url, params) => {
      return new Future((rej, res) => {
          $.getJSON(url, params, res).fail(rej);
        });
    });

and then invoke:

 //+ posts :: Object -> Future(Error, [Post])
  const posts = compose(map(sortBy('date')), getJSON('/posts'));

  posts({}).fork(logError, renderView);

(source: Monad a Day 2: Future - Thanks Brian)

However, am still a little unclear on its interaction with say bluebird / Q promise libraries for doing more advanced promises manipulation, in parallel etc... would be great to get some examples here. Likewise, i would be grateful if anyone could point out usage of Ramda's composeP - assuming that is just async waterfall, or joining together promises with .then() ?

@CrossEye
Copy link
Member

However, am still a little unclear on its interaction with say bluebird / Q promise libraries for doing more advanced promises manipulation, in parallel etc... would be great to get some examples here.

I think many of us here find Promises to be too unlawful to be useful. I know that I personally prefer to use Futures or Tasks instead.

Likewise, i would be grateful if anyone could point out usage of Ramda's composeP - assuming that is just async waterfall, or joining together promises with .then() ?

Yuri Takhteyev, who introduced the function, wrote about it in December, 2014.

@arcseldon
Copy link
Contributor

Thank you, the explanation regarding composeP / pipeP was exactly what I was looking for, as well as getting the context / history too.

Example usage:

const getCostWithTaxAsync = R.pipeP(
    getItem, // get a promise for the item
    R.prop('cost'), // pull out the 'cost' property
    R.multiply(1 + TAX_RATE) // multiply it by 1.13
); // returns a promise for the cost with tax

Regarding Futures:

I know that I personally prefer to use Futures or Tasks instead.

Which javascript Future implementation are you using? (or is that Folktale's renamed data.Task implementation you are referencing?) I was hoping we were eating our own dog food 😄

@arcseldon
Copy link
Contributor

Compared with the example above, I do think the composeP and pipeP documentation could be made more approachable. Appreciate it is accurate, but the way the promise propagates itself through the pipe etc doesn't mean every function in the pipe has to be explicitly promise returning. The above example demonstrates nicely that you can just have ordinary Ramda functions anywhere after a Promise returning function is invoked (in same way you can do likewise within a .then() chain using promises directly).

@davidchambers
Copy link
Member

@davidchambers - take it Plaid is using Sanctuary for Production atm, or is it still in incubation?

We've been using Sanctuary heavily in one project, Parse, for the past year. Parse makes great use of Ramda as well. Every Plaid project written in JavaScript uses Ramda. Many use Sanctuary as well, though often in just a handful of places.

But Sanctuary is not attempting to do what R-F or Folktale are doing, which is to supply substantial useful implementation of various common types.

This is a function of my time and attention. I'd love to add a Task type, or receive a pull request for one. ;)

@arcseldon
Copy link
Contributor

@davidchambers - thank you for your reply. Great, the fact that Ramda and Sanctuary have received heavy usage is reassuring. I was using Ramda version 0.7 in production with a previous Client back in early 2014 - don't like to dwell on such things - sure it was all performant and bug free 🙈

I'd love to add a Task type, or receive a pull request for one

Not from me you wouldn't 😄 but i guess I could always cobble something together based on other libraries at a push.. Seriously, IF I get some time I'd really like to have a go, but not making any commitment here. The workload from new Client is really ramping up now so I am going to have less time available.

What are you using at Plaid to fill the gap regarding Fantasy Land data types? Or aren't you using anything unless Sanctuary / Ramda covers it...

@CrossEye
Copy link
Member

Compared with the example above, I do think the composePand pipeP documentation could be made more approachable.

We'd certainly entertain a PR on this!

@davidchambers
Copy link
Member

What are you using at Plaid to fill the gap regarding Fantasy Land data types? Or aren't you using anything unless Sanctuary / Ramda covers it...

plaid/async-problem makes a compelling case for Task, but right now most of our projects use some flavour of Promise. :\

Funnily enough, I think require('data.task') is a significant barrier to entry. Were S.Task to exist there would be less opposition to using tasks. :)

@CrossEye
Copy link
Member

Which javascript Future implementation are you using? (or is that Folktale's renamed data.Task implementation you are referencing?)

Until recently, I always used data.Task. I now sometimes use R-F's Future.

I was hoping we were eating our own dog food 😄

I don't feel that way at all about Ramda-Fantasy. To me it's mostly been a small learning project, trying to find out what these ADT's are all about. Of course Ramda itself started that way too, but in my mind R-F hasn't come close to making the transition to being a fully formed library the way Ramda did some time back. But I may not have the right impression either, as I haven't been very involved. I've on and off been working on something which is related to the FantasyLand specs, but which is built a very different way. It's quite far from ready, though. But this has taken whatever energy I might have put into R-F.

But one of the whole points of Ramda's dispatching mechanism is that Ramda should be able to work well with any compliant implementation of a particular F-L spec. It might work fine with other objects that have a map, ap, chain, or whatever as well. So choosing one should have to do with other things besides Ramda.

@Jeff-Tian
Copy link

image

@adispring
Copy link
Member

adispring commented Nov 20, 2019

@Jeff-Tian , you can Open in REPL instead of "Run it here", Ramda's REPL import ramda-fantasy & Sanctuary which contain Maybe and Just.

@CrossEye
Copy link
Member

This does make me wonder, though, if it would be easy enough to update our RunKit implementation to include some version of Maybe and Either. I imagine it would be straightforward. But I've never spent any time on that integration.

Anyone know how to do this? @ramda/ramda-repl, @ramda/core, @tolmasky?

@tolmasky
Copy link
Contributor

You can accomplish this fairly trivially by adding something like this:

const { Maybe, Either } = require("ramda-fantasy");

to the preamble of the embed. The preamble property just has code that you want to load before the user-editable portion. It's currently used to get R into scope for example.

@tolmasky
Copy link
Contributor

To follow up, this line would just need the above added to it.

@CrossEye
Copy link
Member

@tolmasky: Perfect. Thank you very much!

@CrossEye CrossEye reopened this Nov 20, 2019
@CrossEye CrossEye self-assigned this Nov 20, 2019
@Jeff-Tian
Copy link

@Jeff-Tian , you can Open in REPL instead of "Run it here", Ramda's REPL import ramda-fantasy & Sanctuary which contain Maybe and Just.

Thank you @adispring . But most of the time I hope I can run it through RunKit, because REPL uses some CDNs that behaves badly in Shanghai:

image

I know I can use VPN, but if runkit works, then I don't need to bother using it.

@tolmasky
Copy link
Contributor

I am getting a pull request ready that adds this feature. However, I had a couple questions before submitting:

  1. According to ramda-fantasy's repository, the project is no longer maintained. Is there some alternative Maybe/Either that is preferred? Seems iffy to add a library that is close to deprecation, but happy to do it.
  2. If we do want to use ramda-fantasy, could we perhaps make a minor change to ramda-fantasy to make ramda a peerDependencies instead of dependencies? As is, ramda-fantasy essentially relies on bespoke to deduping to not include ramda twice, whereas by listing ramda as a peerDependency, the deduping intention would be explicit.

Neither of these are deal breakers, and it works as is, but the second point would improve performance for example.

@CrossEye
Copy link
Member

@tolmasky:

I can't see that it would hurt to change it to a peer dependency. But I should do a little reading first.

I would probably stick with the ramda-fantasy version for now. Most of the Maybe/Either usages we have have been tested with that repo, and they are very simple. It should be easy to change to it later.


On a side note, I'm wondering if you've seen any integrations of RunKit with https://tiddlywiki.com/? I'm working on another project, which I was thinking of documenting with TiddlyWiki, but would love to have runnable snippets. I haven't done any research on this, so there may be an obvious answer somewhere. But if you have seen it, could you let me know?

@tolmasky
Copy link
Contributor

OK, I have filed a pull request to support this: ramda/ramda.github.io#228

@CrossEye I'll take a look at the tiddlywiki thing.

@CrossEye
Copy link
Member

@tolmasky:

Thank you. I will take a look at the PR this weekend.

Please don't worry much about TiddlyWiki. I was hoping that you might have already seen such an integration. If not, it's not a big deal. If and when I get to that stage, I'll start looking.

@tolmasky
Copy link
Contributor

Hi @MattMS and @Jeff-Tian, this should be live on the site now, so I think we can close if we can confirm it works the way you'd like now?

@Jeff-Tian
Copy link

Cool! Love it and thanks a ton.

@customcommander
Copy link
Member

Closing since related pull request has been merged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests