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

Proably an FAQ but how to get around the problem

Expand Messages
  • Michael Erdmann
    Hallo *, i guess i have a simple problem, i found a solution but i am not convinced that this is a correct Ocaml solution. The code fragment at the end of the
    Message 1 of 7 , May 6, 2012
    • 0 Attachment
      Hallo *,

      i guess i have a simple problem, i found a solution but i am not
      convinced that this is a
      correct Ocaml solution.

      The code fragment at the end of the e-mail is part an excerpt of an
      interpreter i am
      writing for training. The function execute_command takes a command as input
      and executes the corresponding command. There is one command called
      batch which
      allows to execute complete files by reading them line by line and again
      executing the
      function execute_command. This simply does not compile since execute_command
      is unbound in the execute_file function :-((

      My current solution is to pass a function to execute_file as argument
      which is called
      instead of calling execute_command directly.

      let execute_file chan interp = .....
      let cmd = input_line chan in *interp *cmd;
      ;;

      let *execute_command* cmd args=
      | "batch" -> let chan = open_in args in execute_file chan
      execute_command

      ;;

      It works; but is this really the best solution ..... ?????

      Advise is highly welcome :-)))

      /Michael


      ...................................................
      (** some command *)
      let do_go args =
      print_endline "go ..."
      ;;

      (** read in a batch of commands from a file *)
      let execute_file chan =
      try
      while true do
      begin
      let cmd = input_line chan in *execute_command*(cmd);
      end
      done
      with x ->
      print_endline "done ****";
      ;;

      (** execute a single commmand line *)
      let *execute_command* cmd args=
      match cmd with
      "go" -> do_go(args)
      | "batch" -> let chan = open_in args in execute_file chan
      | _ -> print_endline "wrong command"
      ;;

      (** toplevel *)



      [Non-text portions of this message have been removed]
    • Gabriel Scherer
      What you need is mutual recursion: let rec execute_command = ... and execute_file = ... Working example: let rec even n = (n = 0) || odd (n - 1) and odd n = (n
      Message 2 of 7 , May 6, 2012
      • 0 Attachment
        What you need is mutual recursion:

        let rec execute_command = ...
        and execute_file = ...

        Working example:

        let rec even n = (n = 0) || odd (n - 1)
        and odd n = (n > 0) && even (n - 1)

        On Sun, May 6, 2012 at 9:52 AM, Michael Erdmann
        <erdmann-berlin@...> wrote:
        > Hallo *,
        >
        > i guess i have a simple problem, i found a solution but i am not
        > convinced that this is a
        > correct Ocaml solution.
        >
        > The code fragment at the end of the e-mail is part an excerpt of an
        > interpreter i am
        > writing for training. The function execute_command takes a command as input
        > and executes the corresponding command. There is one command called
        > batch which
        > allows to execute complete files by reading them line by line and again
        > executing the
        > function execute_command. This simply does not compile since execute_command
        > is unbound in the execute_file function :-((
        >
        > My current solution is to pass a function to execute_file as argument
        > which is called
        > instead of calling execute_command directly.
        >
        > let execute_file chan interp = .....
        >    let cmd = input_line chan in *interp *cmd;
        > ;;
        >
        > let *execute_command* cmd args=
        >        | "batch" -> let chan = open_in args in execute_file chan
        > execute_command
        >
        > ;;
        >
        > It works; but is this really the best solution ..... ?????
        >
        > Advise is highly welcome :-)))
        >
        > /Michael
        >
        >
        > ...................................................
        > (** some command *)
        > let do_go args =
        >    print_endline "go ..."
        > ;;
        >
        > (** read in a batch of commands from a file *)
        > let execute_file chan =
        >    try
        >        while true do
        >           begin
        >             let cmd = input_line chan in *execute_command*(cmd);
        >          end
        >        done
        >    with x ->
        >      print_endline "done ****";
        > ;;
        >
        > (** execute a single commmand line *)
        > let *execute_command* cmd args=
        >    match cmd with
        >            "go" -> do_go(args)
        >        | "batch" -> let chan = open_in args in execute_file chan
        >        | _ -> print_endline "wrong command"
        > ;;
        >
        > (** toplevel *)
        >
        >
        >
        > [Non-text portions of this message have been removed]
        >
        >
        >
        > ------------------------------------
        >
        > 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
        >
        >
        >
      • Michael Erdmann
        Thanxs; works fine (see below) ... but why this ..and .. construct. A two pass parsing would have declared execute_file and in the second compiler pass the
        Message 3 of 7 , May 6, 2012
        • 0 Attachment
          Thanxs; works fine (see below) ... but why this "..and .." construct. A
          two pass parsing would have
          declared execute_file and in the second compiler pass the execute_file
          would have been
          known while compiling execute_command. I guess there is an idea behind
          this??

          /Michael



          ....................... the new code ....

          open Printf;;

          (** some command *)
          let do_go args =
          print_endline "go ..."
          ;;

          let rec execute_command cmd args=
          print_endline cmd;
          match cmd with
          "go" -> do_go(args)
          | "batch" -> execute_file args
          | _ -> print_endline "unknown command"

          and execute_file name =
          let chan = open_in name in
          try
          while true do
          let cmd = input_line chan in execute_command cmd "";
          done
          with End_of_file -> close_in chan
          ;;

          (** toplevel *)

          execute_file "startup.cmd" ;;

          execute_command "batch" "startup.cmd" ;;


          On 05/06/2012 10:11 AM, Gabriel Scherer wrote:
          >
          >
          > What you need is mutual recursion:
          >
          > let rec execute_command = ...
          > and execute_file = ...
          >
          > Working example:
          >
          > let rec even n = (n = 0) || odd (n - 1)
          > and odd n = (n > 0) && even (n - 1)
          >
          > On Sun, May 6, 2012 at 9:52 AM, Michael Erdmann
          > <erdmann-berlin@... <mailto:erdmann-berlin%40t-online.de>> wrote:
          > > Hallo *,
          > >
          > > i guess i have a simple problem, i found a solution but i am not
          > > convinced that this is a
          > > correct Ocaml solution.
          > >
          > > The code fragment at the end of the e-mail is part an excerpt of an
          > > interpreter i am
          > > writing for training. The function execute_command takes a command
          > as input
          > > and executes the corresponding command. There is one command called
          > > batch which
          > > allows to execute complete files by reading them line by line and again
          > > executing the
          > > function execute_command. This simply does not compile since
          > execute_command
          > > is unbound in the execute_file function :-((
          > >
          > > My current solution is to pass a function to execute_file as argument
          > > which is called
          > > instead of calling execute_command directly.
          > >
          > > let execute_file chan interp = .....
          > > let cmd = input_line chan in *interp *cmd;
          > > ;;
          > >
          > > let *execute_command* cmd args=
          > > | "batch" -> let chan = open_in args in execute_file chan
          > > execute_command
          > >
          > > ;;
          > >
          > > It works; but is this really the best solution ..... ?????
          > >
          > > Advise is highly welcome :-)))
          > >
          > > /Michael
          > >
          > >
          > > ...................................................
          > > (** some command *)
          > > let do_go args =
          > > print_endline "go ..."
          > > ;;
          > >
          > > (** read in a batch of commands from a file *)
          > > let execute_file chan =
          > > try
          > > while true do
          > > begin
          > > let cmd = input_line chan in *execute_command*(cmd);
          > > end
          > > done
          > > with x ->
          > > print_endline "done ****";
          > > ;;
          > >
          > > (** execute a single commmand line *)
          > > let *execute_command* cmd args=
          > > match cmd with
          > > "go" -> do_go(args)
          > > | "batch" -> let chan = open_in args in execute_file chan
          > > | _ -> print_endline "wrong command"
          > > ;;
          > >
          > > (** toplevel *)
          > >
          > >
          > >
          > > [Non-text portions of this message have been removed]
          > >
          > >
          > >
          > > ------------------------------------
          > >
          > > 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]
        • Gabriel Scherer
          This is not related to parsing at all, but to how identifier references are resolved. OCaml has asimple scoping model: - in a let foo = bar , the expression
          Message 4 of 7 , May 6, 2012
          • 0 Attachment
            This is not related to parsing at all, but to how identifier references are
            resolved. OCaml has asimple scoping model:
            - in a "let foo = bar", the expression "bar" lives in the ambiant
            environment (what has been defined so far)
            - in a "let rec foo = bar", the expression "bar" lives in the ambiant
            environment *plus* the identifier "foo"
            - "and" allows to make multiple definitions simultaneously that live in the
            same environment, and are evaluated in an undefined order:
            - in "let foo = bar and baz = foobar", the expressions "bar" and
            "foobar" are evaluated in the ambiant environment
            - in "let rec foo = bar and baz = foobar", the expressions "bar" and
            "foobar" are evaluated in the same environment, which is the ambiant
            environment plus "foo" and "baz".

            Having the choice between "let" and "let rec" allows you to decide
            precisely what the scope is, including in presence of variable shadowing:
            consider "let x () = 1;; let x () = x () + 1" and "let x () = 1;; let rec x
            () = x () + 1". If the compiler tried to infer whether a definition is
            recursive or not, or which "x" was actually meant in the first example, he
            would have to make arbitrary choices that could be different from the
            programmer's wish.

            See this caml-list thread for a discussion of such issues:

            http://old.nabble.com/Examples-where-let-rec-is-undesirable-td33068691.html

            On Sun, May 6, 2012 at 11:55 AM, Michael Erdmann <erdmann-berlin@...
            > wrote:

            > **
            > Thanxs; works fine (see below) ... but why this "..and .." construct. A
            > two pass parsing would have
            > declared execute_file and in the second compiler pass the execute_file
            > would have been
            > known while compiling execute_command. I guess there is an idea behind
            > this??
            >
            > /Michael
            >
            >
            >
            > ....................... the new code ....
            >
            > open Printf;;
            >
            >
            > (** some command *)
            > let do_go args =
            > print_endline "go ..."
            > ;;
            >
            > let rec execute_command cmd args=
            > print_endline cmd;
            >
            > match cmd with
            > "go" -> do_go(args)
            > | "batch" -> execute_file args
            > | _ -> print_endline "unknown command"
            >
            > and execute_file name =
            > let chan = open_in name in
            > try
            > while true do
            > let cmd = input_line chan in execute_command cmd "";
            > done
            > with End_of_file -> close_in chan
            > ;;
            >
            > (** toplevel *)
            >
            > execute_file "startup.cmd" ;;
            >
            > execute_command "batch" "startup.cmd" ;;
            >
            >
            >
            > On 05/06/2012 10:11 AM, Gabriel Scherer wrote:
            >
            >
            >
            > What you need is mutual recursion:
            >
            > let rec execute_command = ...
            > and execute_file = ...
            >
            > Working example:
            >
            > let rec even n = (n = 0) || odd (n - 1)
            > and odd n = (n > 0) && even (n - 1)
            >
            > On Sun, May 6, 2012 at 9:52 AM, Michael Erdmann
            > <erdmann-berlin@...> wrote:
            > > Hallo *,
            > >
            > > i guess i have a simple problem, i found a solution but i am not
            > > convinced that this is a
            > > correct Ocaml solution.
            > >
            > > The code fragment at the end of the e-mail is part an excerpt of an
            > > interpreter i am
            > > writing for training. The function execute_command takes a command as
            > input
            > > and executes the corresponding command. There is one command called
            > > batch which
            > > allows to execute complete files by reading them line by line and again
            > > executing the
            > > function execute_command. This simply does not compile since
            > execute_command
            > > is unbound in the execute_file function :-((
            > >
            > > My current solution is to pass a function to execute_file as argument
            > > which is called
            > > instead of calling execute_command directly.
            > >
            > > let execute_file chan interp = .....
            > > let cmd = input_line chan in *interp *cmd;
            > > ;;
            > >
            > > let *execute_command* cmd args=
            > > | "batch" -> let chan = open_in args in execute_file chan
            > > execute_command
            > >
            > > ;;
            > >
            > > It works; but is this really the best solution ..... ?????
            > >
            > > Advise is highly welcome :-)))
            > >
            > > /Michael
            > >
            > >
            > > ...................................................
            > > (** some command *)
            > > let do_go args =
            > > print_endline "go ..."
            > > ;;
            > >
            > > (** read in a batch of commands from a file *)
            > > let execute_file chan =
            > > try
            > > while true do
            > > begin
            > > let cmd = input_line chan in *execute_command*(cmd);
            > > end
            > > done
            > > with x ->
            > > print_endline "done ****";
            > > ;;
            > >
            > > (** execute a single commmand line *)
            > > let *execute_command* cmd args=
            > > match cmd with
            > > "go" -> do_go(args)
            > > | "batch" -> let chan = open_in args in execute_file chan
            > > | _ -> print_endline "wrong command"
            > > ;;
            > >
            > > (** toplevel *)
            > >
            > >
            > >
            > > [Non-text portions of this message have been removed]
            > >
            > >
            > >
            > > ------------------------------------
            > >
            > > 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]
          • Michael Erdmann
            Thanxs; took me a while to think about during lunch; to be honest i don t feel comfortable with this scoping; e.g. i can write (e.g. due to a miss typo): let
            Message 5 of 7 , May 6, 2012
            • 0 Attachment
              Thanxs;

              took me a while to think about during lunch; to be honest i don't feel
              comfortable with this scoping;
              e.g. i can write (e.g. due to a miss typo):

              let f=99 ;;
              let f x = f+x;;

              which is valid but for my opinion quite confusing. Even in mathematics
              you would
              need to use different identifiers to denote different things.

              Using rec makes the Caml example more naturally behaving:

              let f=1 ;;
              let rec f x = f + x;;

              Error: This expression has type 'a -> 'b
              but an expression was expected of type int

              In other languages (like Ada 95) such constructs will cause an error
              under any circumstances

              f : constant Natural := 99;

              function f(x : Natural ) return Natural is
              begin
              return f+x;
              end f;
              ...
              test.adb:7:13: "f" conflicts with declaration at line 5

              for a good reason .. ; Lets see whether i will step into this trap in
              the future ....

              /Michael


              On 05/06/2012 12:14 PM, Gabriel Scherer wrote:
              > This is not related to parsing at all, but to how identifier references are
              > resolved. OCaml has asimple scoping model:
              > - in a "let foo = bar", the expression "bar" lives in the ambiant
              > environment (what has been defined so far)
              > - in a "let rec foo = bar", the expression "bar" lives in the ambiant
              > environment *plus* the identifier "foo"
              > - "and" allows to make multiple definitions simultaneously that live in the
              > same environment, and are evaluated in an undefined order:
              > - in "let foo = bar and baz = foobar", the expressions "bar" and
              > "foobar" are evaluated in the ambiant environment
              > - in "let rec foo = bar and baz = foobar", the expressions "bar" and
              > "foobar" are evaluated in the same environment, which is the ambiant
              > environment plus "foo" and "baz".
              >
              > Having the choice between "let" and "let rec" allows you to decide
              > precisely what the scope is, including in presence of variable shadowing:
              > consider "let x () = 1;; let x () = x () + 1" and "let x () = 1;; let rec x
              > () = x () + 1". If the compiler tried to infer whether a definition is
              > recursive or not, or which "x" was actually meant in the first example, he
              > would have to make arbitrary choices that could be different from the
              > programmer's wish.
              >
              > See this caml-list thread for a discussion of such issues:
              >
              > http://old.nabble.com/Examples-where-let-rec-is-undesirable-td33068691.html
              >
              > On Sun, May 6, 2012 at 11:55 AM, Michael Erdmann <erdmann-berlin@...
              >> wrote:
              >> **
              >> Thanxs; works fine (see below) ... but why this "..and .." construct. A
              >> two pass parsing would have
              >> declared execute_file and in the second compiler pass the execute_file
              >> would have been
              >> known while compiling execute_command. I guess there is an idea behind
              >> this??
              >>
              >> /Michael
              >>
              >>
              >>
              >> ....................... the new code ....
              >>
              >> open Printf;;
              >>
              >>
              >> (** some command *)
              >> let do_go args =
              >> print_endline "go ..."
              >> ;;
              >>
              >> let rec execute_command cmd args=
              >> print_endline cmd;
              >>
              >> match cmd with
              >> "go" -> do_go(args)
              >> | "batch" -> execute_file args
              >> | _ -> print_endline "unknown command"
              >>
              >> and execute_file name =
              >> let chan = open_in name in
              >> try
              >> while true do
              >> let cmd = input_line chan in execute_command cmd "";
              >> done
              >> with End_of_file -> close_in chan
              >> ;;
              >>
              >> (** toplevel *)
              >>
              >> execute_file "startup.cmd" ;;
              >>
              >> execute_command "batch" "startup.cmd" ;;
              >>
              >>
              >>
              >> On 05/06/2012 10:11 AM, Gabriel Scherer wrote:
              >>
              >>
              >>
              >> What you need is mutual recursion:
              >>
              >> let rec execute_command = ...
              >> and execute_file = ...
              >>
              >> Working example:
              >>
              >> let rec even n = (n = 0) || odd (n - 1)
              >> and odd n = (n > 0) && even (n - 1)
              >>
              >> On Sun, May 6, 2012 at 9:52 AM, Michael Erdmann
              >> <erdmann-berlin@...> wrote:
              >>> Hallo *,
              >>>
              >>> i guess i have a simple problem, i found a solution but i am not
              >>> convinced that this is a
              >>> correct Ocaml solution.
              >>>
              >>> The code fragment at the end of the e-mail is part an excerpt of an
              >>> interpreter i am
              >>> writing for training. The function execute_command takes a command as
              >> input
              >>> and executes the corresponding command. There is one command called
              >>> batch which
              >>> allows to execute complete files by reading them line by line and again
              >>> executing the
              >>> function execute_command. This simply does not compile since
              >> execute_command
              >>> is unbound in the execute_file function :-((
              >>>
              >>> My current solution is to pass a function to execute_file as argument
              >>> which is called
              >>> instead of calling execute_command directly.
              >>>
              >>> let execute_file chan interp = .....
              >>> let cmd = input_line chan in *interp *cmd;
              >>> ;;
              >>>
              >>> let *execute_command* cmd args=
              >>> | "batch" -> let chan = open_in args in execute_file chan
              >>> execute_command
              >>>
              >>> ;;
              >>>
              >>> It works; but is this really the best solution ..... ?????
              >>>
              >>> Advise is highly welcome :-)))
              >>>
              >>> /Michael
              >>>
              >>>
              >>> ...................................................
              >>> (** some command *)
              >>> let do_go args =
              >>> print_endline "go ..."
              >>> ;;
              >>>
              >>> (** read in a batch of commands from a file *)
              >>> let execute_file chan =
              >>> try
              >>> while true do
              >>> begin
              >>> let cmd = input_line chan in *execute_command*(cmd);
              >>> end
              >>> done
              >>> with x ->
              >>> print_endline "done ****";
              >>> ;;
              >>>
              >>> (** execute a single commmand line *)
              >>> let *execute_command* cmd args=
              >>> match cmd with
              >>> "go" -> do_go(args)
              >>> | "batch" -> let chan = open_in args in execute_file chan
              >>> | _ -> print_endline "wrong command"
              >>> ;;
              >>>
              >>> (** toplevel *)
              >>>
              >>>
              >>>
              >>> [Non-text portions of this message have been removed]
              >>>
              >>>
              >>>
              >>> ------------------------------------
              >>>
              >>> 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]
              >
              >
              >
              > ------------------------------------
              >
              > 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
              >
              >
              >
              >
            • Gabriel Scherer
              Having two different bindings with the same name at the toplevel is considered bad style -- at least by me. And if the first one is not used, you ll get an
              Message 6 of 7 , May 6, 2012
              • 0 Attachment
                Having two different bindings with the same name at the toplevel is
                considered bad style -- at least by me. And if the first one is not
                used, you'll get an "unused variable" warning.

                There are good use cases for local shadowing. The typical example is:
                let foo x =
                let x = secure_wrapper x in
                ...

                (secure_wrapper may ensure that "x" is nonnegative, or in lowercase
                letter, or whatever. The point is that the old binding is not
                reachable anymore, you can't access it by mistake as you could if you
                wrote "let x' = secure x in ...")

                You will find more examples in the conversation I linked too -- and
                also people disagreeing with me.

                > Even in mathematics you would need to use different identifiers to denote different things.

                That is not true. You will easily find "let x be a real number..."
                several times in the same mathematical document. Those variables have
                the same name but are understood locally to be different. Furthermore,
                the classical pattern "without loss of generality, we can assume that
                x <has a convenient property>, because otherwise we <transform it to
                get this property>" is a equivalent to the "secure_wrapper" that I
                shown above, and also amounts to a variable rebinding (the variable
                does not live in the same space before and after you read this
                statement).

                The point is: the semantics of variable scoping in OCaml is simple,
                easy to specify, understand and reason about. It does not do
                everything magical we could wish, but it is robust and predictable,
                and better (in my opinion) than most proposed alternatives.
                (In particular, I find very important that the binding construct has
                *both* a recursive and a non-recursive version; non-recursive is the
                default, but it could be recursive by default in a language where that
                is convenient enough, such as a lazy-by-default language. But it's
                important that you can specify either ones. The "type ... = ..." does
                not have this property, it is forced to be recursive, and that is a
                defect of the OCaml syntax.)

                One regret is that this syntax enforces a bottom-up writing style,
                where everything needs to be defined before it is used. Sometimes it's
                more convenient to mention things first, and define them later:
                top-to-bottom may be a natural way to read a program. Caml used to
                have a Haskell-like "where .." syntax, but it was removed because of
                perceived uselessness and potential ambiguities. I would very warmly
                welcome a solid design that would allow top-to-bottom declaration
                style while preserving the robustness and simplicity of the scoping
                rules, but I have not yet found anything entirely satisfying --
                despite some personal experimentation.

                On Sun, May 6, 2012 at 6:00 PM, Michael Erdmann
                <erdmann-berlin@...> wrote:
                > Thanxs;
                >
                > took me a while to think about during lunch; to be honest i don't feel
                > comfortable with this scoping;
                > e.g. i can write (e.g. due to a miss typo):
                >
                > let f=99 ;;
                > let f x = f+x;;
                >
                > which is valid but for my opinion quite confusing. Even in mathematics
                > you would
                > need to use different identifiers to denote different things.
                >
                > Using rec makes the Caml example more naturally behaving:
                >
                > let f=1 ;;
                > let rec f x = f + x;;
                >
                > Error: This expression has type 'a -> 'b
                >       but an expression was expected of type int
                >
                > In other languages (like Ada 95) such constructs will cause an error
                > under any circumstances
                >
                >   f : constant Natural := 99;
                >
                >   function f(x : Natural ) return Natural is
                >   begin
                >      return f+x;
                >   end f;
                > ...
                > test.adb:7:13: "f" conflicts with declaration at line 5
                >
                > for a good reason .. ; Lets see whether i will step into this trap in
                > the future ....
                >
                > /Michael
                >
                >
                > On 05/06/2012 12:14 PM, Gabriel Scherer wrote:
                >> This is not related to parsing at all, but to how identifier references are
                >> resolved. OCaml has asimple scoping model:
                >> - in a "let foo = bar", the expression "bar" lives in the ambiant
                >> environment (what has been defined so far)
                >> - in a "let rec foo = bar", the expression "bar" lives in the ambiant
                >> environment *plus* the identifier "foo"
                >> - "and" allows to make multiple definitions simultaneously that live in the
                >> same environment, and are evaluated in an undefined order:
                >>    -  in "let foo = bar and baz = foobar", the expressions "bar" and
                >> "foobar" are evaluated in the ambiant environment
                >>    - in "let rec foo = bar and baz = foobar", the expressions "bar" and
                >> "foobar" are evaluated in the same environment, which is the ambiant
                >> environment plus "foo" and "baz".
                >>
                >> Having the choice between "let" and "let rec" allows you to decide
                >> precisely what the scope is, including in presence of variable shadowing:
                >> consider "let x () = 1;; let x () = x () + 1" and "let x () = 1;; let rec x
                >> () = x () + 1". If the compiler tried to infer whether a definition is
                >> recursive or not, or which  "x" was actually meant in the first example, he
                >> would have to make arbitrary choices that could be different from the
                >> programmer's wish.
                >>
                >> See this caml-list thread for a discussion of such issues:
                >>
                >> http://old.nabble.com/Examples-where-let-rec-is-undesirable-td33068691.html
                >>
                >> On Sun, May 6, 2012 at 11:55 AM, Michael Erdmann <erdmann-berlin@...
                >>> wrote:
                >>> **
                >>> Thanxs; works fine (see below) ... but why this "..and .." construct. A
                >>> two pass parsing would have
                >>> declared execute_file and in the second compiler pass the execute_file
                >>> would have been
                >>> known while compiling execute_command. I guess there is an idea behind
                >>> this??
                >>>
                >>> /Michael
                >>>
                >>>
                >>>
                >>> .......................  the new code ....
                >>>
                >>> open Printf;;
                >>>
                >>>
                >>> (** some command *)
                >>> let do_go args =
                >>>     print_endline "go ..."
                >>> ;;
                >>>
                >>> let rec execute_command cmd args=
                >>>     print_endline cmd;
                >>>
                >>>     match cmd with
                >>>             "go" -> do_go(args)
                >>>         | "batch" -> execute_file args
                >>>         | _ -> print_endline "unknown command"
                >>>
                >>> and execute_file name =
                >>>     let chan = open_in name in
                >>>         try
                >>>             while true do
                >>>                let cmd = input_line chan in execute_command cmd "";
                >>>             done
                >>>         with End_of_file -> close_in chan
                >>> ;;
                >>>
                >>> (** toplevel *)
                >>>
                >>> execute_file "startup.cmd" ;;
                >>>
                >>> execute_command "batch" "startup.cmd" ;;
                >>>
                >>>
                >>>
                >>> On 05/06/2012 10:11 AM, Gabriel Scherer wrote:
                >>>
                >>>
                >>>
                >>> What you need is mutual recursion:
                >>>
                >>> let rec execute_command = ...
                >>> and execute_file = ...
                >>>
                >>> Working example:
                >>>
                >>> let rec even n = (n = 0) || odd (n - 1)
                >>> and odd n = (n > 0) && even (n - 1)
                >>>
                >>> On Sun, May 6, 2012 at 9:52 AM, Michael Erdmann
                >>> <erdmann-berlin@...> wrote:
                >>>> Hallo *,
                >>>>
                >>>> i guess i have a simple problem, i found a solution but i am not
                >>>> convinced that this is a
                >>>> correct Ocaml solution.
                >>>>
                >>>> The code fragment at the end of the e-mail is part an excerpt of an
                >>>> interpreter i am
                >>>> writing for training. The function execute_command takes a command as
                >>> input
                >>>> and executes the corresponding command. There is one command called
                >>>> batch which
                >>>> allows to execute complete files by reading them line by line and again
                >>>> executing the
                >>>> function execute_command. This simply does not compile since
                >>> execute_command
                >>>> is unbound in the execute_file function :-((
                >>>>
                >>>> My current solution is to pass a function to execute_file as argument
                >>>> which is called
                >>>> instead of calling execute_command directly.
                >>>>
                >>>> let execute_file chan interp = .....
                >>>>    let cmd = input_line chan in *interp *cmd;
                >>>> ;;
                >>>>
                >>>> let *execute_command* cmd args=
                >>>>        | "batch" -> let chan = open_in args in execute_file chan
                >>>> execute_command
                >>>>
                >>>> ;;
                >>>>
                >>>> It works; but is this really the best solution ..... ?????
                >>>>
                >>>> Advise is highly welcome :-)))
                >>>>
                >>>> /Michael
                >>>>
                >>>>
                >>>> ...................................................
                >>>> (** some command *)
                >>>> let do_go args =
                >>>>    print_endline "go ..."
                >>>> ;;
                >>>>
                >>>> (** read in a batch of commands from a file *)
                >>>> let execute_file chan =
                >>>>    try
                >>>>        while true do
                >>>>           begin
                >>>>             let cmd = input_line chan in *execute_command*(cmd);
                >>>>          end
                >>>>        done
                >>>>    with x ->
                >>>>      print_endline "done ****";
                >>>> ;;
                >>>>
                >>>> (** execute a single commmand line *)
                >>>> let *execute_command* cmd args=
                >>>>    match cmd with
                >>>>            "go" -> do_go(args)
                >>>>        | "batch" -> let chan = open_in args in execute_file chan
                >>>>        | _ -> print_endline "wrong command"
                >>>> ;;
                >>>>
                >>>> (** toplevel *)
                >>>>
                >>>>
                >>>>
                >>>> [Non-text portions of this message have been removed]
                >>>>
                >>>>
                >>>>
                >>>> ------------------------------------
                >>>>
                >>>> 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]
                >>
                >>
                >>
                >> ------------------------------------
                >>
                >> 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
                >>
                >>
                >>
                >>
                >
                >
              • Michael Erdmann
                Regarding style (guides): I found some of them http://www.seas.upenn.edu/~cis341/programming_style.html
                Message 7 of 7 , May 8, 2012
                • 0 Attachment
                  Regarding style (guides):

                  I found some of them

                  http://www.seas.upenn.edu/~cis341/programming_style.html
                  <http://www.seas.upenn.edu/%7Ecis341/programming_style.html>
                  http://caml.inria.fr/resources/doc/guides/guidelines.en.html

                  i find them both reasonable :-)


                  /Michael


                  On 05/06/2012 07:13 PM, Gabriel Scherer wrote:
                  > Having two different bindings with the same name at the toplevel is
                  > considered bad style -- at least by me. And if the first one is not
                  > used, you'll get an "unused variable" warning.
                  >
                  > There are good use cases for local shadowing. The typical example is:
                  > let foo x =
                  > let x = secure_wrapper x in
                  > ...
                  >
                  > (secure_wrapper may ensure that "x" is nonnegative, or in lowercase
                  > letter, or whatever. The point is that the old binding is not
                  > reachable anymore, you can't access it by mistake as you could if you
                  > wrote "let x' = secure x in ...")
                  >
                  > You will find more examples in the conversation I linked too -- and
                  > also people disagreeing with me.
                  >
                  >> Even in mathematics you would need to use different identifiers to denote different things.
                  > That is not true. You will easily find "let x be a real number..."
                  > several times in the same mathematical document. Those variables have
                  > the same name but are understood locally to be different. Furthermore,
                  > the classical pattern "without loss of generality, we can assume that
                  > x <has a convenient property>, because otherwise we <transform it to
                  > get this property>" is a equivalent to the "secure_wrapper" that I
                  > shown above, and also amounts to a variable rebinding (the variable
                  > does not live in the same space before and after you read this
                  > statement).
                  >
                  > The point is: the semantics of variable scoping in OCaml is simple,
                  > easy to specify, understand and reason about. It does not do
                  > everything magical we could wish, but it is robust and predictable,
                  > and better (in my opinion) than most proposed alternatives.
                  > (In particular, I find very important that the binding construct has
                  > *both* a recursive and a non-recursive version; non-recursive is the
                  > default, but it could be recursive by default in a language where that
                  > is convenient enough, such as a lazy-by-default language. But it's
                  > important that you can specify either ones. The "type ... = ..." does
                  > not have this property, it is forced to be recursive, and that is a
                  > defect of the OCaml syntax.)
                  >
                  > One regret is that this syntax enforces a bottom-up writing style,
                  > where everything needs to be defined before it is used. Sometimes it's
                  > more convenient to mention things first, and define them later:
                  > top-to-bottom may be a natural way to read a program. Caml used to
                  > have a Haskell-like "where .." syntax, but it was removed because of
                  > perceived uselessness and potential ambiguities. I would very warmly
                  > welcome a solid design that would allow top-to-bottom declaration
                  > style while preserving the robustness and simplicity of the scoping
                  > rules, but I have not yet found anything entirely satisfying --
                  > despite some personal experimentation.
                  >
                  > On Sun, May 6, 2012 at 6:00 PM, Michael Erdmann
                  > <erdmann-berlin@...> wrote:
                  >> Thanxs;
                  >>
                  >> took me a while to think about during lunch; to be honest i don't feel
                  >> comfortable with this scoping;
                  >> e.g. i can write (e.g. due to a miss typo):
                  >>
                  >> let f=99 ;;
                  >> let f x = f+x;;
                  >>
                  >> which is valid but for my opinion quite confusing. Even in mathematics
                  >> you would
                  >> need to use different identifiers to denote different things.
                  >>
                  >> Using rec makes the Caml example more naturally behaving:
                  >>
                  >> let f=1 ;;
                  >> let rec f x = f + x;;
                  >>
                  >> Error: This expression has type 'a -> 'b
                  >> but an expression was expected of type int
                  >>
                  >> In other languages (like Ada 95) such constructs will cause an error
                  >> under any circumstances
                  >>
                  >> f : constant Natural := 99;
                  >>
                  >> function f(x : Natural ) return Natural is
                  >> begin
                  >> return f+x;
                  >> end f;
                  >> ...
                  >> test.adb:7:13: "f" conflicts with declaration at line 5
                  >>
                  >> for a good reason .. ; Lets see whether i will step into this trap in
                  >> the future ....
                  >>
                  >> /Michael
                  >>
                  >>
                  >> On 05/06/2012 12:14 PM, Gabriel Scherer wrote:
                  >>> This is not related to parsing at all, but to how identifier references are
                  >>> resolved. OCaml has asimple scoping model:
                  >>> - in a "let foo = bar", the expression "bar" lives in the ambiant
                  >>> environment (what has been defined so far)
                  >>> - in a "let rec foo = bar", the expression "bar" lives in the ambiant
                  >>> environment *plus* the identifier "foo"
                  >>> - "and" allows to make multiple definitions simultaneously that live in the
                  >>> same environment, and are evaluated in an undefined order:
                  >>> - in "let foo = bar and baz = foobar", the expressions "bar" and
                  >>> "foobar" are evaluated in the ambiant environment
                  >>> - in "let rec foo = bar and baz = foobar", the expressions "bar" and
                  >>> "foobar" are evaluated in the same environment, which is the ambiant
                  >>> environment plus "foo" and "baz".
                  >>>
                  >>> Having the choice between "let" and "let rec" allows you to decide
                  >>> precisely what the scope is, including in presence of variable shadowing:
                  >>> consider "let x () = 1;; let x () = x () + 1" and "let x () = 1;; let rec x
                  >>> () = x () + 1". If the compiler tried to infer whether a definition is
                  >>> recursive or not, or which "x" was actually meant in the first example, he
                  >>> would have to make arbitrary choices that could be different from the
                  >>> programmer's wish.
                  >>>
                  >>> See this caml-list thread for a discussion of such issues:
                  >>>
                  >>> http://old.nabble.com/Examples-where-let-rec-is-undesirable-td33068691.html
                  >>>
                  >>> On Sun, May 6, 2012 at 11:55 AM, Michael Erdmann <erdmann-berlin@...
                  >>>> wrote:
                  >>>> **
                  >>>> Thanxs; works fine (see below) ... but why this "..and .." construct. A
                  >>>> two pass parsing would have
                  >>>> declared execute_file and in the second compiler pass the execute_file
                  >>>> would have been
                  >>>> known while compiling execute_command. I guess there is an idea behind
                  >>>> this??
                  >>>>
                  >>>> /Michael
                  >>>>
                  >>>>
                  >>>>
                  >>>> ....................... the new code ....
                  >>>>
                  >>>> open Printf;;
                  >>>>
                  >>>>
                  >>>> (** some command *)
                  >>>> let do_go args =
                  >>>> print_endline "go ..."
                  >>>> ;;
                  >>>>
                  >>>> let rec execute_command cmd args=
                  >>>> print_endline cmd;
                  >>>>
                  >>>> match cmd with
                  >>>> "go" -> do_go(args)
                  >>>> | "batch" -> execute_file args
                  >>>> | _ -> print_endline "unknown command"
                  >>>>
                  >>>> and execute_file name =
                  >>>> let chan = open_in name in
                  >>>> try
                  >>>> while true do
                  >>>> let cmd = input_line chan in execute_command cmd "";
                  >>>> done
                  >>>> with End_of_file -> close_in chan
                  >>>> ;;
                  >>>>
                  >>>> (** toplevel *)
                  >>>>
                  >>>> execute_file "startup.cmd" ;;
                  >>>>
                  >>>> execute_command "batch" "startup.cmd" ;;
                  >>>>
                  >>>>
                  >>>>
                  >>>> On 05/06/2012 10:11 AM, Gabriel Scherer wrote:
                  >>>>
                  >>>>
                  >>>>
                  >>>> What you need is mutual recursion:
                  >>>>
                  >>>> let rec execute_command = ...
                  >>>> and execute_file = ...
                  >>>>
                  >>>> Working example:
                  >>>>
                  >>>> let rec even n = (n = 0) || odd (n - 1)
                  >>>> and odd n = (n > 0) && even (n - 1)
                  >>>>
                  >>>> On Sun, May 6, 2012 at 9:52 AM, Michael Erdmann
                  >>>> <erdmann-berlin@...> wrote:
                  >>>>> Hallo *,
                  >>>>>
                  >>>>> i guess i have a simple problem, i found a solution but i am not
                  >>>>> convinced that this is a
                  >>>>> correct Ocaml solution.
                  >>>>>
                  >>>>> The code fragment at the end of the e-mail is part an excerpt of an
                  >>>>> interpreter i am
                  >>>>> writing for training. The function execute_command takes a command as
                  >>>> input
                  >>>>> and executes the corresponding command. There is one command called
                  >>>>> batch which
                  >>>>> allows to execute complete files by reading them line by line and again
                  >>>>> executing the
                  >>>>> function execute_command. This simply does not compile since
                  >>>> execute_command
                  >>>>> is unbound in the execute_file function :-((
                  >>>>>
                  >>>>> My current solution is to pass a function to execute_file as argument
                  >>>>> which is called
                  >>>>> instead of calling execute_command directly.
                  >>>>>
                  >>>>> let execute_file chan interp = .....
                  >>>>> let cmd = input_line chan in *interp *cmd;
                  >>>>> ;;
                  >>>>>
                  >>>>> let *execute_command* cmd args=
                  >>>>> | "batch" -> let chan = open_in args in execute_file chan
                  >>>>> execute_command
                  >>>>>
                  >>>>> ;;
                  >>>>>
                  >>>>> It works; but is this really the best solution ..... ?????
                  >>>>>
                  >>>>> Advise is highly welcome :-)))
                  >>>>>
                  >>>>> /Michael
                  >>>>>
                  >>>>>
                  >>>>> ...................................................
                  >>>>> (** some command *)
                  >>>>> let do_go args =
                  >>>>> print_endline "go ..."
                  >>>>> ;;
                  >>>>>
                  >>>>> (** read in a batch of commands from a file *)
                  >>>>> let execute_file chan =
                  >>>>> try
                  >>>>> while true do
                  >>>>> begin
                  >>>>> let cmd = input_line chan in *execute_command*(cmd);
                  >>>>> end
                  >>>>> done
                  >>>>> with x ->
                  >>>>> print_endline "done ****";
                  >>>>> ;;
                  >>>>>
                  >>>>> (** execute a single commmand line *)
                  >>>>> let *execute_command* cmd args=
                  >>>>> match cmd with
                  >>>>> "go" -> do_go(args)
                  >>>>> | "batch" -> let chan = open_in args in execute_file chan
                  >>>>> | _ -> print_endline "wrong command"
                  >>>>> ;;
                  >>>>>
                  >>>>> (** toplevel *)
                  >>>>>
                  >>>>>
                  >>>>>
                  >>>>> [Non-text portions of this message have been removed]
                  >>>>>
                  >>>>>
                  >>>>>
                  >>>>> ------------------------------------
                  >>>>>
                  >>>>> 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]
                  >>>
                  >>>
                  >>>
                  >>> ------------------------------------
                  >>>
                  >>> 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
                  >>>
                  >>>
                  >>>
                  >>>
                  >>
                Your message has been successfully submitted and would be delivered to recipients shortly.