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

Re: "ocaml_beginners"::[] Reading to end of file

Expand Messages
  • Eray Ozkural
    ... No I haven t a clue! -- Eray Ozkural (exa) Comp. Sci. Dept., Bilkent University, Ankara KDE Project: http://www.kde.org www:
    Message 1 of 29 , Apr 17, 2003
      On Thursday 17 April 2003 16:09, Stalkern 2 wrote:
      > Il Thursday 17 April 2003 13:53, Eray Ozkural ha scritto:
      > > For functional code right now I'm using haskell style
      > > type 'a maybe = None | Just of 'a
      >
      > You know that's like 'a option in Ocaml, don't you
      >

      No I haven't a clue!

      --
      Eray Ozkural (exa) <erayo@...>
      Comp. Sci. Dept., Bilkent University, Ankara KDE Project: http://www.kde.org
      www: http://www.cs.bilkent.edu.tr/~erayo Malfunction: http://mp3.com/ariza
      GPG public key fingerprint: 360C 852F 88B0 A745 F31B EA0F 7C07 AE16 874D 539C
    • Walter C. Reel III
      Wow... I m certainly getting a lot of interesting input. Thanks everyone! What if the recursive function is constructing a return? Like a val :: mk_more_rec
      Message 2 of 29 , Apr 17, 2003
        Wow... I'm certainly getting a lot of interesting input. Thanks everyone!

        What if the recursive function is constructing a return? Like a 'val ::
        mk_more_rec acc_list' would it still pay off to try to hoist the exception
        handling to the entry level call?

        I'm still trying to understand last call optimisations. If I understand
        correctly, it would be better to do something like:

        let rec foo state acc_list =
        ... (* get value for 'val' *)
        foo state (val :: acc_list)

        than:

        let rec foo state acc_list =
        ... (* get value for 'val' *)
        val :: foo state acc_list

        Is that right or am I off base?

        cheers
        - Walt

        p.s. if the ordering is significant than the return should be reversed in
        first version. That seems to be the LISP way from the material I read.

        Il Thursday 17 April 2003 08:18, Walter C. Reel III ha scritto:
        > <html><body>
        >
        >
        > <tt>
        > I have a little learning program does simple processing on a report
        > style<BR> file.  I build a list using the 'input_line input_channel'
        > in a recursive<BR> function until an End_of_file is raised (the end
        > condition).  Is there<BR> another way of dertimining the end of the
        > file without using the exception?<BR> <BR>
        > I come from the C++ world of avoiding to use exceptions as regular
        > control<BR> structures, does that translate to OCaml?<BR>

        Use exceptions, but be aware both of the fact that try...with... constructs
        break tail-recursiveness, and of the kind of incorrect nesting described
        below (quoting from a post by David Brown in Caml-list, 9/4/2003).
        ----------------------------------------------------------------------------
        ------------------
        A common mistake is to
        add a try clause inside of a tail recursive call. The call is no longer
        tail-recursive, and makes a chain of exception handlers for each
        invocation. e.g.

        let rec loop () =
        try let line = input_line () in
        ...;
        loop ()
        with End_of_file -> ...

        instead of

        let rec loop () =
        let line = input_line () in
        ...;
        loop ()
        in
        try loop ()
        with End_of_file -> ...
        ----------------------------------------------------------------------------
        ------------------

        Ciao
        Ernesto
      • Stalkern 2
        ... AFAIK at present exceptions are not parameterizeable, so you can t export a value through a failure. But you can hold a copy of the value when you send it
        Message 3 of 29 , Apr 17, 2003
          Il Thursday 17 April 2003 16:22, Walter C. Reel III ha scritto:
          > <html><body>
          >
          >
          > <tt>
          > Wow... I'm certainly getting a lot of interesting input.  Thanks
          > everyone!<BR> <BR>
          > What if the recursive function is constructing a return?  Like a 'val
          > ::<BR> mk_more_rec acc_list' would it still pay off to try to hoist the
          > exception<BR> handling to the entry level call?<BR>

          AFAIK at present exceptions are not parameterizeable, so you can't export a
          value through a failure. But you can hold a copy of the value when you send
          it to a location where a failure could occur, so if a failure occurs, you can
          take the "backup" copy.
          A recursion is a repeated passage. Now, you can either have a
          try <recursion><code/></recursion> with <failure/>
          or a
          <recursion> try <code/> with <failure/></recursion>

          Both of these forms are correct, unlike the one where you start several
          try..., but have only one ...with.

          In the first case, you can have the recursion update a ref variable at every
          successful passage. In case of failure, you go and check it out:
          let myBackup = ref startValue in
          try <recursion><code/><backupUpdate/></recursion> with <failure/> ->
          !myBackup

          In the second case, you can fetch over and over an extra argument that is also
          updated at every passage, and released upon failure.
          <recursion arg="partialResult">
          try <code/> with <failure/> -> partialResult
          <partialResultUpdate/>
          </recursion>

          The "partial result" is often called "accumulator".

          > <BR>
          > I'm still trying to understand last call optimisations.  If I
          > understand<BR> correctly, it would be better to do something like:<BR>
          > <BR>
          >     let rec foo state acc_list =<BR>
          >       ... (* get value for 'val' *)<BR>
          >       foo state (val :: acc_list)<BR>
          > <BR>
          > than:<BR>
          > <BR>
          >     let rec foo state acc_list =<BR>
          >       ... (* get value for 'val' *)<BR>
          >       val :: foo state acc_list<BR>
          > <BR>
          > Is that right or am I off base?<BR>

          That is right. Tail recursion is allowed by having the LAST call to the
          function be the function itself. But in the case of val :: (foo state
          acc_list), the LAST call is the :: operator, not (foo state acc_list), so the
          compiler will not find its way for optimizing the function.

          Ciao
          Ernesto
        • Brian Hurt
          ... I wouldn t use exceptions if some other control structure worked better- but I wouldn t worry about using exceptions where necessary and/or convient. ...
          Message 4 of 29 , Apr 17, 2003
            On Thu, 17 Apr 2003, Didier Le Botlan wrote:

            > > I come from the C++ world of avoiding to use exceptions as regular control
            > > structures, does that translate to OCaml?

            I wouldn't use exceptions if some other control structure worked better-
            but I wouldn't worry about using exceptions where necessary and/or
            convient.

            >
            > In OCaml you are welcome to use exceptions as much as you wish.
            > I would be interested to know why exceptions are so bad in C++.
            >

            Stack objects, and the the lack of garbage collection. Here's the
            problem: when you declare an object with a destructor is on the stack
            (i.e. is not allocatated statically on on the heap by calling new), when
            an exception is thrown that exits that namespace, the destructor must be
            called. Unwinding the stack then becomes a complicated algorithm called
            "stack unwinding". Very expensive computationally.

            I'm not 100% sure how Ocaml does exceptions, but it's much closer to C's
            setjmp/longjmp. You can't allocate anything with a destructor on the
            stack (well, effectively). So all Ocaml needs to do is set the stack
            pointer to the right frame, and then jump to the right handler- much
            faster. Objects on the heap will get collected just as soon as the
            garbage collector gets around to them.

            Brian
          • Martin Weber
            ... Yes, that s right. Tail calls mean the last thing you do in a function is call another function, while you can throw away the local state because it s
            Message 5 of 29 , Apr 17, 2003
              On Thu, Apr 17, 2003 at 10:22:56AM -0400, Walter C. Reel III wrote:
              > Wow... I'm certainly getting a lot of interesting input. Thanks everyone!
              >
              > What if the recursive function is constructing a return? Like a 'val ::
              > mk_more_rec acc_list' would it still pay off to try to hoist the exception
              > handling to the entry level call?
              >
              > I'm still trying to understand last call optimisations. If I understand
              > correctly, it would be better to do something like:
              >
              > let rec foo state acc_list =
              > ... (* get value for 'val' *)
              > foo state (val :: acc_list)
              >
              > than:
              >
              > let rec foo state acc_list =
              > ... (* get value for 'val' *)
              > val :: foo state acc_list
              >
              > Is that right or am I off base?

              Yes, that's right. Tail calls mean the last thing you do in a function
              is call another function, while you can throw away the local state because
              it's embodied in the last call. In the first example this is the case;
              nothing from the local environment is needed anylonger as you pass the
              constructed value (val :: acc_list) along to the next function call.
              in the second example you first have to call the other function and
              then still need the local environment to construct the parameter.

              One thing really helping understanding of tail calls is the original(1)
              paper about it by Guy Lewis Steele Jr. "Debunking the 'Expensive Procedure
              Call' Myth, or, Procedure Call, Implementations Considered Harmful, or,
              Lambda: the ultimate GOTO" from Oct. 1977. It's available online and
              for free via ftp:
              <ftp://publications.ai.mit.edu/ai-publications/0-499/AIM-443.ps>

              (1) At least I think it's the original paper. Anyways, it's a fine
              explanation of the nature of tail calls.

              -Martin
            • Brian Hurt
              ... OK, stupid question that I should see but don t: what happens if you want to return a value from loop? For example, reading a file and making a (backwards)
              Message 6 of 29 , Apr 17, 2003
                On Thu, 17 Apr 2003, Stalkern 2 wrote:

                > Use exceptions, but be aware both of the fact that try...with... constructs
                > break tail-recursiveness, and of the kind of incorrect nesting described
                > below (quoting from a post by David Brown in Caml-list, 9/4/2003).
                > ----------------------------------------------------------------------------------------------
                > A common mistake is to
                > add a try clause inside of a tail recursive call. The call is no longer
                > tail-recursive, and makes a chain of exception handlers for each
                > invocation. e.g.
                >
                > let rec loop () =
                > try let line = input_line () in
                > ...;
                > loop ()
                > with End_of_file -> ...
                >
                > instead of
                >
                > let rec loop () =
                > let line = input_line () in
                > ...;
                > loop ()
                > in
                > try loop ()
                > with End_of_file -> ...
                > ----------------------------------------------------------------------------------------------
                >

                OK, stupid question that I should see but don't: what happens if you want
                to return a value from loop?

                For example, reading a file and making a (backwards) list of the strings
                of the line. The naive way would be to do:

                let read_file chan =
                let rec loop accum =
                try
                let line = input_line chan in
                loop (line :: accum)
                with End_of_file -> accum
                in
                loop []
                ;;

                The next best thing I can think of is:

                let read_file chan =
                let read_a_line () =
                try
                let line = input_line chan in
                (line, false)
                with End_of_file -> ("", true)
                in
                let rec loop accum =
                let line, eof = read_a_line () in
                if (eof) then accum else loop (line :: accum)
                in
                loop []
                ;;


                In addition to being half again more code, this strikes me as being less
                elegant than the original solution.

                It would be really nice if we had some sort of feof-like function,
                allowing us to write the above code without exceptions at all:

                let read_file chan =
                let rec loop accum =
                if feof chan then
                accum
                else
                let line = input_line chan in
                loop (line :: accum)
                in
                loop []
                ;;

                I've looked, but didn't find anything.

                Brian
              • Brian Hurt
                ... You are 100% correct. A pattern (in the OO sense) you will see often is to build a list by prepending new elements to an accumulator argument, which is
                Message 7 of 29 , Apr 17, 2003
                  On Thu, 17 Apr 2003, Walter C. Reel III wrote:

                  > I'm still trying to understand last call optimisations. If I understand
                  > correctly, it would be better to do something like:
                  >
                  > let rec foo state acc_list =
                  > ... (* get value for 'val' *)
                  > foo state (val :: acc_list)
                  >
                  > than:
                  >
                  > let rec foo state acc_list =
                  > ... (* get value for 'val' *)
                  > val :: foo state acc_list
                  >
                  > Is that right or am I off base?

                  You are 100% correct. A pattern (in the OO sense) you will see often is
                  to build a list by prepending new elements to an "accumulator" argument,
                  which is then reversed at the last minute. Variations on:

                  let rec foo args accum =
                  if not_the_end then
                  let newelem = ... in
                  foo args (newelem :: accum)
                  else
                  List.rev accum
                  ;;

                  Brian
                • Remi Vanicat
                  ... you really should use the option type. It already there, so much better than a new identical one. [...] -- Rémi Vanicat vanicat@labri.u-bordeaux.fr
                  Message 8 of 29 , Apr 17, 2003
                    Eray Ozkural <erayo@...> writes:

                    > On Thursday 17 April 2003 12:38, Stalkern 2 wrote:
                    >> Use exceptions, but be aware both of the fact that try...with... constructs
                    >> break tail-recursiveness, and of the kind of incorrect nesting described
                    >> below (quoting from a post by David Brown in Caml-list, 9/4/2003).
                    >
                    > For functional code right now I'm using haskell style
                    > type 'a maybe = None | Just of 'a

                    you really should use the option type. It already there, so much better
                    than a new identical one.
                    [...]


                    --
                    Rémi Vanicat
                    vanicat@labri.u-bordeaux.fr
                    http://dept-info.labri.u-bordeaux.fr/~vanicat
                  • Daniel Andor
                    ... I know this doesn t answer the original question, but can t you paramterise exceptions by declaring them: exception My_EOF of int for example? Or am I
                    Message 9 of 29 , Apr 17, 2003
                      On Thu, 17 Apr 2003, Stalkern 2 wrote:
                      > AFAIK at present exceptions are not parameterizeable, so you can't export a
                      > value through a failure.

                      I know this doesn't answer the original question, but can't you
                      paramterise exceptions by declaring them:

                      exception My_EOF of int

                      for example? Or am I missing what you mean by parametrisable?

                      Confused,
                      Daniel.
                    • Stalkern 2
                      ... Yes Daniel you re quite right. It is true that e.g. Unix exceptions are generally composite, I forgot that. # exception My_EOF of int;; exception My_EOF of
                      Message 10 of 29 , Apr 17, 2003
                        Il Thursday 17 April 2003 21:13, Daniel Andor ha scritto:
                        > <html><body>
                        >
                        >
                        > <tt>
                        > On Thu, 17 Apr 2003, Stalkern 2 wrote:<BR>
                        > > AFAIK at present exceptions are not parameterizeable, so you can't
                        > export a<BR> > value through a failure.<BR>
                        > <BR>
                        > I know this doesn't answer the original question, but can't you<BR>
                        > paramterise exceptions by declaring them:<BR>
                        > <BR>
                        > exception My_EOF of int<BR>
                        > <BR>
                        > for example?  Or am I missing what you mean by parametrisable?<BR>
                        > <BR>
                        > Confused,<BR>
                        > Daniel.<BR>

                        Yes Daniel you're quite right. It is true that e.g. Unix exceptions are
                        generally composite, I forgot that.

                        # exception My_EOF of int;;
                        exception My_EOF of int
                        # raise (My_EOF 1);;
                        Exception: My_EOF 1.

                        Thank you very much.

                        Ernesto
                      • Stalkern 2
                        ... In this ML you are not the first one asking for a clear EOF (or similar) marker. Why not? At present we detect a EOF by a failure. This sounds strange in
                        Message 11 of 29 , Apr 17, 2003
                          Il Thursday 17 April 2003 17:35, Brian Hurt ha scritto:
                          > It would be really nice if we had some sort of feof-like function,
                          > allowing us to write the above code without exceptions at all:
                          >
                          > let read_file chan =
                          > let rec loop accum =
                          > if feof chan then
                          > accum
                          > else
                          > let line = input_line chan in
                          > loop (line :: accum)
                          > in
                          > loop []
                          > ;;
                          >
                          > I've looked, but didn't find anything.

                          In this ML you are not the first one asking for a clear EOF (or similar)
                          marker. Why not? At present we detect a EOF by a failure. This sounds strange
                          in the imperative world, where there is a file and then there is a EOF, and
                          when you find the EOF you look in the current environment and the file before
                          the EOF is still in memory.

                          But the functional world is different: if you get a EOF, you do really get a
                          EOF. Now if you where reading some text from a channel, a EOF is for sure an
                          exceptional event. Think of all the lambda things that you could have done
                          with a string, that you CAN'T do with a EOF. And the EOF does not help in
                          recovering automagically the string so far, because we can't access the
                          memory context as easily (and error-pronely) as in the imperative world.

                          But remember: using in and out channels (e.g. printing) is by its very nature
                          an imperative activity. That (at least using Ocaml) you can write in several
                          styles. For some simple purposes e.g. reading and writing files in a row,
                          personally I use an imperative style with while true do... done constructs,
                          while for other purposes involving complex operations I do prefer to write a
                          let rec loop. You can choose, too.

                          Cheers
                          Ernesto
                        • Remi Vanicat
                          ... I don t agree here, it is not a failure, it is an exception. It is not the same thing. [...] -- Rémi Vanicat vanicat@labri.u-bordeaux.fr
                          Message 12 of 29 , Apr 17, 2003
                            Stalkern 2 <stalkern2@...> writes:

                            > Il Thursday 17 April 2003 17:35, Brian Hurt ha scritto:
                            >> It would be really nice if we had some sort of feof-like function,
                            >> allowing us to write the above code without exceptions at all:
                            >>
                            >> let read_file chan =
                            >> let rec loop accum =
                            >> if feof chan then
                            >> accum
                            >> else
                            >> let line = input_line chan in
                            >> loop (line :: accum)
                            >> in
                            >> loop []
                            >> ;;
                            >>
                            >> I've looked, but didn't find anything.
                            >
                            > In this ML you are not the first one asking for a clear EOF (or similar)
                            > marker. Why not? At present we detect a EOF by a failure.

                            I don't agree here, it is not a failure, it is an exception. It is not
                            the same thing.

                            [...]


                            --
                            Rémi Vanicat
                            vanicat@labri.u-bordeaux.fr
                            http://dept-info.labri.u-bordeaux.fr/~vanicat
                          • Stalkern 2
                            ... Can you go on explaining this, Rémi? I have always seen exceptions and failures coupled. I agree that exceptions can be used in a positive way, i.e. not
                            Message 13 of 29 , Apr 17, 2003
                              Il Friday 18 April 2003 03:57, Remi Vanicat ha scritto:
                              > I don't agree here, it is not a failure, it is an exception. It is not
                              > the same thing.

                              Can you go on explaining this, Rémi?
                              I have always seen exceptions and failures coupled.
                              I agree that exceptions can be used in a "positive" way, i.e. not only kept as
                              failure statement but happily reused in the rest of the code. But the
                              conditions that lead to use them seem to be "breakages".
                              I don't know (yet) why would one use an exception as a result when other kind
                              of results, much more flexible, are available.

                              T I A

                              Ernesto
                            • Nicolas Cannasse
                              ... kept as ... kind ... I think that what Remi want to say is the same thing we ve been talking about on the ExtLib mailling lit :. A failure ( exception
                              Message 14 of 29 , Apr 18, 2003
                                > > I don't agree here, it is not a failure, it is an exception. It is not
                                > > the same thing.
                                >
                                > Can you go on explaining this, Rémi?
                                > I have always seen exceptions and failures coupled.
                                > I agree that exceptions can be used in a "positive" way, i.e. not only
                                kept as
                                > failure statement but happily reused in the rest of the code. But the
                                > conditions that lead to use them seem to be "breakages".
                                > I don't know (yet) why would one use an exception as a result when other
                                kind
                                > of results, much more flexible, are available.

                                I think that what Remi want to say is the same thing we've been talking
                                about on the ExtLib mailling lit :.

                                A failure ( exception Failure of string ) is not supposed to be catched. Why
                                ? because if you want to catch it properly, and at any level, you need to do
                                a full matching such as : "with Failure "int_of_string" -> (* handle it *)"
                                , while matching Failure _ can be good enough if you're trapping the
                                exception immediatly, most of the time, you have to be sure that you're
                                catching the "good" failure, and then you need to specify which function
                                raised it.... as a string. Quite type-unsafe for an type-safe language
                                isnt'it ? There can occurs typos, wrong spelling, and more... That's why
                                failures are not supposed to be catched, but to reach the top-level in order
                                to be printed.

                                Consequence of that, in the ExtLib, we have been modifying the specification
                                of several functions ( among theses List.hd , List.tl , etc. ) which are now
                                raising Empty_list (or other exception) because we think that theses
                                exceptions are worth catching.

                                Nicolas Cannasse
                              • Stalkern 2
                                ... Hey, I say failure (common word) not Failure (ocaml constructor). ;-) Bye Ernesto
                                Message 15 of 29 , Apr 18, 2003
                                  Il Friday 18 April 2003 09:12, Nicolas Cannasse ha scritto:
                                  > > > I don't agree here, it is not a failure, it is an exception. It is not
                                  > > > the same thing.
                                  > >
                                  > > Can you go on explaining this, Rémi?
                                  > > I have always seen exceptions and failures coupled.
                                  > > I agree that exceptions can be used in a "positive" way, i.e. not only
                                  >
                                  > kept as
                                  >
                                  > > failure statement but happily reused in the rest of the code. But the
                                  > > conditions that lead to use them seem to be "breakages".
                                  > > I don't know (yet) why would one use an exception as a result when other
                                  >
                                  > kind
                                  >
                                  > > of results, much more flexible, are available.
                                  >
                                  > I think that what Remi want to say is the same thing we've been talking
                                  > about on the ExtLib mailling lit :.
                                  >
                                  > A failure ( exception Failure of string ) is not supposed to be catched.

                                  Hey, I say failure (common word) not Failure (ocaml constructor).
                                  ;-)
                                  Bye
                                  Ernesto
                                • Martin Weber
                                  ... Well, I m coming from a lisp world, and I see the two clearly decoupled. One use of an exception is to install a throw/catch mechanism, which can
                                  Message 16 of 29 , Apr 18, 2003
                                    On Fri, Apr 18, 2003 at 08:45:24AM +0200, Stalkern 2 wrote:
                                    > Il Friday 18 April 2003 03:57, Remi Vanicat ha scritto:
                                    > > I don't agree here, it is not a failure, it is an exception. It is not
                                    > > the same thing.
                                    >
                                    > Can you go on explaining this, Rémi?
                                    > I have always seen exceptions and failures coupled.

                                    Well, I'm coming from a lisp world, and I see the two clearly decoupled.
                                    One use of an exception is to install a "throw/catch" mechanism, which
                                    can transport information up through the calling levels, and is NOT meant
                                    as a failure, but rather as an "alternate exit" (much like a continuation).

                                    The other part is an "failure notification with unrolling" which signals
                                    a recoverable (or not) error which has occured and asks for fixing that
                                    in an upper level. This decoupling helps to make the intent clear (which
                                    you can't with solely exceptions): One way you'd like to get out of a
                                    deeply recursive function which itself does not have the means to stop
                                    itself, and the other way is there to get out of anything where you expect
                                    the caller to be able to handle the condition.

                                    In lisp it's throw/catch vs. "conditions", and I think this distinction
                                    helps both programmers and source code to have a nice separation between
                                    wanted non-local exit and asking for help. When you only have exceptions
                                    which combine both features, I feel it's always a problem because many
                                    people think like you: Exception = failure.

                                    If you happen to stumble over "The C++ programming language" by Bjarne
                                    Stroustroup (even if it's not about a functional programming language :),
                                    go read his introduction about exceptions. He's stating the very same there,
                                    but also implies that exceptions shouldn't be used for a generic throw/catch,
                                    because programmers tend to think of exception as a failure and thus it's
                                    no good service to make them think there was an error where just a "different
                                    exit" has been used. He's not strictly against it though, and generally is
                                    shrugging helplessly when all you want is a throw/catch. Seems HE cannot see
                                    the need for two different non-local exits, one for the error case, one for
                                    the "normal" case. In C++ you can understand that, in ML you can't. Well.

                                    Hope that helps for some insight though.

                                    regards,

                                    -martin
                                  • Costin Cozianu
                                    Hi, I was doing kind of a laundry list to see if I can push Ocaml around my work environemnt for a few more or less essential and time/speed/flexibility
                                    Message 17 of 29 , Apr 18, 2003
                                      Hi,

                                      I was doing kind of a laundry list to see if I can push Ocaml around my
                                      work environemnt for a few more or less essential and
                                      time/speed/flexibility critical tasks.

                                      However,as much as I am in love with the language I have hit a few
                                      stumbling blocks by myself:

                                      The major factor is lack of good documentation.

                                      I have bought the O'Reilly french book (delivered to me personally from
                                      France :) ), as well as have downloaded the online English edition. The
                                      problem with it is that it is too much structured on a HOWTO approach,
                                      here's the feature, here's the example, key information is spread here
                                      and there among the phrases of various paragraphs. If I was young again
                                      I'd dedicate a full week to read it cover to cover, but for somebody who
                                      steals a few hours in the weekend, this is terrible.

                                      I need to know the principles of the language so that whenever I face a
                                      problem (can I do it like this, or is this possible at all), I could
                                      judge for myself based on a few simple rules, instead of chasing the
                                      miriad of how to discussions both in Ocaml documentation or in the book.

                                      For example, I had to learn by myself that a (top level) expression ends
                                      where the next expression begins (determined more or less by keywords).
                                      For people coming from Java , Pascal, C++ background this is quite a
                                      novelty, it would have been nice to find out from the very beginning. A
                                      great deal of confusion comes about how to structure my code and the ;;
                                      terminator and how the compiler generates a code that doesn't (or does
                                      it ? ) have a clear main entry similar to C's main. It's nice to play
                                      around with the interactive environment but typical programmers worry
                                      more about how to structure their build process. Then I slowly learnt
                                      about loops, but when to exercise with more substantial algorithms
                                      (imperative of course because I can write C in any decent language) I
                                      have to learn about breaking the loops with a value with "exception
                                      Break of int", for example. But when to write a generic algorithm I had
                                      to slowly learn again that exceptions can't be made generic
                                      (parameterized by types). Or can they ? If I declare them in a module
                                      will it be allowed ?

                                      These kind of questions are very hard to answer from a HOWTO book, and
                                      very painful to write little programs about. Also the complexity of the
                                      language doesn't help at all, if I steal 8 hours this weekend, learn a
                                      few things , come back in a month, I forget most of the details. Some
                                      design considerations and why things are the way they are would be a
                                      nice help for learning and using the language.

                                      Is there a better reference available ?

                                      Second, I have a practical problem to solve, and I'm puzzled by the
                                      serialization problem, trying to prototype a replacement part for a Java.

                                      It looks to me that I can't serialize objects. Is it true, or am I
                                      missing something ? Another thing that I'm puzzled is how I can write a
                                      server that deserializes some kind of values (I'd prefer objects, but a
                                      substitute would suffice -- can I serialize functional closures , and
                                      what if those things contain references to objects) ?

                                      And how can I be sure that I can coerce the value to the write type
                                      (protecting myself against faulty clients)? Is there a function for
                                      casting similar to a typecase statement or Java's instanceof and ()
                                      operators ? Because as far as I can read the documentation that I have,
                                      the only solution apears to be to trust the clients that they send me
                                      the right thing, and risk a segmentation fault ???

                                      Is the statement
                                      let x= (Marshal.from_channel channel : myType)

                                      working essentially as reinterpret_cast<myType> in C++ (just
                                      reinterpreting the bits for the purpose of the compiler, with no effect
                                      and no protection at runtime) . Related to this problem is there anyway
                                      in which values carry their type with them like in Lisp, Scheme or even
                                      Java, or is this a performance trade-off, and it works as in C++ ?

                                      I'd also like to know about other people's experiences in introducing
                                      ocaml in "production" (the links at ocaml.org look a bit outdated and
                                      not very encouraging). So far the most impressive application in Ocaml
                                      seems to be the ocaml itself.

                                      Hope you had the patience to read my tribulations, but please excuse my
                                      impatience and my amateurish comments, but if I can't learn the language
                                      fast enough and be able to write a production level prototype, I won't
                                      learn it at all.

                                      Thank you,
                                      Costin Cozianu
                                    • Remi Vanicat
                                      ... [...] It is exactly what I mean. Thanks Martin for this very clear explanation. -- Rémi Vanicat vanicat@labri.u-bordeaux.fr
                                      Message 18 of 29 , Apr 18, 2003
                                        Martin Weber <Ephaeton@...> writes:

                                        > On Fri, Apr 18, 2003 at 08:45:24AM +0200, Stalkern 2 wrote:
                                        >> Il Friday 18 April 2003 03:57, Remi Vanicat ha scritto:
                                        >> > I don't agree here, it is not a failure, it is an exception. It is not
                                        >> > the same thing.
                                        >>
                                        >> Can you go on explaining this, Rémi?
                                        >> I have always seen exceptions and failures coupled.
                                        >
                                        > Well, I'm coming from a lisp world, and I see the two clearly decoupled.
                                        > One use of an exception is to install a "throw/catch" mechanism, which
                                        > can transport information up through the calling levels, and is NOT meant
                                        > as a failure, but rather as an "alternate exit" (much like a continuation).
                                        >

                                        [...]

                                        It is exactly what I mean. Thanks Martin for this very clear
                                        explanation.

                                        --
                                        Rémi Vanicat
                                        vanicat@labri.u-bordeaux.fr
                                        http://dept-info.labri.u-bordeaux.fr/~vanicat
                                      • Brian Hurt
                                        On Fri, 18 Apr 2003, Stalkern 2 wrote:In this ML you are not the first one asking for a clear EOF (or similar) marker. Why not? At present we detect a
                                        Message 19 of 29 , Apr 18, 2003
                                          On Fri, 18 Apr 2003, Stalkern 2 wrote:

                                          > In this ML you are not the first one asking for a clear EOF (or similar)
                                          > marker. Why not? At present we detect a EOF by a failure. This sounds strange
                                          > in the imperative world, where there is a file and then there is a EOF, and
                                          > when you find the EOF you look in the current environment and the file before
                                          > the EOF is still in memory.
                                          >
                                          > But the functional world is different: if you get a EOF, you do really get a
                                          > EOF. Now if you where reading some text from a channel, a EOF is for sure an
                                          > exceptional event.

                                          I agree that EOF is not a character in the same way that C has the EOF
                                          character (well, -1 anyways). But EOF *is* a condition- that this channel
                                          is at the end of it's file, and the next read will throw an exception.
                                          And as a condition, I don't think it'd be hard to detect.

                                          > Think of all the lambda things that you could have done
                                          > with a string, that you CAN'T do with a EOF. And the EOF does not help in
                                          > recovering automagically the string so far, because we can't access the
                                          > memory context as easily (and error-pronely) as in the imperative world.

                                          Hmm? Now I'm confused. The last read should read everything up to the
                                          end of file. Even if the last character isn't a newline, the read should
                                          end at EOF. So we got the last line on the last read, and there are no
                                          more characters to read. This is the behavior of Ocaml at least on Linux-
                                          I just checked. Otherwise, if you have a file with the last character not
                                          being a newline, you lose characters in either case.

                                          Consider the file generated by the C program I just attached. It creates
                                          a file that looks like:
                                          $ xxd -g 1 temp.txt
                                          0000000: 62 61 72 0a 66 6f 6f bar.foo

                                          (xxd is a hex dumping program under linux). Notice that the last
                                          character is *not* and end of line. So we fire up Ocaml:

                                          $ ocaml
                                          Objective Caml version 3.06

                                          # let f = open_in_bin "temp.txt";;
                                          val f : in_channel = <abstr>
                                          # let x = input_line f;;
                                          val x : string = "bar"
                                          # let y = input_line f;;
                                          val y : string = "foo"
                                          # let z = input_line f;;
                                          Exception: End_of_file.
                                          #

                                          Notice that we actually read "foo". So when we go to read line z, we have
                                          no more characters in the buffer. So the function I'm thinking of would
                                          look like:

                                          $ ocaml
                                          Objective Caml version 3.06

                                          # let f = open_in_bin "temp.txt";;
                                          val f : in_channel = <abstr>
                                          # feof f;;
                                          - : bool = false
                                          # let x = input_line f;;
                                          val x : string = "bar"
                                          # feof f;;
                                          - : bool = false
                                          # let y = input_line f;;
                                          val y : string = "foo"
                                          # feof f;;
                                          - : bool = true
                                          # let z = input_line f;;
                                          Exception: End_of_file.
                                          #


                                          >
                                          > But remember: using in and out channels (e.g. printing) is by its very nature
                                          > an imperative activity. That (at least using Ocaml) you can write in several
                                          > styles. For some simple purposes e.g. reading and writing files in a row,
                                          > personally I use an imperative style with while true do... done constructs,
                                          > while for other purposes involving complex operations I do prefer to write a
                                          > let rec loop. You can choose, too.
                                          >

                                          I suppose you could always use references:

                                          let read_file f =
                                          let rec loop accum_ref =
                                          let l = input_line f in
                                          accum_ref := l :: (!accum_ref);
                                          loop accum_ref
                                          in
                                          let accum_ref = ref [] in
                                          try
                                          loop accum_ref
                                          with
                                          End_of_file -> !accum_ref
                                          ;;

                                          This preserves tail recursion, but again I don't think it's as clean as
                                          having an feof.

                                          Brian



                                          ----------

                                          #include <stdio.h>

                                          int main (void) {
                                          char d[] = { 'f', 'o', 'o' };

                                          FILE * f = fopen("temp.txt", "wb");

                                          if (f == NULL) {
                                          perror("temp.txt");
                                          return -1;
                                          }

                                          fwrite("bar\n", 1, 4, f);
                                          fwrite(d, 1, sizeof(d), f);
                                          fclose(f);
                                          return 0;
                                          }





                                          [Non-text portions of this message have been removed]
                                        • Stalkern 2
                                          ... In my opinion, to mix _data values_ and a _condition_ is not very friendly to a static type checking mechanism, and that s why I consider the lack of EOF
                                          Message 20 of 29 , Apr 22, 2003
                                            Il Friday 18 April 2003 17:32, Brian Hurt ha scritto:
                                            > I agree that EOF is not a character in the same way that C has the EOF
                                            > character (well, -1 anyways). But EOF *is* a condition- that this channel
                                            > is at the end of it's file, and the next read will throw an exception.
                                            > And as a condition, I don't think it'd be hard to detect.

                                            In my opinion, to mix _data values_ and a _condition_ is not very friendly to
                                            a static type checking mechanism, and that's why I consider the lack of EOF
                                            as normal.

                                            BTW, since reading characters in Ocaml gives a number of characters read, at
                                            least when the number of characters read is below the expected one you know
                                            that -if the channel is reliable and not loosing chars on its own- you're
                                            approaching the EOF. And I guess that a mechanism similar to the one of
                                            exception throw/catch is used at lower level by the input function, since it
                                            can return numbers of read chars lower than asked.

                                            Cheers
                                            Ernesto
                                          • Brian Hurt
                                            ... I think we re talking past each other. What I m looking for is a function: val feof : in_channel - bool where feof chan returns true if the next read
                                            Message 21 of 29 , Apr 22, 2003
                                              On Tue, 22 Apr 2003, Stalkern 2 wrote:

                                              > Il Friday 18 April 2003 17:32, Brian Hurt ha scritto:
                                              > > I agree that EOF is not a character in the same way that C has the EOF
                                              > > character (well, -1 anyways). But EOF *is* a condition- that this channel
                                              > > is at the end of it's file, and the next read will throw an exception.
                                              > > And as a condition, I don't think it'd be hard to detect.
                                              >
                                              > In my opinion, to mix _data values_ and a _condition_ is not very friendly to
                                              > a static type checking mechanism, and that's why I consider the lack of EOF
                                              > as normal.

                                              I think we're talking past each other. What I'm looking for is a
                                              function:

                                              val feof : in_channel -> bool

                                              where feof chan returns true if the next read will throw an End_of_file
                                              exception, and false otherwise. No mixing data values and conditions.
                                              Just a seperate way to *detect* the condition other than catching an
                                              exception.

                                              This would allow us to read a file into a list of strings like:

                                              let readfile chan =
                                              let rec loop accum =
                                              if (feof chan) then
                                              List.rev accum
                                              else
                                              let line = input_line chan in
                                              loop (line :: accum)
                                              in
                                              loop []
                                              ;;


                                              >
                                              > BTW, since reading characters in Ocaml gives a number of characters read, at
                                              > least when the number of characters read is below the expected one you know
                                              > that -if the channel is reliable and not loosing chars on its own- you're
                                              > approaching the EOF. And I guess that a mechanism similar to the one of
                                              > exception throw/catch is used at lower level by the input function, since it
                                              > can return numbers of read chars lower than asked.
                                              >

                                              But this means I can't use convience functions, like input_line.

                                              Brian
                                            Your message has been successfully submitted and would be delivered to recipients shortly.