dartz
dartz copied to clipboard
Improve documentation
I love this package and use it wherever I can, as I love functional programming. The only thing that bothers me a little is the lack of documentation.
Would'nt it be a nice idea to document the code? I know it's a annoying task, but the results are gratificating, so I'm willing to help. I have a little knowledge on category theory that may help, although it's not a deep knowledge. However, I feel like helping on the documentation will also help me improve my knowledge and skills on FP/CT.
You may set me as collaborator, or we may work simply with gradual PRs, or you may ever decline my proposal.
Thanks, in advance.
Documentation status
In-code documentation
- [ ]
streaming
- [ ]
conveyor.dart
- [ ]
io.dart
- [ ]
pipe.dart
- [ ]
source.dart
- [ ]
tee.dart
- [ ]
text.dart
- [ ]
- [ ]
unsafe
- [ ]
each.dart
- [ ]
io.dart
- [ ]
- [ ]
applicative.dart
- [ ]
applicative_plus.dart
- [ ]
avl_tree.dart
- [ ]
builtins.dart
- [ ]
dual.dart
- [ ]
either.dart
- [ ]
endo.dart
- [ ]
eq.dart
- [ ]
evaluation.dart
- [ ]
foldable.dart
- [ ]
free.dart
- [ ]
free_composition.dart
- [ ]
function.dart
(in progress) - [ ]
functor.dart
- [ ]
future.dart
- [ ]
id.dart
- [ ]
ihashmap.dart
- [ ]
ilist.dart
- [ ]
imap.dart
- [ ]
io.dart
- [ ]
iset.dart
- [ ]
ivector.dart
- [ ]
lens.dart
- [ ]
list.dart
- [ ]
monad.dart
- [ ]
monad_catch.dart
- [ ]
monad_plus.dart
- [ ]
monoid.dart
(in progress) - [ ]
option.dart
- [ ]
order.dart
- [ ]
plus.dart
- [ ]
plus_empty.dart
- [ ]
semigroup.dart
(in progress) - [ ]
state.dart
- [ ]
task.dart
- [ ]
trampoline.dart
- [ ]
traversable.dart
- [ ]
traversable_monad.dart
- [ ]
traversable_monad_plus.dart
- [ ]
tuple.dart
- [ ]
unit.dart
(in progress)
Hi @mateusfccp!
I completely agree. You are not the first one to suggest this and I believe that at least some basic level of documentation would make the library much more approachable.
I'm not even going to try to come up with any excuses for the current sorry state of the documentation :-) Let's just say I would welcome any help with open arms! If you or others are willing to contribute, how would you feel about starting with a PR based approach and switching to collaborator mode once we've gotten our feet wet?
Hi, @spebbe
I'm fine with your suggestion. I don't have a lot of time, but I'm willing to gradually help with documentation whenever I can. If other people would join me, any help is appreciated.
May we use this issue to track the work?
Sure! Also, no pressure – any improvement whenever you have the time is appreciated.
As another FP fan, I'd like to help a little as well. Would it be convenient to create a docs branch for this work that could be merged into master periodically until we get some momentum? Or should we just submit PRs against master?
@deanriverson, I appreciate your help.
If you feel to, we may initially work on a forked branch of ours. I already started to work on some basic documentation on less complex classes, like Unit
, Semigroup
and Monoid
. I'm going to push it tomorrow so you all can see if you like the approach I'm using by now.
We may then set up some general guidelines for the documentation to be consistent. By now, I'm using the Effective Dart guidelines, as it's a good idea to be in conformance with the community, but we may also define some more specific guidelines if we like to.
Agreed, working on a forked repo is the best way to go. I also like the plan of using the Effective Dart guidelines as a baseline and layering more specific guidelines on top if we need to.
Looking forward to seeing your initial work!
Well, here is my initial attempt (unit.dart
):
https://github.com/mateusfccp/dartz/blob/master/lib/src/unit.dart
Some principles I tried to acomplish:
- I tried to be straight and clear;
- I tried to provide a minimal and practical example;
- I tried to left additional not so important details under "Additional details".
For now, I left overriden methods (toString
, zero
, append
) to inherit its documentations from its parents, but they can of course be rewritten if needed.
What do you think about this approach? @spebbe @deanriverson
@mateusfccp I see that you mentioned me (but meant to mention dean). I still would like to give my retrospective opinion about the lack of documentation since I did spend quite some time learning FP mainly by digging through dartz.
IMHO dartz is not lacking documentation. Each element in itself is not complicated to grasp. The hardest part is getting a feel for the full picture. Documenting monoids and monads feels to me like teaching a programmer, while he is programming, what classes are.
The biggest problem that new developers have with fp is that they think that it can't be used to solve real world problems. The example folder in dartz is invaluable. It teaches techniques that are eye opening to someone who is used to OOP and that is what I believe dartz needs more of.
I don't mean to offend you or your efforts, but everytime I tried to convince someone to take a look at fp it never failed because of the lack of documentation but because they didn't see why they would need it. Explaining what a lens (or any other concept for that matter is) is not enough to give them an intuitive understanding for them. They need to see FP in action.
@modulovalue Although I agree partly with you, I don't think this is the point of the documentation. As a functional programmer myself, I found the lack of documentation a little frustrating when started with dartz. For example, I only realized the fact that |
could be used for getOrElse
after looking at the source code.
There's also the case where a person is still learning FP and know some concepts but not all of them. In this cases, a documentation helps him to learn a little about the concept and its practical utilization, and if they like to, they may learn more about the subject by itself.
I definitely agree with @modulovalue that explaining how each of the types can be used is important. But I think even the documentation that @mateusfccp did for a type as simple as Unit shows how important source code documentation can be. It's not that Unit is a difficult concept to grasp, it's more about getting new users (new to FP as well as new to dartz) comfortable with the library and its philosophy. If you're an old hand at FP (I'm sure they exist somewhere) then you know right away that this is the Unit you're used to, but with maybe a few differences. For a newbie, it makes the library infinitely more approachable.
@mateusfccp That is a great start! Exactly what I was picturing.
@deanriverson There's details pending as stated by @modulovalue on the commit, but I'm glad you liked it. I'm going to Semigroup now. Feel free to give suggestions.
Off to a great start! Thank you, people!
@modulovalue, your reasoning rings true to me too. I believe usage examples are the best (and possibly only) way to convey how to "do" FP. On the other hand, I think that some light documentation on the basic purpose and potential quirks of individual types can't hurt either.
I've recently seen a surprising amount of people using parts of dartz
, mainly Either
, that don't seem to have any desire to go all-in on FP. Either
and a couple of other structures are relatively useful in isolation and I think it could be nice to lower the threshold and clear up some confusion about why there is no get
, what you should use instead, etc.
Haskell people on the other hand might appreciate some hint that Option
is what they would normally call Maybe
, etc. ok, a bit of a stupid example, i know, but you get what i mean ;-)
While I like the Unit
documentation, I'm not sure who benefits from the category theoretical information in it. People who have studied category theory might just find it obvious and redundant, while people who haven't will probably find it incomprehensible...? I'm very torn about this though... What do you think?
@spebbe I though a little about this. This is why I gave a more tangible explanation with "This means that". Maybe we can switch positions and place the "easier" explanation before and throw the more mathematical explanation on the Additional Details section...
What do you think?
Even so, I don't think it's easy to do this in classes that are by itself the concreteness of mathematical terminology, like Monoid, Semigroup, Functor... How could we make it tangible to people who don't really know algebraic and category terms?
Here's another idea, wouldn't it perhaps make more sense to start at the readme level since most people get to see the readme first? That would also be a great way to solve this problem
Either and a couple of other structures are relatively useful in isolation and I think it could be nice to lower the threshold and clear up some confusion about why there is no get, what you should use instead, etc.
And a second completely different suggestion for you @mateusfccp. Of course, it all depends on how far you're willing to go but I personally believe that examples and blog posts are the way to go if you want to help the most people. We have a great community over at r/FlutterDev and FlutterCommunity on Medium. I think they would really appreciate that a lot and it would expose dartz to people who may have never considered using FP concepts before.
Edit: here's an example of a readme that I believe would be a great fit for dartz extended_math
@mateusfccp, Agree. When possible to explain something without category theory, it maybe should be done at the top and with examples. For pure category theoretical structures like the ones you mention, I'm wondering if we might just point interested readers to some of the great learning resources out there (Chiusano&Bjarnason, Milewski, Lipovača, typeclassopedia, etc)? Repeating the standard definitions and laws will probably not help the FP-curious and will be old news to the seasoned FP crowd.
All great ideas. I'm not great on category theory, so I personally liked the balance @mateusfccp struck on the Unit documentation. A little light theory coupled with a little bit of exposition in the form of "this means that..." was just right.
I definitely agree that heavy theory discussions should be avoided in favor of links to the already existing and plentiful resources. This means we have the opportunity to link to the articles that best explain the concepts used in dartz -- a curated list, so to speak.
I also second @modulovalue's thoughts on placing a high priority on the README as well as blog posts and other outreach. I think it's highly effective to link blog posts from a project's README. They are usually more useful to newcomers than just diving into the example code unless the example code is simple and extremely well commented.
It's funny that using Option instead of Maybe was mentioned because that definitely threw me when I was first looking at dartz since finding a Dart Maybe type was what motivated my search for a FP library. So I can relate to that!
@spebbe I'm going to try this inverted approach, and remove teory details to a minimum so teory proficients will know what this does means with just a glance. Plus, add reference links to in-dept explanation.
For classes like Semigroup, I'm going to use simple on-line statements, like "A structure with an associative binary operator", plus the reference links. What do you think about this approach?
@modulovalue Maybe it's a valid alternative that may also improve the situation of FP on dart/flutter. Sadly, I don't have the time and energy now to work in this kind of bigger project. I agree that this is in some aspect more valuable, but it also demands more responsibility and dedication, that I unfurtunately don't have currently...
Here are some initial thoughts on improving the README:
- I think we can mainly focus on replacing the bullet list of features with some details and simple examples
- Move Dart 1 features to a separate section later in the document. I'm assuming the Dart 2 is the path forward and will be more relevant to the vast majority of current and future users.
- For each of the major types, give a brief description of what it does and a simple motivating example for why you'd want to use it.
- Give examples of common FP idioms in dartz like currying and function composition. Focus on the things everyone will need to do.
What else?
@deanriverson: love it!
The main reason I still have for maintaining Dart 1 compatibility is that the test suite is running with a "fake" property testing engine on Dart 2, meaning that the test suite isn't as confidence building as it is on Dart 1 yet. As soon as I can get my hands on/write a real engine that works with Dart 2, I'll ditch Dart 1!
I'm really excited about the high ambitions here, but I want to stress that I am grateful for any contribution/involvement. Let's keep the good ideas flowing, but please don't feel that you are being coerced into doing more/other work than you feel comfortable with.
@spebbe I'm happy to take on the README work. I think we can draw some inspiration from scalaz and some of the other popular FP libraries.
I'm working my way through the FP in Scala book (really great book, thanks for the recommendation!) and I'm hoping to take inspiration from it for some examples to use in a Quick Start section for the dartz README. I'll also go back through some of the other tutorials and books I've liked, searching for some useful but easy-to-understand examples of the type classes.
If anyone has suggestions for Quick Start examples or of their favorite FP links for the Resources section, I'd love to hear them!
@spebbe
I have a little question regarding FirstSemigroup
and firstSemigroup()
usage. What is the difference in the use-case of these? In my understanding of the code the only difference is that one is typed and the other is dynamic. Am I missing something?
By now, I documented like this:
/// A [Semigroup] whose [append] always return the first element.
final Semigroup FirstSemigroup = semigroup((a1, a2) => a1);
/// Creates a [Semigroup] on `A` whose [append] always return the first element.
Semigroup<A> firstSemigroup<A>() => cast(FirstSemigroup);
@deanriverson
If you are going to work on the readme, please, feel free to send me the status so I can track it in the original post, like I'm doing with in-code documentation!
@mateusfccp, crap, I should have warned you! It is probably more fruitful to work based on the 0_9_0_wip_2 branch. I've been procrastinating merging it, but it has been more or less ready for a while now. The definitions for firstSemigroup
and a couple of others look different on that branch.
This specific pattern allowed a singleton instance of FirstSemigroup
to be used for any A
. This worked as a neat, safe optimization on Dart 1 for "empty" types like FirstSemiGroup
, Nil
and None
, but DDC will notice it and complain although it should in practice be perfectly safe. Compare it with types parameterized with Nothing
in scala.
@spebbe I rebased to 0_9_0_wip_2
with no problems and I'm going to proceed with the work.
Any update on this. I want to use this package but I can't find any getting-started documentation.
I know it's unfortunate @pedromassango but because naming is pretty much the same across languages, I'd recommend you to check out Scala Cats and Kotlin Arrow docs.
@pedromassango I'm working only on in-code documentation, so I can't really help you with this.
I don't know how is things at @deanriverson side.
However, you can check other sources, like @ResoDev suggested.
Hi,
Followed @ResoDev video and successfully used it on my project. 👍 It feels like I'm just scratching the surface and there is much more to discover.
I keep an eyes on this thread and will be satisfied with either a doc or a new in depth video 😄
Same here, lack of example codes creates a huge barrier from learning this awesome lib.