Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upPiping data to functions #2049
Comments
This comment has been minimized.
This comment has been minimized.
Luthaf
commented
Jun 27, 2017
•
|
If your functions do take a result = x.sum()
.abs()
.sqrt()
.round(2); |
This comment has been minimized.
This comment has been minimized.
burdges
commented
Jun 27, 2017
|
I think you're stuck with the reverse polish dot chaining on As an aside, if you consider a language like Haskell, Idris, OCaML, etc. where juxtaposition is high-precedence curried function application, then you have both |
This comment has been minimized.
This comment has been minimized.
|
It's actually pretty simple to implement this with a wrapper type: https://is.gd/42O3Ns But I agree that it's nice that Rust code is readable for people who've never seen a functional language and I wouldn't want to break this for purity's sake. |
This comment has been minimized.
This comment has been minimized.
nixpulvis
commented
Jun 30, 2017
•
|
While I'm on a little Rust RFC binge I'll just swing by here and say that I really hope to never see syntax like |
This comment has been minimized.
This comment has been minimized.
|
I think this is an attempt at building convenient function composition. And i would totally support that! |
This comment has been minimized.
This comment has been minimized.
alilleybrinker
commented
Jul 2, 2017
|
So, translating the pseudocode above into something more Rust-y: // ... assume various functions are implemented here.
fn main() {
let x = vec![1, -7, -5, 3];
let a = sum(x);
let b = abs(a);
let c = sqrt(b);
let result = round(c, 2);
let result = round(sqrt(abs(sum(x))), 2);
let result = x %>% sum %>% abs %>% sqrt %>% |x| round(x, 2)
}I'm not completely opposed to adding an infix function composition operator. But I don't think // ... assume various functions are implemented here.
fn main() {
let x = vec![1, -7, -5, 3];
let a = sum(x);
let b = abs(a);
let c = sqrt(b);
let result = round(c, 2);
let result = round(sqrt(abs(sum(x))), 2);
let result = x >>> sum >>> abs >>> sqrt >>> |x| round(x, 2)
} |
This comment has been minimized.
This comment has been minimized.
|
I was thinking we could define the bitwise-or operator for functions and
closures...
…On Jul 2, 2017 12:24 PM, "Andrew Brinker" ***@***.***> wrote:
So, translating the pseudocode above into something more Rust-y:
// ... assume various functions are implemented here.
fn main() {
let x = vec![1, -7, -5, 3];
let a = sum(x);
let b = abs(a);
let c = sqrt(b);
let result = round(c, 2);
let result = round(sqrt(abs(sum(x))), 2);
let result = x %>% sum %>% abs %>% sqrt %>% |x| round(x, 2)
}
I'm not completely opposed to adding an infix function composition
operator. But I don't think %>% is the right name for it. Pulling the
name from Haskell, you could have either .> (which in Haskell is a
convenient name for flip (.), or you can use >>> from Control.Arrow,
which is more general):
// ... assume various functions are implemented here.
fn main() {
let x = vec![1, -7, -5, 3];
let a = sum(x);
let b = abs(a);
let c = sqrt(b);
let result = round(c, 2);
let result = round(sqrt(abs(sum(x))), 2);
let result = x >>> sum >>> abs >>> sqrt >>> |x| round(x, 2)
}
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#2049 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AIazwBBuc6tcJxopsGqvAGO1qdHFnWTZks5sJ8RJgaJpZM4OGqNe>
.
|
This comment has been minimized.
This comment has been minimized.
|
See also the |
This comment has been minimized.
This comment has been minimized.
alilleybrinker
commented
Jul 2, 2017
•
|
There is something worth pointing out here, which is the distinction between
I mention this because if we're going to do infix composition, there's the question of whether we'd want to keep it to functions of one argument (like with
|
This comment has been minimized.
This comment has been minimized.
alilleybrinker
commented
Jul 2, 2017
•
|
@mark-i-m, that particular overloading seems like it would be confusing. I certainly wouldn't expect bitwise-or on functions to work, much less to provide function composition. It reminds me a bit of C++ overloading |
This comment has been minimized.
This comment has been minimized.
nixpulvis
commented
Jul 2, 2017
|
Call me crazy, but one day we wont be limited to shitty ASCII keyboards, could we start using unicode like ∘ for this? Only like 75% joking. |
This comment has been minimized.
This comment has been minimized.
nixpulvis
commented
Jul 2, 2017
|
In reality |
This comment has been minimized.
This comment has been minimized.
alilleybrinker
commented
Jul 2, 2017
|
@nixpulvis, I mean, APL and APL family languages have all gone down this rabbit hole. In the Haskell world, the proliferation of operators (imo) really hurts readability. I think there's a core set that can be good, but I am generally against going completely crazy with introducing new operators. Haskell's |
This comment has been minimized.
This comment has been minimized.
|
Yeah, i guess chaining method calls are the primary alternative... Did anybody know if they equally expressive? |
This comment has been minimized.
This comment has been minimized.
nixpulvis
commented
Jul 2, 2017
|
They should be, but might require creating a trait. |
This comment has been minimized.
This comment has been minimized.
burdges
commented
Jul 2, 2017
•
|
You cannot beat the curried languages for expressiveness: If you consider the original example As I said before, I think people interested in these question should be asking : How do we bring borrowing, mutability, Rust ABI, etc., to a curried language? Could it be as thin a layer over Rust as say Dogelang is over Python? etc. It's partially that function composition becomes less useful without currying and combinators. |
This comment has been minimized.
This comment has been minimized.
nixpulvis
commented
Jul 2, 2017
|
Upping the level off expressivity isnt always a good thing. I think Haskell itself should be a cautionary tale in what happens when you make something have too many expressive forms. Simplicity should be a goal of any practical language. Readability then comes naturally. Rust already struggles here due to it's complex type system, however I personally believe this is warranted due to the static memory guarantees it provides. |
This comment has been minimized.
This comment has been minimized.
OvermindDL1
commented
Jul 3, 2017
|
Don't forget OCaml, it is as powerful as Haskell but goes through the Module system with sane names instead of doing operator hell as Haskell does. It comes with very few infix operators, one of those is indeed the pipe operator ( |
This comment has been minimized.
This comment has been minimized.
Are you making a theoretical statement or an experiential one? Personally, if chaining can be done via some sort of trait impl, I think that would be the most rustic, but it really depends on the tradeoffs of how much we would lose over composition... |
This comment has been minimized.
This comment has been minimized.
egilburg
commented
Jul 17, 2017
|
@nixpulvis I think that's the direction Julia takes, here are some syntax literals. |
This comment has been minimized.
This comment has been minimized.
TedDriggs
commented
Jul 25, 2017
•
|
The only case where I've found myself looking for this was in Iterator, Result, or Option contexts which already encourage a What if we added a trait like the one @oli-obk provided and then implemented that for the three types that encourage the chaining style? That would keep the syntax lightweight but also let those cases use their preferred style. Having it be a trait would also let people implement it for their own types that use the same style. |
This comment has been minimized.
This comment has been minimized.
|
@OvermindDL1 Maybe it's just me, but I find Haskell way more readable than Rust or any other language syntactically in the C language family. I find that Haskell's abundance of white space really helps me read the code as opposed to code being littered with terminal symbols A significant advantage of compositional programming which you get with pointfree style is that you get away with a complete lack of imagination for variable names since you have none to name. @burdges is spot on - function composition is not very ergonomic when you can't box anything on the heap anytime you like and when you have to think about lifetimes. |
This comment has been minimized.
This comment has been minimized.
I think this is mostly a matter of taste, though... Personally, I find well-formatted rust rather pleasing to the eye...
I'm not sure I follow... as I understand it, a composition feature would be sugar for something you can already write, so how would there be any difference? |
This comment has been minimized.
This comment has been minimized.
|
@mark-i-m I guess it's subjective some degree - and there are worse offenders ;) Sure, it would be sugar, but getting the same expressive power as Haskell might be hard as you might have to distinguish between different types of functions and closures. Some of the expressive you get from partial application and auto-currying, which might need to transparently box the arguments - which you probably wouldn't like in Rust. All I'm saying is it won't be a trivial task to design this well in Rust. |
Centril
added
the
T-lang
label
Dec 6, 2017
This comment has been minimized.
This comment has been minimized.
elcritch
commented
Mar 15, 2018
|
Occasional Rust user here; I landed here after googling for "rust pipe operator". :-) Given Rust's general railway programming style I’m a little surprised it’s not in the language already! A pipe operator provides a useful visual cue that some data is being transformed and enables non-self-methods to be used. Programming in Elixir, Julia, and OCaml/F# has given me a taste for the |
This comment has been minimized.
This comment has been minimized.
sergeysova
commented
Mar 15, 2018
|
Also Javascript has |
This comment has been minimized.
This comment has been minimized.
sergeysova
commented
Mar 15, 2018
•
fn main() {
let result = vec![1, -7, -5, 3]
|> sum
|> abs
|> sqrt
|> |x| round(x, 2);
let result = round(sqrt(abs(sum(vec![1, -7, -5, 3]))), 2);
} |
This comment has been minimized.
This comment has been minimized.
|
Rust has a pipe operator, let result = vec![1.0, -7.0, -5.0, 3.0].into_iter
(). sum::<f32>
(). abs
(). sqrt
(). round
();
println!("{}", result);Try it on play: https://play.rust-lang.org/?gist=e00f6a9e9738ee655b23c62866d78653&version=stable More seriously, should it just be easier to make extension methods? |
This comment has been minimized.
This comment has been minimized.
egilburg
commented
Mar 16, 2018
|
@scottmcm That work only on methods of the receiver, not an arbitrary function |
This comment has been minimized.
This comment has been minimized.
|
I don't know how well this would work, but we could have |
This comment has been minimized.
This comment has been minimized.
OvermindDL1
commented
Mar 19, 2018
•
Sounds similar to C++'s Unified Call Syntax proposal. However that doesn't really fix pipelining entirely as ambiguity can pop up on which to use in such a syntax. For note, a big reason for pipelining is to prevent stupid things like Haskell'y operator explosion. Instead of doing things like |
This comment has been minimized.
This comment has been minimized.
|
That kind of UFCS isn't a great fit for Rust since we already have deref
coercion. Does a.b(c) desugar to (*a).b(c) or b(a, c)? What if they both
exist, which one is first, how many times to deref before trying UFCS? We
can define the precedence obviously but I think it'll make it harder to
figure out what code does when reading/writing it.
…On Mon, Mar 19, 2018 at 10:29 AM, OvermindDL1 ***@***.***> wrote:
I don't know how well this would work, but we could have a.b(c) desugar to
b(a, c) if the type of a does not have a b method. This would be kind of
like an extension of UFCS...
Sounds similar to C++'s Unified Call Syntax proposal.
However that doesn't really fix pipelining entirely as ambiguity can pop
up on which to use in such a syntax.
For note, a big reason for pipelining is to prevent stupid things like
Haskell'y operator explosion. Instead of doing things like blah >>> bloop
you can instead 'name' the calls via blah |> andThen(bloop) or whatever.
It allows you make DSEL things but with a unified syntax easily and across
type that you may or may not control. Traditionally functional languages
pipe into the last position, but many popping up are piping into the front
position so it visually 'flows' properly, I.E. blah |> andThen(bloop) === andThen(blah,
bloop), thus meaning that both forms seem proper. However, knowing what
subject should be passed in is not always correct, so some kind of 'put
here' form is useful, perhaps like blah |> andThen(_, bloop) being
equivalent to the prior when used in non-default position (bonus points for
supporting doing stuff to the _ bit as well).
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#2049 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAC3nxHoSME4dIqG0YWzZ0G-x7WG19YXks5tf8CygaJpZM4OGqNe>
.
|
This comment has been minimized.
This comment has been minimized.
It is not true that you have an explosion of operators in Haskell -- there are only a few packages that do this (like
The former as function composition ("pipelining") seems infinitely more ergonomic -- you learn the operator once and then you know what it means. You can also use the reverse, which is just @durka Seems to me that Personally, I'd like some general and ergonomic mechanism for function composition tho so I can write pointfree code (I hate naming function parameters and names for lambda binders) so some currying and composition would be nice. |
This comment has been minimized.
This comment has been minimized.
OvermindDL1
commented
Mar 19, 2018
•
Sorry, I just have a bit of a thing against it from having to maintain some other people's Haskell code... ^.^;
More ergonomic perhaps, but that also means that the user has to learn those operators, which is still more overhead compared to nice and descriptive names. I do some teaching of programming in real life so I may be biased to well descriptive function names instead of non-descriptive operators though as it really helps the teaching process.
What @durka said is just one of those ambiguities that can pop up that I mentioned, in the C++ world there are even more issues (yay templates...).
Sounds like you'd prefer Haskell then, I significantly prefer readable code (and no, horror's like Ruby are not readable, though I tend to find most OCaml code readable unlike Haskell code, I.E. newbies in my classes can actually read OCaml code and understand most of it without needing to learn the language, unlike Haskell, which at times looks perl'y in its line-noiseness in the 'common standard' code, which yes includes Also as for this part of:
That implies that you don't maintain the code in the long term. Proper names significantly, like amazingly significantly improves maintainability. |
This comment has been minimized.
This comment has been minimized.
Operators should be introduced with care and not whilly nilly, but most experienced Haskell programmers instantly recognize the meaning of My time as a TA showed me that students had a hard time understanding Java and that descriptive function names were the least of their problems.
Again; this is your judgement that Haskell has unreadable code - I don't agree with this at all. Signal to noise ratio in Haskell is pretty minimal. Also, I'm perfectly capable of liking more than one language. My preference is towards correctness, polymorphism and strong type systems, so naturally I gravitate towards languages like Rust, Haskell, and Idris. Syntactically I prefer Haskell, yes, - but Rust's syntax OK and not more important to me than the very nice semantic properties of Rust (zero cost abstractions, low latency, performance, no runtime, ..).
I take just the opposite view; OCaml is utterly unreadable for me... but I believe this is just about what you are used too... People who are used to C style syntax will think that python and Haskell is unreadable. I don't think you can draw any general conclusions about this other than conclusions about the person making these claims. With this said; hopefully we can get back on topic (and sorry for being a bit hypocritical..) ^,- |
This comment has been minimized.
This comment has been minimized.
burdges
commented
Mar 19, 2018
|
As an aside, I've never used lens in Haskell, but my impression is lens mostly makes up for the lack of mutability, so rust does not obviously need anything like that. I'll therefore conjecture that a curried language built on Rust, or even an ML, does not benefit nearly as much from lenses as Haskell. I think similar claims can be made about many other operators in Haskell, like monads being replaced with a more detailed effects system in newer languages. I therefore doubt Rust would even suffer the same flavor of operator explosion as Haskell, although entirely new flavors might be possible or worse. As I said upthread #2049 (comment) there is probably too much strangeness budget cost in making a bunch of new operators that do basically what If otoh you want to allow unicode then maybe we can have an actual function composition operator |
This comment has been minimized.
This comment has been minimized.
OvermindDL1
commented
Mar 19, 2018
As do I, but that does not make it easier than well named functions as you still have to remember precedence and all.
Actually back when we still taught Java here (thankfully not anymore!) I found the difficult part was not the naming but rather the intense and overwhelming verbosity to get, well, anything done, and that was primarily a (standard) library issue, not necessarily an issue with the language (though the overwhelming OOP'ness of the language design definitely made a lot of things more verbose then it would be in other better languages).
I find the general OCaml ecosystem (which 'tends' to eschew operator-explosion, generally just using
Heh, I quite enjoy it, plus it is still kind of on topic here, the pipeline operator is easily one of the best operators to come out of any language (and is why it is being added to so many languages as well), far far more used than even the mathematical operators as it makes code easier to read, use, and maintain. :-)
Eh, lens's have other features in that it is easier to pass around 'what' to do instead of just how, but with trivial lambda's that's not as big of an issue either. I like lenses, but honestly I never really use them...
Oh if you want to see a good effect system, look at what's being designed for OCaml right now (OCaml is fully functional like Haskell, though with a bit more powerful of a typing system and significantly faster to compile, like really it is the fastest optimizing compiler out and compiles to within an order of C speed on fairly generic code), it is amazing looking (and for note, OCaml doesn't really use monads all over, it supports typed mutable cells like Rust does as well, though GC and not ownership model if you use them).
There are quite a few massive syntax warts I find in Rust that things like OCaml just tend to do better (though again entirely biased I do admit), that seem like things Rust took from Haskell instead of something like OCaml (OCaml's HPT's are so much more powerful, especially with implicit modules, and faster to compile, than Haskell's HKT's and typeclasses, which Rust is trying to mimic it seems sadly...). But that's all another discussion and not much can be done about it now that Rust has some of those syntax warts pretty permanently baked in.
Not just ML-style modules, but look at OCaml modules specifically, they are full Higher Polymorphic types, which are significantly more powerful and better able to represent concepts than standard ML modules or most things in Haskell with it's ton of nonstandard type extensions in GHC's case. :-) |
This comment has been minimized.
This comment has been minimized.
It can be used that way, and that mostly only describes https://hackage.haskell.org/package/lens-4.15.1/docs/Control-Lens-Setter.html#g:5 , but you can do so much more with Lens. The normEvery :: (Monad m, Data s, Typeable a, Data a)
=> (a -> m a) -> s -> m s
normEvery = transformMOnOf biplate uniplatehttps://github.com/DATX02-17-26/DATX02-17-26/blob/dev/libsrc/Norm/NormM.hs#L366 -- | Flatten blocks
execFlattenBlock :: NormCUA
execFlattenBlock = normEvery $ \case
Block stmts -> fmap Block $ flip traverseJ stmts $ \case
SBlock (Block ss) -> change ss
s -> unique [s]
x -> unique xhttps://github.com/DATX02-17-26/DATX02-17-26/blob/dev/libsrc/Norm/ElimRedundant.hs Prisms on the other hand allow you to take any sum type and extract out the contents of any variant to
Monad transformers are not bad -- as I understand it, they are more flexible than Idris' algebraic effects. They also allow you to compose things in different ways - the fact that things do not always commute with monad transformers is not always a bad thing. I think Idris has an effect system due/thanks to dependent types tho, but Idris also has monads.
Hopefully we would not need a bunch, just
FP research on top of MIR would be great; Building Haskell's runtime in Rust is also something I'd like to do one day.
I never had this problem... I use operators in such a way (and they have a fixity in such a way) that I run into precedence issues very seldom.
The verbosity is/was a very big problem especially pre lambdas in Java 8, and that was due to language features - not library features. But other big problem students faced were arrays, pointers, and mutability. I think pure functions are easier to teach since it is closer to the mathematics computer science students already learned in discrete maths and such.
It's not so much about short code as it is about pointfree code - I find that Haskellers just love composition and think in those terms -- and we use a small toolkit of infix operators to facilitate this.
Are you referring to the 1ML paper here? AFAIK OCaml does not have dependent types which Haskell does (to some extent - and more is being worked on..) but I could be wrong.
My only note here is that practically speaking, standardization of Haskell does not matter and GHC == Haskell is in practice true -- so the "nonstandard" extensions are essentially standard for Haskell programmers. The language I'm being most impressed with these days is Idris. On a separate not I think Rust could gain an effects system at least in part for |
This comment has been minimized.
This comment has been minimized.
OvermindDL1
commented
Mar 19, 2018
It is a habit thing, and I don't habitually use Haskell enough for it to become engrained as I generally just use it to maintain things and not write new in it, but this is a definite friction point when you don't live Haskell.
That really was such a nice feature they added in J8! It needed it long before (honestly in a different way internally, but eh), but we'd dropped Java here as something to teach back in the J6 era. ^.^;
But for most people this makes the code exceptionally hard to read, especially when teaching. Point-free coding is a section we've used here (though in OCaml instead but the syntax was similar enough to Haskell) and 99% of students always preferred the code that was actually readable, even if longer. It requires them to hold less 'state' in their head at a given time (and yes that is something you have to exercise to get good at, and even then it does not gain enough to be worth it in my couple-decades of experience).
Ooo? Something to read? Linkie please? :-)
It does not, that is one feature that I would quite like, although there are languages with dependent and refined types that do compile 'to' OCaml (OCaml is such a bliss of a language to both compile from it to other things as well as compile 'to' it). Honestly I'd love an OCaml'y language, with implicit modules and algebraic effects and an ownership system with tracked lifetimes, throw in dependent types (preferably in a way that does not impact compile time, one thing I really exceptionally love about OCaml is how blazing fast it compiles, unlike smaller Haskell code I have to maintain that takes ~20m to compile compared to much larger OCaml code that compiles in a couple of seconds and it executes far faster), that would be bliss. Rust is a nice balance between my C++ and ML worlds though, but it is getting too many Haskell'isms in it that I quite think is hurting the syntax and it is soooo dreadfully slow to compile at times like C++/Haskell...
True in 'general' but we didn't use GHC here the few times we show other languages like Haskell (not my choice, I would have used GHC, but you know colleges...).
It does look quite nice, though is also quite slow to compile. I've been playing with making a codegen backend to compile it to the BEAM VM lately actually. :-)
+1 I don't think it should have full unbounded continuations that are really required for a 'proper' full effect system due to their fairly tremendous runtime costs compared to pure native code, but you can get 95% of the way to full effects while keeping native speed by using delimited continuations ala MC-OCaml or many Lisps. You can get fast unbounded continuations if you don't mind hoisting some of the work to the user though, but definitely not as easy to use then. |
This comment has been minimized.
This comment has been minimized.
I think that holds in the reverse too. I find that once you live in Haskell (and use pointfree code) you get friction when you try to use other things.. It's the old "once you got nice things, you don't want to give them up".
This is strange... as pointfree code has less points (variable bindings) to pass around, and so it should have less state? For me
Here you go: https://people.mpi-sws.org/~rossberg/1ml/
That does not sound realistic given that dependent types allow you to do more computations at compile time ^,-
I think part of the problem is that laziness seemed like a nice idea but makes it very hard to reason about performance... However, I'd like to note that you usually don't compile Haskell code until you actually want to deploy - I usually only live in
That's the university's fault :P At Chalmers University of Technology (AKA "Church of Haskell", and where Agda was invented) Haskell is the first course the computer engineering programme uses and it is also taught in one of the most appreciated courses for the IT students.
I had thought of compiling Haskell Core to BEAM VM as my masters thesis incidentally =P |
This comment has been minimized.
This comment has been minimized.
OvermindDL1
commented
Mar 19, 2018
For actively using it yes, but not everyone uses exclusively one language, or even uses it all that often (I touch Haskell to keep certain things updated only a couple times a year at most). And that still ignores the learnability part and later maintainability of the lack of descriptiveness.
Less 'program' state, but not mental state, it requires you more to worry about the types and how they are being combined and transformed as it goes back and forth across the operators, where a simple pipeline is trivial, especially in comparison. This makes languages a LOT harder to learn for students as well as still requiring more work for those that do even know it. In a pipeline you only have to worry about how types transform from one pipe to the next, where in full point free you have to see how they combine what new types return from those combinations, how they get called (if not just outright curried) and more and more.
Awesome, added to my list, thanks! You might be curious in seeing how the multi-core/effectful OCaml is being implemented as well as they've tried to taking everything learned thus far from elsewhere to implement something that compiles to exceedingly efficient code, while remaining blazing fast to compile and still able to handle the 95%+ of effects that are needed, it is quite a fascinating implementation, compared to most other languages that incur a massive speed hit either at runtime, compiletime, or usually both (GHC likes to have both I've noticed, they are very thunk-friendly...).
Even then it still takes a lot more than the split second an OCaml incremental compile takes (either by calling the compiler or recompiling via the REPL), especially when heavy HKT usage is around.
Where here it is generally starting with either SML and C both, or Python (depending on if you are coming from the engineering or business sides respectively), before proceeding to more languages.
You so should! That'd get my Idris->BEAM-VM magically done for me via Haskell translation! ^.^ |
This comment has been minimized.
This comment has been minimized.
|
Trying to get back to the topic at hand... Honest question: When is this better for a function that wouldn't just have been defined as a method in Rust in the first place? Everything here so far has either been something that's a method already or a nonsense name like API design as a whole seems to be moving heavily towards "almost always a method", like how even symmetric things like And one can always add an extension trait to let you call things method-style if you want: trait Methodize: Sized {
fn methodize<F, R>(self, f: F) -> R
where F: FnOnce(Self) -> R
{
f(self)
}
}
impl<T> Methodize for T {}
fn main() {
println!("{:?}", (1).methodize(std::iter::repeat));
println!("{:?}", (1).methodize(|x| 9 - x));
} |
This comment has been minimized.
This comment has been minimized.
|
@scottmcm Extension traits for just a method to get method call syntax is a pain compared to just writing the function and then using |
This comment has been minimized.
This comment has been minimized.
So the problem is "It's too annoying to make extension methods", not "I want to call free functions with pipe syntax instead of using methods"?
That has its advantages and disadvantages. For example, it would lead to
All iterators are intoiterator, so the extension trait could have just been on IntoIterator instead the whole time. I don't know why it isn't, or whether that would actually be better, but it totally works: trait IntoIteratorTools: IntoIterator {
fn my_sum1(self) -> Option<Self::Item>
where Self: Sized, Self::Item: std::ops::AddAssign
{
let mut it = self.into_iter();
let mut sum = it.next()?;
for x in it {
sum += x;
}
Some(sum)
}
}
impl<T: IntoIterator> IntoIteratorTools for T {}
fn main() {
let v = vec![1, 2, 3];
println!("{:?}", v.my_sum1());
let i: Box<Iterator<Item = i32>> = Box::new(0..10);
println!("{:?}", i.my_sum1());
} |
This comment has been minimized.
This comment has been minimized.
TedDriggs
commented
Mar 20, 2018
I'm not sure I'd go that far. Having extension trait wrappers all over the place would be a high barrier to entry for someone trying to preserve the reading order of a set of function calls. |
This comment has been minimized.
This comment has been minimized.
I60R
commented
May 9, 2018
|
(already proposed that on internals) Non-associated function to be called on value with let result = x
.sum(in) // Called on `x`
.abs(in) // Called on resut of `sum`
.sqrt(in) // ...
.round(in, 2); // Other arguments allowed return collection.iter()
.apply_mapping_combinators(in)
.apply_logging_combinators(in)
.collect();Borrowing and copying should work like this: return Type::builder()
.apply_common_settings(&mut in) // To mutably borrow builder.
.build(); long_name_binding
.borrowed(&in, &in); // That's allowed for all types. long_name_binding
.copied(in, in); // That's allowed only if `Copy` is implemented.Alternative placeholders might be: |
This comment has been minimized.
This comment has been minimized.
eedahl
commented
May 24, 2018
•
|
@I60R That looks pretty clean to me. Is there a nice way to handle cases where a function might return a result, a tuple, etc.? With pattern matching you could do stuff like By the way, Rust does already use |
This comment has been minimized.
This comment has been minimized.
I60R
commented
May 24, 2018
|
@eedahl you can use However things like Syntax with |
This comment has been minimized.
This comment has been minimized.
If one needs to write out the whole thing I agree, but one could instead imagine adding a feature such that |
andrewmarx commentedJun 27, 2017
Something I've seen elsewhere is the concept of piping data to functions, which can drastically increase readability in cases where someone would either use intermediate variables or call functions as parameters.
Pseudocode for a contrived example:
The %>% operator is just an example (from R), it could be something else
I'm just learning rust, and know nothing about language development, so the complexities involved might make this impractical. At the same time, it would also be really interesting to see how something like this could be incorporated to work with tuples and multiple return values.