Skip to content

Added lift2 and Functor/Applicative/Monad implementations for Result#2

Open
aoprisan wants to merge 16 commits into
kitfre:masterfrom
aoprisan:master
Open

Added lift2 and Functor/Applicative/Monad implementations for Result#2
aoprisan wants to merge 16 commits into
kitfre:masterfrom
aoprisan:master

Conversation

@aoprisan
Copy link
Copy Markdown

I had to restrict the error type (E) to implement Copy, I kind of rushed a bit but I didn't knew exactly how to do it otherwise (I started checking Rust relatively recently).

@mgattozzi
Copy link
Copy Markdown

The Copy trait works fine for things that implement it like numbers but will fail on things like String. Error types usually don't have the Copy restriction for their Trait. In fact Error itself is a trait you should use this as a restriction and then allow the user to choose what to return as an error! (Usually some type of enum or struct implementing it)
Here's an example from one of my libraries and how I implemented Error for my API. I'd be happy to help out if you need it.

@kitfre
Copy link
Copy Markdown
Owner

kitfre commented Sep 20, 2016

Overall, I really like what you've done, thanks! But as mgattozi has said, I'm a bit hesitant to merge with Result errors needing the Copy trait. As soon as that is cleaned up a bit, I'll definitely merge this to master. mgattozi is right that Error is a trait, so perhaps you could require E: Error, instead of E: Copy, or I'm sure there are other fixes. Again, thanks!

@kitfre kitfre closed this Sep 20, 2016
@aoprisan
Copy link
Copy Markdown
Author

Thanks for your input. The reason why I added the Copy restrictions if the fact that I think I need a way to take the current error which I get by reference and pass it to the Err constructor which expect a parameter by value (passing the ownership). In case of the Ok(_) branch, we have the passed in function which takes a &B and returns a A. To exemplify in case of functor:

 match *self {
            Ok(ref x) => Ok(f(x)),
            Err(ref e) => Err(*e),
 }

Error doesn't seem to help here. I would have let the E type free of any constraints, but I don't see how to get a E from &E.

@mgattozzi
Copy link
Copy Markdown

Perhaps the From trait? I'm not really sure of the answer off the top of my
head.

On Tue, Sep 20, 2016, 13:33 Andrei Oprisan notifications@github.com wrote:

Thanks for your input. The reason why I added the Copy restrictions if the
fact that I think I need a way to take the current error which I get by
reference and pass it to the Err constructor which expect a parameter by
value (passing the ownership). In case of the Ok(_) branch, we have the
passed in function which takes a &B and returns a A. To exemplify in case
of functor:

match _self {
Ok(ref x) => Ok(f(x)),
Err(ref e) => Err(_e),
}

Error doesn't seem to help here. I would have let the E type free of any
constraints, but I don't see how to get a E from &E.


You are receiving this because you commented.
Reply to this email directly, view it on GitHub
#2 (comment), or mute
the thread
https://github.com/notifications/unsubscribe-auth/ADWgHyYZ1p53-5GHVbSKRopHonoBf7F7ks5qsBjwgaJpZM4KBU_Z
.

@aoprisan
Copy link
Copy Markdown
Author

I apologize if I missed something obvious, but I can't see how From would help me. What I mean is that I get a reference to the error and I need its value to pass it to Err(_).

@mgattozzi
Copy link
Copy Markdown

I think I was wrong here. Try with the Error trait and see if that works. I think it should.

Merge remote-tracking branch 'upstream/master'
@aoprisan
Copy link
Copy Markdown
Author

I am afraid it doesn't, I have the same issue cannot move out of borrowed content. Clone would help, but I am sure how much better is that than Copy.

@mgattozzi
Copy link
Copy Markdown

Without seeing all the code I can't really do much to help. You shouldn't have to use clone either. It's even more resource usage than copy and still too restrictive..

@aoprisan
Copy link
Copy Markdown
Author

aoprisan commented Sep 21, 2016

If you have time, have a look here: https://github.com/aoprisan/Kinder/blob/master/src/functor.rs#L32 . It's the same situation in case of Monad/Applicative. I can even paste it here, it's quite short:

impl<A, B, E : Clone> Functor<A> for Result<B, E> {
    fn fmap<F>(&self, f: F) -> Result<A, E>
        where F: Fn(&B) -> A
    {
        match *self {
            Ok(ref x) => Ok(f(x)),
            Err(ref e) => Err(e.clone()),
        }
    }
}

To me the above it kind of makes sense, I mean fmap is creating a new Result from a reference of the original result. In case of Ok, a fresh B is created by f, while in case of Err, I need to create a new one as the Result fmap is called on (self) should stay intact. In the stdlib, map over Result takes self and not &self, therefore no need for Clone/Copy, as ownership is passed.

Merge remote-tracking branch 'upstream/master'
Merge remote-tracking branch 'upstream/master'
Merge remote-tracking branch 'upstream/master'
@kitfre kitfre reopened this Oct 4, 2016
@kitfre
Copy link
Copy Markdown
Owner

kitfre commented Oct 4, 2016

I want to revisit this issue. As it stands, it is necessary for E to implement Clone based on the type of f: Fn(&B) -> A. It needs to take ownership of the error, which leaves us with stipulating that the Error implement Clone. That being said, I do not know how I feel about Result being a functor, etc. I propose that it be lifted into something more along the lines of profunctor. This would allow us to more naturally map over either the Ok, the Error, or both. What do you think?

@mgattozzi
Copy link
Copy Markdown

Given that Either is a Functor I would expect Result to be the same. However, given the issues inherent with Clone I would say Profunctor is probably a better fit here if we need to get it to work properly.

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

Successfully merging this pull request may close these issues.

3 participants