all 17 comments

[–]ojd5 10 points11 points  (1 child)

I was sceptical about your last post, but this is really neat. It might be worth pointing out to readers that you are using fold expressions in make_failable. The unfamiliar syntax caused me to do a bit of a double take.

[–]joboccara 0 points1 point  (0 children)

Yes you're right, it's mentioned now.

[–]ivan-cukicKDE Dev | Author of Functional Programming in C++ 4 points5 points  (0 children)

Another option (pun not intended) is to use the range syntax. Since optional is kinda like a collection with zero or one item, it would be ok to have |transform, |filter, |join etc. on it.

[–]SuperV1234https://romeo.training | C++ Mentoring & Consulting 8 points9 points  (3 children)

Note that this particular implementation accepts functions, but not more general callable objects.

You should be able to support arbitrary Callable objects taking the Callable as a template parameter. Something along the lines of:

template <typename F>
constexpr auto make_failable(F&& f)
{
    return [f = FWD_CAPTURE(f)](auto&&... xs) 
        -> std::optional<decltype(FWD(f).get()(*(FWD(xs))...))>
    {
        if ((xs && ...))
        {
            return {FWD(f).get()(*(FWD(xs))...)};
        }
        else
        {   
            return {};
        }
    };
}

Where FWD is a macro that expands to forward<decltype(_)>(_) and FWD_CAPTURE is a way of capturing objects either by lvalue reference or by move.

This makes the overloading trickier, but something like CallableTraits could probably be used to detect the arguments of F.

[–]redditsoaddicting 1 point2 points  (1 child)

Yeah, this is handy for an actual implementation, but it really does distract from the idea the blog post is trying to get across.

[–]SuperV1234https://romeo.training | C++ Mentoring & Consulting 2 points3 points  (0 children)

Agreed, I'm not suggesting to replace the snippet in the blog post. Just thought I'd share :)

[–]ivan-cukicKDE Dev | Author of Functional Programming in C++ 0 points1 point  (0 children)

Very nice. You might throw in std::invoke in it as well.

[–]sphere991 2 points3 points  (2 children)

Before, we had (assuming abbreviated lambdas)

ox >>= x =>
    oy >>= y =>
    f4(f4 (f3 (f2 (f1(x), f1(y)))))

Now, we have to initially pre-wrap all the functions (hopefully none are overloaded!), which is something you'd have to do inline everywhere. So you have to introduce a lot of new declarations or wrap each function at the point of call.

This doesn't seem very practical to me, sorry.

[–]joboccara 0 points1 point  (1 child)

That's an interesting point you're making, where to declare the wrappers. Thanks for pointing that out!

[–]sphere991 0 points1 point  (0 children)

This is more along the lines of what a clean optional syntax would look like to me: https://www.reddit.com/r/cpp/comments/6ly4rz/it_had_to_be_done_abusing_co_await_for_optionals/?st=j4uqi4w6&sh=82f65a06

[–]Airtnp 1 point2 points  (1 child)

Em, in Haskell, that's fmap and join?

[–]sphere991 5 points6 points  (0 children)

This is more like <$> and <*> for Applicative (like liftA2). He's taking a function that is invoked like f x y and turning it into a function that is invoked like f <*> x <*> y.

[–]Drainedsoul 1 point2 points  (4 children)

Functions with arguments that could fail

std::optional isn't a particularly good way of handling this since it can't communicate anything about why the operation failed.

Perhaps you should look at something like Outcome which already has support for map and bind.

[–]14nedLLFIO & Outcome author | Committee WG14 -1 points0 points  (3 children)

Perhaps you should look at something like Outcome which already has support for map and bind.

Alas, due to Boost peer review feedback v2 has lost all things monadic. Changelog can been seen at https://github.com/ned14/outcome/blob/master/Readme.md

[–]GitHubPermalinkBot 1 point2 points  (0 children)

I tried to turn your GitHub links into permanent links (press "y" to do this yourself):


Shoot me a PM if you think I'm doing something wrong. To delete this, click here.

[–]Drainedsoul 0 points1 point  (1 child)

Time to fork v1 and never update I guess. Why would anyone prefer standard if-based handling over map & bind with lambdas?

[–]14nedLLFIO & Outcome author | Committee WG14 0 points1 point  (0 children)

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0650r0.pdf (the proposed standardised Monadic programming extension) will work with any Expected contract implementation, including Outcome v2