lloydmeta / frunk

Funktional generic type-level programming in Rust: HList, Coproduct, Generic, LabelledGeneric, Validated, Monoid and friends.
https://beachape.com/frunk/
MIT License
1.29k stars 58 forks source link

add prelude and reexports #103

Closed ExpHP closed 6 years ago

ExpHP commented 6 years ago

This completes the paradigm shift from a focus on per-module glob imports to the more rust-y ideal of "use what you need." It adds a prelude module to contain that small number of things that really should be glob-imported (i.e. things that the user might not realize they need :wink:).

I grepped for everything that is pub in the repo and went down the list, considering where each thing belongs. I'll post a comment with reasoning for all of my choices.

ExpHP commented 6 years ago
Reasoning behind each placement --- * `pub struct hlist::HNil` * `pub struct hlist::HCons` * `pub enum coproduct::Coproduct` **Root-level reexports** These are data types intended for user consumption. Examples should begin to write `use frunk::{HNil, HCons}` or etc. as needed, rather than writing `use frunk::hlist::*`. (many examples don't even need to import anything at all, thanks to the macros) --- * `pub enum coproduct::CNil` No action taken because its days are limited. --- * `pub trait hlist::HList` **In the prelude** for `::LEN`. --- * `pub fn hlist::h_cons` **Root-level reexport** So that you can write `use frunk::{HNil, HCons, h_cons}`. --- * `pub enum hlist::Here` * `pub struct hlist::There` * `pub struct hlist::Suffixed` No action taken. Users don't need to know about them. (for now) --- * `pub trait hlist::Selector` * `pub trait hlist::Plucker` * `pub trait hlist::Sculptor` * `pub trait hlist::IntoReverse` * `pub trait hlist::IntoTuple2` * `pub trait coproduct::CoprodInjector` * `pub trait coproduct::CoproductSelector` * `pub trait coproduct::CoproductTaker` * `pub trait coproduct::CoprodUninjector` * `pub trait coproduct::CoproductSubsetter` * `pub trait coproduct::CoproductEmbedder` No action taken. These have inherent method wrappers. --- * `pub trait hlist::HMappable` * `pub trait hlist::HFoldRightable` * `pub trait hlist::HFoldLeftable` * `pub trait coproduct::CoproductFoldable` **Prelude.** These are a prime example of what belongs in a prelude; they are traits that the user shouldn't need to know about, which nonetheless provide useful methods that the user probably wants to use. --- * `pub trait hlist::LiftFrom` * `pub trait hlist::LiftInto` * `pub fn hlist::lift_from` **Root-level reexports,** since it appears to me that the traits are intended to possibly be implemented by users on their own types. (@Centril: please verify?) --- * `pub trait generic::Generic` * `pub trait labelled::LabelledGeneric` **Root-level reexports** because they are a core feature and they deserve at the *very least* a left-clickable link on the the root module's doc page. **Note:** I feel like these belong in the prelude as well (so that the methods "just work" after `#[derive(Generic)]`), but I left them out because I am worried about collisions with `From::from` and `Into::into`. --- * `pub fn generic::from_generic` * `pub fn generic::into_generic` * `pub fn generic::convert_from` * `pub fn labelled::from_labelled_generic` * `pub fn labelled::into_labelled_generic` * `pub fn labelled::labelled_convert_from` * `pub fn labelled::transform_from` **Root-level reexports** since they're advertised in the docs. IMO these have a role similar to e.g. `::serde_json::to_writer`: * For a single use, you can write `::frunk::from_generic`. * For frequent use, you can `use frunk::from_generic`. --- * `pub struct labelled::Field` * `pub struct labelled::ValueField` * `pub fn labelled::field_with_name` * `pub trait labelled::IntoUnlabelled` * `pub trait labelled::IntoValueLabelled` No action taken. It doesn't look like these are prominent features. --- * `pub trait semigroup::Semigroup` * `pub trait monoid::Monoid` **Root-level reexport** because these are traits that people might want to impl for their own types. Not in the prelude because it seems unlikely for a user to need these methods "by accident" (i.e. without knowing that they belong to the trait). (**Note: (counterexample)** when I wrote the example in lib.rs I mistakenly imported `Monoid` thinking it would make `combine` available...) (P.S. I think these deserve iterator extension traits, which would *definitely* go in the prelude) --- * `pub struct semigroup::Max` * `pub struct semigroup::Min` * `pub struct semigroup::Product` * `pub struct semigroup::All` * `pub struct semigroup::Any` No action taken. These helper structs benefit from being namespaced. Users should import them as `use frunk::semigroup::Min`. --- * `pub fn semigroup::combine_n` * `pub fn semigroup::combine_all_option` * `pub fn monoid::combine_n` * `pub fn monoid::combine_all` No action taken. Names would conflict if they were reexported. (P.S. it bothers me that `semigroup::combine_n` accepts `n = 0`...) --- * `pub enum validated::Validated` **Root-level reexport.** --- * `pub trait validated::IntoValidated` **In the prelude** because it is an extension trait whose methods have clearly distinguished names. --- * `pub trait kind::Kind` * `pub trait functor::Functor` Ignored because they don't actually exist. (Looks like these were checked into VCS by accident.) ---
Centril commented 6 years ago

Root-level reexports, since it appears to me that the traits are intended to possibly be implemented by users on their own types. (@Centril: please verify?)

These are mostly to facilitate quick construction of HLists from smaller parts, they are the "inject" equivalents for HLists.

but I left them out because I am worried about collisions with From::from and Into::into.

Should we solve this by renaming the methods in Generic?

ExpHP commented 6 years ago

These are mostly to facilitate quick construction of HLists from smaller parts, they are the "inject" equivalents for HLists.

Okay. In that case the prelude sounds like a better fit for them. (I'll keep the lift_from function reexported)

Should we solve this by renaming the methods in Generic?

Sounds good to me. (also renaming the ones in LabelledGeneric to avoid conflicts between the two)

ExpHP commented 6 years ago

That said, Generic and LabelledGeneric they don't need to go in the prelude right now because there's a bunch of reexported free functions (which is what I mostly changed README.md to use)

lloydmeta commented 6 years ago

FWIW, I'm 👍 on renaming the methods on Generic and LabelledGeneric; that was a terrible decision that still haunts me.

Centril commented 6 years ago

Let the bikeshed commence!

ExpHP commented 6 years ago

So I was thinking about this today (in part because I'd like to move on with this and get on to adding other, more exciting features!). I think I would rather leave Generic and LabelledGeneric as is for now, as the free functions feel "good enough" to me.

I think the docs should not advertise the use of UFCS for these methods.

Aside: I am also thinking of removing the re-export of h_cons, in favor of encouraging the use of hlist![head, ...tail].

Modulo that change, does this PR seem okay?

Centril commented 6 years ago

I think I would rather leave Generic and LabelledGeneric as is for now, as the free functions feel "good enough" to me.

OK; We can revisit later.

Aside: I am also thinking of removing the re-export of h_cons, in favor of encouraging the use of hlist![head, ...tail].

Agreed.

Modulo that change, does this PR seem okay?

I think so.

ExpHP commented 6 years ago

I'll make the aforementioned finishing touches and merge this on the weekend