Reason: Special case `>>=` to be pretty printed in a specific way

Created on 18 Jan 2017  路  14Comments  路  Source: reasonml/reason

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.

FEATURE REQUEST Printer

Most helpful comment

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?

All 14 comments

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
Was this page helpful?
0 / 5 - 0 ratings

Related issues

bloodyowl picture bloodyowl  路  3Comments

rickyvetter picture rickyvetter  路  4Comments

modlfo picture modlfo  路  4Comments

gustavopinto picture gustavopinto  路  3Comments

cristianoc picture cristianoc  路  4Comments