It'd be really nice to have >>= pretty printed in a special way
Maybe like
let a =
data1 >>= fun data2 =>
do_something_async data2 >>= fun data3 =>
do_something_async_again data3 >>= fun data4 =>
return data4
Or like
let a =
data1
>>= fun data2 => do_something_async data2
>>= fun data3 => do_something_async_again data3
>>= fun data4 => return data4
The idea is to have one line per nested anonymous function. I think this would encourage the usage of >>=, which could be a good thing.
Great idea!
I like the second example better.
(Edited: first example also has its pros)
Probably good to include >|= and >>| in that format as well.
Regarding which example is better - it kind of depends on how long each expression between the binds ends up being. If it's multiple lines then the first example make for cleaner code in my experience.
let a =
data1
>>= ((data2) => do_something_async(data2))
>>= ((data3) => do_something_async_again(data3))
>>= ((data4) => return(data4));
Fixed in master. Beautiful
This still has some issues with latest master:
let _ =
get_a()
>>= (
(a) =>
get_b()
>>= (
(b) =>
get_c()
>>= (
(c) =>
return({
a,
b,
c
})
)
)
);
@hcarty you forgot parens around the lambdas
That's intentional as I don't want parens around them - I need to use a, b and c in the final result.
@chenglou In the example you posted, the final return doesn't have data2 or data3 in scope. They could be passed along manually as a tuple but that gets to be painful and easy to mess up when you get up to dataInsertLargerNumberHere and the values are used to build a record, for example.
Isn't @hcarty 's example basically do notation ala Haskell? I feel like I remember seeing a PPX sort of thing for that, but I could just be making stuff up.
Like:
let main = do
a <- get_a ()
b <- get_b ()
c <- get_c ()
return ( a, b, c )
I don't know if we'd wanna add some sort of sugar for that like Haskell or just fix the formatting, but I could see an argument for it. do notation, or something similar gives a more imperative look to monadic code which might be easier for newcomers. I imagine a lot of JS developers have seen do in other languages before (ruby comes to mind), so I don't think it'll be too much, and I also imagine most newcomers won't be diving too hard into monads right off the bat. I could be wrong though.
Also, I believe this could be done as an applicative functor. I'm not sure what type get_a, etc returns, but I'll just demonstrate in Haskell's Maybe:
Just (\a b c -> return (a, b, c)) <*> get_a () <*> get_b () <*> get_c ()
Should return the same result... Although I don't think applicatives are in the std lib of OCaml/Reason.
One benefit of >>= is that it's a normal value. It must be defined/aliased or brought into scope via open/include.
There could be a convention for Reason regarding how to pick the module to use inside of a do block but it requires some extra understanding of selection criteria that a vanilla operator does not.
@hcarty given that there's semantic differences, I think there should still be indentation. OCaml's habit of obscuring function scope by having a ton of things at the same level of indentation has always bothered me
Indentation per >>= makes this kind of use-case effectively unusable with Reason's current syntax. Keeping >>= at even levels of indentation is like having a sequence of let bindings at the same indentation level.
OCaml's habit of obscuring function scope by having a ton of things at the same level of indentation has always bothered me
I've always written ocaml so that 'lower lines' are 'deeper in scope' and I only nest further right when there are possible branches or sub-definitions (like inline functions or so). How is that obscured?
For another concrete example, this can also affect things like logging:
Logs_lwt.info (fun m -> m "This is some info") >>= fun () ->
Logs_lwt.debug (fun m -> m "Imagine something happened") >>= fun () ->
Logs_lwt.warn (fun m -> m "This may be important") >>= fun () ->
Lwt.return_unit
Most helpful comment
I've always written ocaml so that 'lower lines' are 'deeper in scope' and I only nest further right when there are possible branches or sub-definitions (like inline functions or so). How is that obscured?