Loading ...
Sorry, an error occurred while loading the content.

Re: "ocaml_beginners"::[] Coding style: let vs and

Expand Messages
  • Gabriel Scherer
    My (admittedly unjustified) personal style is to use let .. in , except for mutual recursive bindings let rec .. and .. . I m not fond of using let..and
    Message 1 of 13 , Feb 15 8:09 AM
    • 0 Attachment
      My (admittedly unjustified) personal style is to use "let .. in",
      except for mutual recursive bindings "let rec .. and ..". I'm not fond
      of using let..and directly as it adds an uncertainty on evaluation
      effect order, and -- to me -- suggest mutual dependency rather than
      non-dependency. For short, clearly effect-free bindings, I actually
      write "let x,y = foo,bar" rather than "let x = foo and y = bar".

      For the evaluation-order effect, consider this `map` function on binary trees:

      let rec map f= function
      | Leaf -> Leaf
      | Branch(a, x, b) ->
      let fa = map f a and fb = map f b in
      Branch(fa, f x, fb)

      This definition has the downside that `f` is applied in a fairly
      unpredictable, unspecified and unsatisfying order. While I don't want
      to encourage users into using `map` with weird effectful functions
      relying on evaluation order, I found it to be less painful for both me
      and them if their evil trickeries will actually work in the way they
      expect (left to right), so that they don't talk to me about it, ever.

      let rec map f = function
      | Leaf -> Leaf
      | Branch (a, x, b) ->
      let fa = map f a in
      let fx = f x in
      let fb = map f b in
      Branch(fa, fx, fb)

      One unusual situation where "let..and" is useful is when producing
      code mechanically, for example when writing a Camlp4 extension.
      Imagine I wanted to write a code-transforming function that would
      transform NORM2(foo,bar) into `foo * foo + bar * bar`. To avoid effect
      duplication, I actually want to produce `let x = <foo> and y = <bar>
      in x * x + y * y`. By using `let x = <foo> in let y = <bar> in`, I
      would expose myself to variable capture problems; I can have hygiene
      with "let..and" without using gensyms -- the idea is just to
      immediately bind all user-produced pieces of code at the beginning of
      my expansion, under no additional scope; this can be done even when I
      want to delay side-effects, by writing `let x () = <foo> and ...`
      instead.

      On Wed, Feb 15, 2012 at 4:18 PM, Lukasz Stafiniak <lukstafi@...> wrote:
      > On Wed, Feb 15, 2012 at 4:10 PM, Boris Hollas
      > <hollas@...-dresden.de> wrote:
      >> Hello,
      >>
      >> I often see code such as
      >>
      >>    let typ = unrollType v.vtype in
      >>    let loc = v.vdecl in
      >>
      >> Would it be better to write "and" for the second binding?
      >
      > I second the question. The rule of parsimony says that we should use
      > as many "and"s as logically possible so that the dependencies between
      > data are evident. But I almost never use "and" (outside of mutual
      > recursion) in my code... Probably to make the code more homogeneous,
      > then it is easier "for the eye" and easier to manipulate.
      >
      >
      > ------------------------------------
      >
      > Archives up to December 31, 2011 are also downloadable at http://www.connettivo.net/cntprojects/ocaml_beginners
      > The archives of the very official ocaml list (the seniors' one) can be found at http://caml.inria.fr
      > Attachments are banned and you're asked to be polite, avoid flames etc.Yahoo! Groups Links
      >
      >
      >
    • Rajat Khanduja
      I use let .. and pretty often but it is when the order of evaluation is of little importance. For instance, I choose let x = a and y = b instead of let x,y =
      Message 2 of 13 , Feb 15 11:18 AM
      • 0 Attachment
        I use let .. and pretty often but it is when the order of evaluation is of
        little importance.

        For instance, I choose let x = a and y = b instead of let x,y = a,b or let
        x = a in let y = b.

        I have the tendency to relate "let x,y = a,b" with tuples and probably that
        is the reason I avoid using this and I try to use let .. in only in case of
        some dependency.

        Sincerely

        Rajat

        On Wed, Feb 15, 2012 at 9:39 PM, Gabriel Scherer
        <gabriel.scherer@...>wrote:

        > **
        >
        >
        > My (admittedly unjustified) personal style is to use "let .. in",
        > except for mutual recursive bindings "let rec .. and ..". I'm not fond
        > of using let..and directly as it adds an uncertainty on evaluation
        > effect order, and -- to me -- suggest mutual dependency rather than
        > non-dependency. For short, clearly effect-free bindings, I actually
        > write "let x,y = foo,bar" rather than "let x = foo and y = bar".
        >
        > For the evaluation-order effect, consider this `map` function on binary
        > trees:
        >
        > let rec map f= function
        > | Leaf -> Leaf
        > | Branch(a, x, b) ->
        > let fa = map f a and fb = map f b in
        > Branch(fa, f x, fb)
        >
        > This definition has the downside that `f` is applied in a fairly
        > unpredictable, unspecified and unsatisfying order. While I don't want
        > to encourage users into using `map` with weird effectful functions
        > relying on evaluation order, I found it to be less painful for both me
        > and them if their evil trickeries will actually work in the way they
        > expect (left to right), so that they don't talk to me about it, ever.
        >
        > let rec map f = function
        > | Leaf -> Leaf
        > | Branch (a, x, b) ->
        > let fa = map f a in
        > let fx = f x in
        > let fb = map f b in
        > Branch(fa, fx, fb)
        >
        > One unusual situation where "let..and" is useful is when producing
        > code mechanically, for example when writing a Camlp4 extension.
        > Imagine I wanted to write a code-transforming function that would
        > transform NORM2(foo,bar) into `foo * foo + bar * bar`. To avoid effect
        > duplication, I actually want to produce `let x = <foo> and y = <bar>
        > in x * x + y * y`. By using `let x = <foo> in let y = <bar> in`, I
        > would expose myself to variable capture problems; I can have hygiene
        > with "let..and" without using gensyms -- the idea is just to
        > immediately bind all user-produced pieces of code at the beginning of
        > my expansion, under no additional scope; this can be done even when I
        > want to delay side-effects, by writing `let x () = <foo> and ...`
        > instead.
        >
        >
        > On Wed, Feb 15, 2012 at 4:18 PM, Lukasz Stafiniak <lukstafi@...>
        > wrote:
        > > On Wed, Feb 15, 2012 at 4:10 PM, Boris Hollas
        > > <hollas@...-dresden.de> wrote:
        > >> Hello,
        > >>
        > >> I often see code such as
        > >>
        > >> let typ = unrollType v.vtype in
        > >> let loc = v.vdecl in
        > >>
        > >> Would it be better to write "and" for the second binding?
        > >
        > > I second the question. The rule of parsimony says that we should use
        > > as many "and"s as logically possible so that the dependencies between
        > > data are evident. But I almost never use "and" (outside of mutual
        > > recursion) in my code... Probably to make the code more homogeneous,
        > > then it is easier "for the eye" and easier to manipulate.
        > >
        > >
        > > ------------------------------------
        >
        > >
        > > Archives up to December 31, 2011 are also downloadable at
        > http://www.connettivo.net/cntprojects/ocaml_beginners
        > > The archives of the very official ocaml list (the seniors' one) can be
        > found at http://caml.inria.fr
        > > Attachments are banned and you're asked to be polite, avoid flames
        > etc.Yahoo! Groups Links
        > >
        > >
        > >
        >
        >
        >


        [Non-text portions of this message have been removed]
      • Rajat Khanduja
        Also, I find that let..and increases readability and helps me identify relations (or absence of it) easily. And, aligning them like this :- let x = a and y =
        Message 3 of 13 , Feb 15 11:20 AM
        • 0 Attachment
          Also, I find that let..and increases readability and helps me identify
          relations (or absence of it) easily.

          And, aligning them like this :-

          let x = a
          and y = b

          also helps me maintain the indentation (again increases readability).

          On Thu, Feb 16, 2012 at 12:48 AM, Rajat Khanduja
          <rajatkhanduja13@...>wrote:

          > I use let .. and pretty often but it is when the order of evaluation is of
          > little importance.
          >
          > For instance, I choose let x = a and y = b instead of let x,y = a,b or
          > let x = a in let y = b.
          >
          > I have the tendency to relate "let x,y = a,b" with tuples and probably
          > that is the reason I avoid using this and I try to use let .. in only in
          > case of some dependency.
          >
          > Sincerely
          >
          > Rajat
          >
          >
          > On Wed, Feb 15, 2012 at 9:39 PM, Gabriel Scherer <
          > gabriel.scherer@...> wrote:
          >
          >> **
          >>
          >>
          >> My (admittedly unjustified) personal style is to use "let .. in",
          >> except for mutual recursive bindings "let rec .. and ..". I'm not fond
          >> of using let..and directly as it adds an uncertainty on evaluation
          >> effect order, and -- to me -- suggest mutual dependency rather than
          >> non-dependency. For short, clearly effect-free bindings, I actually
          >> write "let x,y = foo,bar" rather than "let x = foo and y = bar".
          >>
          >> For the evaluation-order effect, consider this `map` function on binary
          >> trees:
          >>
          >> let rec map f= function
          >> | Leaf -> Leaf
          >> | Branch(a, x, b) ->
          >> let fa = map f a and fb = map f b in
          >> Branch(fa, f x, fb)
          >>
          >> This definition has the downside that `f` is applied in a fairly
          >> unpredictable, unspecified and unsatisfying order. While I don't want
          >> to encourage users into using `map` with weird effectful functions
          >> relying on evaluation order, I found it to be less painful for both me
          >> and them if their evil trickeries will actually work in the way they
          >> expect (left to right), so that they don't talk to me about it, ever.
          >>
          >> let rec map f = function
          >> | Leaf -> Leaf
          >> | Branch (a, x, b) ->
          >> let fa = map f a in
          >> let fx = f x in
          >> let fb = map f b in
          >> Branch(fa, fx, fb)
          >>
          >> One unusual situation where "let..and" is useful is when producing
          >> code mechanically, for example when writing a Camlp4 extension.
          >> Imagine I wanted to write a code-transforming function that would
          >> transform NORM2(foo,bar) into `foo * foo + bar * bar`. To avoid effect
          >> duplication, I actually want to produce `let x = <foo> and y = <bar>
          >> in x * x + y * y`. By using `let x = <foo> in let y = <bar> in`, I
          >> would expose myself to variable capture problems; I can have hygiene
          >> with "let..and" without using gensyms -- the idea is just to
          >> immediately bind all user-produced pieces of code at the beginning of
          >> my expansion, under no additional scope; this can be done even when I
          >> want to delay side-effects, by writing `let x () = <foo> and ...`
          >> instead.
          >>
          >>
          >> On Wed, Feb 15, 2012 at 4:18 PM, Lukasz Stafiniak <lukstafi@...>
          >> wrote:
          >> > On Wed, Feb 15, 2012 at 4:10 PM, Boris Hollas
          >> > <hollas@...-dresden.de> wrote:
          >> >> Hello,
          >> >>
          >> >> I often see code such as
          >> >>
          >> >> let typ = unrollType v.vtype in
          >> >> let loc = v.vdecl in
          >> >>
          >> >> Would it be better to write "and" for the second binding?
          >> >
          >> > I second the question. The rule of parsimony says that we should use
          >> > as many "and"s as logically possible so that the dependencies between
          >> > data are evident. But I almost never use "and" (outside of mutual
          >> > recursion) in my code... Probably to make the code more homogeneous,
          >> > then it is easier "for the eye" and easier to manipulate.
          >> >
          >> >
          >> > ------------------------------------
          >>
          >> >
          >> > Archives up to December 31, 2011 are also downloadable at
          >> http://www.connettivo.net/cntprojects/ocaml_beginners
          >> > The archives of the very official ocaml list (the seniors' one) can be
          >> found at http://caml.inria.fr
          >> > Attachments are banned and you're asked to be polite, avoid flames
          >> etc.Yahoo! Groups Links
          >> >
          >> >
          >> >
          >>
          >>
          >>
          >
          >


          [Non-text portions of this message have been removed]
        • Dan Bensen
          ... Most experienced OCamlers seem to prefer let...in for the default form. I don t think let/in looks any better than and , and OCaml is a functional
          Message 4 of 13 , Feb 15 3:16 PM
          • 0 Attachment
            >> let typ = unrollType v.vtype in
            >> let loc = v.vdecl in
            >> Would it be better to write "and" for the second binding?
            >
            > I second the question.... Probably to make the code more homogeneous,
            > then it is easier "for the eye" and easier to manipulate.

            Most experienced OCamlers seem to prefer "let...in" for the default form. I
            don't think let/in looks any better than "and", and OCaml is a functional
            language, so I wouldn't worry about order of evaluation too much. The main
            advantage of let/in seems to be your last point about editing the code: Every
            binding line has the same form as the first one, so you can swap them
            arbitrarily without having to change the keywords.

            [Non-text portions of this message have been removed]
          • oliver
            ... [...] The and allows mutual recursive functions. So, when using and this could be a hint to what the programmer has in mind, when using these things...
            Message 5 of 13 , Feb 15 4:15 PM
            • 0 Attachment
              On Thu, Feb 16, 2012 at 12:50:40AM +0530, Rajat Khanduja wrote:
              > Also, I find that let..and increases readability and helps me identify
              > relations (or absence of it) easily.
              [...]


              The "and" allows mutual recursive functions.

              So, when using "and" this could be a hint to what the programmer has in mind,
              when using these things... at least when defining functions.

              So I'm not clear if using "and" in general would make that distinction less
              obvious, even both works.

              If the "and" is always used, it would not give the hint to mutual recursive functions.
              One would have a deeper look at the code then, assuring that there are not
              mutual recursive functions used...
              ...when using let .. in let ... in ...
              would make it obvious that there will not be mutaual recursive functions.
              This might make reading the code more easy.

              Also I'm not sure if there are performance issues related to the both
              styles.

              Ciao,
              Oliver
            • oliver
              ... let ... in definitely restricts the order of the evaluation of the code. I m not sure if this necessarily is always the case when using and ; in principal
              Message 6 of 13 , Feb 15 4:18 PM
              • 0 Attachment
                On Wed, Feb 15, 2012 at 03:16:32PM -0800, Dan Bensen wrote:
                > >> let typ = unrollType v.vtype in
                > >> let loc = v.vdecl in
                > >> Would it be better to write "and" for the second binding?
                > >
                > > I second the question.... Probably to make the code more homogeneous,
                > > then it is easier "for the eye" and easier to manipulate.
                >
                > Most experienced OCamlers seem to prefer "let...in" for the default form. I
                > don't think let/in looks any better than "and", and OCaml is a functional
                > language, so I wouldn't worry about order of evaluation too much. The main
                > advantage of let/in seems to be your last point about editing the code: Every
                > binding line has the same form as the first one, so you can swap them
                > arbitrarily without having to change the keywords.
                >
                > [Non-text portions of this message have been removed]
                >

                let ... in

                definitely restricts the order of the evaluation of the code.

                I'm not sure if this necessarily is always the case when using "and";
                in principal it could be valid, to evaluate the later defined items
                before the former ones, because the "and" allows both definitions
                be independent of each other.


                Ciao,
                Oliver
              • danbensen@att.net
                ... Evaluation order is unspecified in let/and bindings. I was just saying the OCaml culture encourages programmers to ignore evaluation order whenever they
                Message 7 of 13 , Feb 15 6:03 PM
                • 0 Attachment
                  > > OCaml is a functional language,
                  > > so I wouldn't worry about order of evaluation
                  >
                  > let ... in definitely restricts the order of the evaluation
                  > I'm not sure if this necessarily is always the case when using "and"

                  Evaluation order is "unspecified" in let/and bindings. I was just saying the OCaml culture encourages programmers to ignore evaluation order whenever they can.
                • Boris Hollas
                  ... But this is what you told the compiler here: I don t mind how the tree is traversed, the end result is the same. If you want to enforce a dfs then
                  Message 8 of 13 , Feb 16 1:10 AM
                  • 0 Attachment
                    On Wed, 2012-02-15 at 17:09 +0100, Gabriel Scherer wrote:

                    > let rec map f= function
                    > | Leaf -> Leaf
                    > | Branch(a, x, b) ->
                    > let fa = map f a and fb = map f b in
                    > Branch(fa, f x, fb)
                    >
                    > This definition has the downside that `f` is applied in a fairly
                    > unpredictable, unspecified and unsatisfying order. While I don't want

                    But this is what you told the compiler here: I don't mind how the tree
                    is traversed, the end result is the same. If you want to enforce a dfs
                    then evaluation order matters.

                    On the other hand, does


                    > let fa = map f a in
                    > let fx = f x in
                    > let fb = map f b in
                    > Branch(fa, fx, fb)

                    guarantee that fa is evaluated before fb? The compiler might detect that
                    fa is not part of let fb = map f b, and decide that both expressions can
                    be evaluated independently. So perhaps the sequencing operator ";"
                    should be used?
                  • Boris Hollas
                    ... you d have to look for a let rec at the beginning.
                    Message 9 of 13 , Feb 16 1:14 AM
                    • 0 Attachment
                      On Thu, 2012-02-16 at 01:15 +0100, oliver wrote:
                      > If the "and" is always used, it would not give the hint to mutual
                      > recursive functions.
                      > One would have a deeper look at the code then, assuring that there are
                      > not
                      > mutual recursive functions used...

                      you'd have to look for a "let rec" at the beginning.
                    • Dan Bensen
                      ... Yes, fa, fx, and fb will always be evaluated in that order. I would call the function itermap to emphasize the ordering. ... No, bindings before in are
                      Message 10 of 13 , Feb 16 1:40 AM
                      • 0 Attachment
                        > does
                        > > let fa = map f a in
                        > > let fx = f x in
                        > > let fb = map f b in
                        > > Branch(fa, fx, fb)
                        > guarantee that fa is evaluated before fb?

                        Yes, fa, fx, and fb will always be evaluated in that order.
                        I would call the function "itermap" to emphasize the ordering.

                        > The compiler might detect that fa is not part of let fb = map f b,
                        > and decide that both expressions can be evaluated independently.

                        No, bindings before "in" are always evaluated before the expression that
                        follows.


                        [Non-text portions of this message have been removed]
                      Your message has been successfully submitted and would be delivered to recipients shortly.