[cwn] Attn: Development Editor, Latest Caml Weekly News

Alan Schmitt alan.schmitt at polytechnique.org
Tue Feb 1 01:21:21 PST 2005


Hello,

Here is the latest Caml Weekly News, for the week of 25 January to 01  
February, 2005.

1) Dynaml: Dynamic types hack for O'Caml
2) 'a Set?
3) local Open
4) Phantom types and polymorphic variants
5) Ocaml-Packrat 0.1.0
6) Sourceforge Trove Categories
7) yacc style
8) perl4caml 0.9.0
9) '_a
10) C-threads & callbacks
11) cyclic types
12) Debian apt-proxy/apt-cacher replacement
13) developing apps with ocaml exercices web pages
14) Ocaml license - why not GPL?

========================================================================
1) Dynaml: Dynamic types hack for O'Caml
Archive: http://caml.inria.fr/archives/200501/msg00214.html
------------------------------------------------------------------------
** Jim Farrand announced:

Dynaml is a camlp4 extension to O'Caml which allows values to be typed
dynamically (at runtime), rather than statically (at compile time).

http://farrand.net/dynaml.shtml

The README file is on the website, and is reasonably instructive.

Features:
   * Provides "to dynamic" and "to static" cast for converting values
     from statuc/dynamic.
   * Type exception is thrown if a value is cast to an incorrect type, to
     preserve type safety.
   * Can deal with polymorphic functions and values.

========================================================================
2) 'a Set?
Archive: http://caml.inria.fr/archives/200501/msg00229.html
------------------------------------------------------------------------
** Mike Hamburg asked:

Is there any clean way to make a type 'a set, corresponding to Set.Make
of a module with type t='a and compare=Pervasives.compare?  I'm trying
to make a module which uses sets of arbitrary types of objects, and I
don't want to have to make it a functor.

So in other words, I'd like to make a module AlphaSet with type
type 'a t,
val is_empty: 'a t -> bool
val mem: 'a -> 'a t -> bool,
etc.

instead of Set which is a functor producing
types t, elt
val is_empty: t -> bool
val mem: elt -> t -> bool,
etc.

Is there a clean way to do this without removing the code from set.ml
and modifying it?

** Jean-Christophe Filliatre answered:

Unfortunately, no.

Note that when duplicating the code from set.ml, you can either keep a
functorized code, with an additional type parameter:

   module type OrderedType = sig
     type 'a t
     val compare: 'a t -> 'a t -> int
   end
   module type S = sig
     type 'a elt
     type 'a t
     ...
   end
   module Make(Ord: OrderedType): (S with type 'a elt = 'a Ord.t)

or directly substitute  Pervasives.compare for the comparison function
to get a polymorphic data structure (and no functor anymore):

   module AlphaSet : sig
     type 'a elt
     type 'a t
     ...
   end

** Jon Harrop also answered (and the thread continued, please read the  
rest online):

I do not believe so. I have also had to do this.

Compared to a flat set of functions, the functor approach has the  
advantage of
enforcing a consistently used compare function. The same effect can be
achieved with "elt = 'a" by writing a higher-order function which  
returns a
record containing the Set.* functions using the given function argument  
as
the compare function. Something equivalent to this:

   type 'a t = 'a list
   type 'a set =
     { empty : 'a t;
       is_empty : 'a t -> bool;
       add : 'a -> 'a t -> 'a t;
       mem : 'a -> 'a t -> bool }

   let rec add compare e = function
     [] -> [e]
   | h :: t -> match compare h e with
       -1 -> e :: h :: t
     | 0 -> e :: t
     | _ -> h :: add compare e t
   let rec mem compare e = function
     [] -> false
   | h :: t -> match compare h e with
       -1 -> false
     | 0 -> true
     | _ -> mem compare e t

   let make ?(compare=compare) () =
     { empty = [];
       is_empty = (fun s -> s=[]);
       add = add compare;
       mem = mem compare }

Possible issues with this are that building closures (i.e. in "make") is
expensive and that the resulting type is monomorphic ('_a). You can  
probably
get a polymorphic type most easily by putting the definitions of "add"  
etc.
in the record definition, rather than partially applying their  
arguments.

========================================================================
3) local Open
Archive: http://caml.inria.fr/archives/200501/msg00216.html
------------------------------------------------------------------------
** Oliver Bandel asked and Julien Signoles answered:

 > Is it planned to have a local Open-statement in OCaml
 > in newer Versions?
 > This would help a lot to easily write code with
 > opened modules and at the same time to have
 > unpolluted namespace.
 >
 > There are local modules... but not local Open's?!
 >
 > Any idea about that?

openin is probably your friend. It is a camlp4 syntax extension by Alain
Frisch allowing local open's and struct's. The file is available at:

	http://www.eleves.ens.fr/home/frisch/soft.html#openin

exemple:

module M = struct let x = 0 end
let y = open M in x top

-->

let y =
   let module OPENIN_1 = struct open M let res = x in
   OPENIN_1.res

========================================================================
4) Phantom types and polymorphic variants
Archive: http://caml.inria.fr/archives/200501/msg00252.html
------------------------------------------------------------------------
** Daniel Bünzli asked and Jacques Garrigue answered:

 > Suppose I have the following (well-typed) definitions
 >
 > > type tool = [`Spoon | `Fork]
 > >
 > > type 'a t = unit constraint 'a = [< tool]
 > >
 > > type 'a toolspec = unit constraint 'a = [< tool]
 > >
 > > let spoon : [< tool > `Spoon ] toolspec = ()
 > > let fork : [< tool > `Fork ] toolspec = ()
 > >
 > > let create : ([< tool ] as 'a) -> 'a t = fun t -> ()
 > > let create' : ([< tool ] as 'a) toolspec -> 'a t = fun t -> ()
 >
 > I don't really understand why the type of the value returned by create
 > and create' differ :
 >
 > > # create `Spoon;;
 > > - : [< Test.tool > `Spoon ] Test.t = ()
 > > # create' spoon;;
 > > - : [< Test.tool ] Test.t = ()
 >
 > I expected the second value to have the same type as the first.

The problem is that what you define here is not a phantom type.
To behave properly, phantom types must be abstract types (or, in ocaml
3.09, private types).
In particular, if they are simple type abbreviations, the type checker
will expand them before unification, and the parameters will never be
unified. This is why you get the type you gave as annotation, and
nothing more.
Even with normal sum types, unification would work, but variance
information  would allow to change the parameter through coercions,
making it useless as phantom type.

========================================================================
5) Ocaml-Packrat 0.1.0
Archive: http://caml.inria.fr/archives/200501/msg00266.html
------------------------------------------------------------------------
** Bardur Arantsson announced:

I'd like to announce the availability of version 0.1.0 of my Packrat
parser generator for OCaml, unimaginatively named OCaml-Packrat. The
tarball can be fecthed from

      
http://www.imada.sdu.dk/~bardur/personal/programs/ocaml-packrat/ocaml- 
packrat-0.1.0.tar.bz2

The following page provides a good overview of what packrat parsers are
(and how they are implemented):

     http://www.pdos.lcs.mit.edu/~baford/packrat/

The README includes usage notes, and an example grammar for parsing
simple expressions (with precedence) is included.

The following are prerequisites for building:

   - ExtLib>=1.3 is required, but the generated parsers do not depend on
   ExtLib. Removing the ExtLib dependency is one of the first things on  
my
   TODO list.

   - Findlib>=1.0.4 and OMake>=0.9.4 are used to build/install. You can
   do it without these, but you'd have to compile everything manually.

The current incarnation uses OCaml itself for specifying the grammars  
and
'actions' and generates an ML AST with the parser module as output. The
grammars are specified as lists and actions are specified using ML ASTs.
See the included example for details.

Finally, I should point out I haven't done any memory/time profiling  
yet,
so the current implementation is probably quite ineffcient.

Comments and suggestions welcomed.

========================================================================
6) Sourceforge Trove Categories
Archive: http://caml.inria.fr/archives/200501/msg00288.html
------------------------------------------------------------------------
** John Skaller said:

I should mention that as a Sourceforge developer I complained
that their Trove categorisation for developer skills had
a list of programming languages which did not include Ocaml.

I was informed recently that this system has been changed,
so that a more general categorisation is now used, which
does include Ocaml as a skills category (via the programming
languages category which did include Ocaml). This
note from the Sourceforge site therefore includes my
complaint as a feature request, and I believe the changes
they have done have resulted in a satisfactory fix.

"Software Map, Trove, Skills, Project Help Wanted: An initiative has
been completed to review and process all outstanding RFEs (Requests for
Enhancement, Feature Requests) related to addition of categories to the
Trove system, used for developer skills, the Software Map and the
Project Help Wanted systems. More than 200 requests have been reviewed
and processed, resulting in a more complete, well-managed category set
within the Trove system. Further, a process has been put in to place for
the regular review and processing of future requests for new Trove
categories. Projects are encouraged to review the categorization of
their projects to ensure it is listed in places that end-users would go
to look for software of that type."

I just wish my local Employment web site would include
Ocaml as a programming language (it has Simula, Cobol
and IBM JCL but no modern or scripting languages .. :(

========================================================================
7) yacc style
Archive: http://caml.inria.fr/archives/200501/msg00283.html
------------------------------------------------------------------------
** Deep inside a thread on parsing, Jean-Christophe Filliatre said:

When parsing C, the lexer  must produce different tokens for variables
identifiers  and  types identifiers,  otherwise  you may  misinterpret
things  like "a  * b"  (is it  the  declaration of  a pointer  b or  a
multiplication?) or casts. The following piece of code is illustrating
the difficulty:

======================================================================
int a, b;
typedef int t, u;
void f1() { a * b; }
void f2() { t * u; }
void f3() { t * b; }
void f4() { int t; t * b; }
void f5(t u, unsigned t) {
   switch ( t ) {
   case 0: if ( u )
     default: return;
   }
}
======================================================================

The  solution  is  to  have  the  parser  modifying  the  lexer  while
parsing. This is quite ugly in practice. The CIL framework includes a
full C parser written in ocaml, so you can get there one possible way
of handling this issue; see http://manju.cs.berkeley.edu/cil/

========================================================================
8) perl4caml 0.9.0
Archive: http://caml.inria.fr/archives/200501/msg00306.html
------------------------------------------------------------------------
** Richard Jones announced:

I'm pleased to announce the release of version 0.9.0 of perl4caml.

Perl4caml allows you to call Perl code and libraries directly from
OCaml code.  It is licensed under the LGPL + OCaml linking exception.

http://merjis.com/developers/perl4caml

The reason for the large jump in version number (0.3.15 was the last
release) is that I have fixed up a lot of reference counting problems
in the code, so now perl4caml should operate much more reliably, and
by default frees Perl objects at the correct time.  I have also added
a test suite ('make test') which exercises large parts of the library.

I have also wrapped up more CPAN classes, and added more coverage to
the existing wrappers.

========================================================================
9) '_a
Archive: http://caml.inria.fr/archives/200501/msg00253.html
------------------------------------------------------------------------
** Mike Hamburg said and Jacques Garrigue answered:

 > The appearance of '_a in places where it shouldn't appear causes some
 > annoyance, and a good deal of confusion among beginners to O'Caml.  In
 > particular, List.map (fun x -> x) "ought to" have type 'a list -> 'a
 > list, whereas it instead has type '_a list -> '_a list.
 >
 > Some types are treated specially for creation of '_a, such as refs and
 > arrays.  For instance, if you have the following two declarations:
 >
 > # let a = let f x () = [x] in f [];;
 > val a : unit -> 'a list list = <fun>
 > # let b = let f x () = [|x|] in f [];;
 > val b : unit -> '_a list array = <fun>
 >
 > Although I haven't read the code for O'Caml, I deduce from this that
 > there is deep magic in place to determine when to turn 'a into '_a,  
and
 > in many cases, the heuristic is wrong (in the conservative direction:
 > in this case, 'a should not be turned into '_a until b is applied).

There is no deep magic, no heuristics. There is just a type system
which guarantees type soundness (i.e. "well typed programs cannot
produce runtime type errors").

If you want the type system and all the historical details, read my
paper "Relaxing the value restriction" at
   http://wwwfun.kurims.kyoto-u.ac.jp/~garrigue/papers/

In a nutshell, ocaml uses an improvement of the value restriction.
With the value restriction, only definitions which are syntactical
values (i.e. that do not call functions, etc when defined) are allowed
to contain polymorphic type variables.
This is improved by allowing covariant type variables to be
generalized in all cases. Your first example is ok, because list is a
covariant type, but your second fails, because array is not (you may
assign to an array, and you would have to look at the code to see that
each call to b creates a different array)

Of course, one could think of many clever tricks by looking
at what the code actually does. The above paper describes some of the
"crazy" things Xavier Leroy and others tried in the past, which
actually subsume your ideas, before they all decided this was too
complicated. The main reason is that, if something is going to break
at module boundaries, then it is not really useful.

** Dave Berry added:

That's a very interesting paper.  I note that you ask

"Our examples with constructor functions and abstract datatypes were
expressible in
systems predating the value restriction, and are refused by the strict
value restriction.
This makes one wonder why this didn't cause more problems during the
transition."

At the time that SML'97 was being defined, I was working on Harlequin's  
SML
compiler and programming environment (which has long since vanished into
legal limbo).  The Harlequin team initially opposed the adoption of the
value polymorphism rule for precisely the reasons you give.  Eventually  
we
gave in because the other advantages outweighed the disadvantages.  (All
these discussions took place in private e-mail).

Basically, the touted advantages of adopting the value polymorphism  
rule were:

1. The formal semantics became simpler.
2. Eliminating the different types of type variable made the language
easier to explain, without affecting expressibility in practice.
3.  It enabled typeful compilation (as you note in your paper).

I have never believed either half of point 2.  The value polymorphism  
rule
means that you have to explain about references and their effect on type
inference even for some simple programs that don't use references at  
all,
such as the example that Mike gave.  This "raises the bar" for  
explaining
type inference to beginners.  Furthermore, expressiveness is affected  
for
the examples that you give in your paper.  We had to change several  
parts
of our code when we adopted the value polymorphism rule.  However, we  
felt
(and I still think) that points 1 and 3, particularly point 3, outweigh
these disadvantages.

  From a practical point of view, I like your approach.  However, it does
negate point 1 above, because it makes the formal semantics more complex
again - although this is less of a problem in O'Caml, because its  
semantics
are already so complicated compared to SML97.  (I do not intend that  
remark
as an insult). It will be interesting to see how your approach affects
point 2 - novices may still encounter the value restriction in a simple
program, and the new system will be more complicated to explain.

I sometimes wonder whether it would help to have a "pure" annotation for
function types that would require the implementation to not use  
references
nor to raise exceptions.  I don't mean a detailed closure analysis,  
just a
simple flag.  Most practical functions would not be pure, but many  
simple
ones could be, and these could be used to introduce people to the  
basics of
functional programming without raising the complication of the value
polymorphism rule.  (You wouldn't get a theory paper out of it
though).  Unfortunately I'm no longer working on programming languages  
and
so I don't have the capability to explore this.   It may be a half-baked
idea that doesn't work in practice.

========================================================================
10) C-threads & callbacks
Archive: http://caml.inria.fr/archives/200501/msg00173.html
------------------------------------------------------------------------
** Continuing last week's thread, Xavier Leroy answered Markus Mottl:

 > I'm currently interfacing a 3rd-party library that spawns threads
 > to execute callbacks.  I would like those callbacks to be handled by
 > OCaml-code, but have run into some issues here.
 >
 > As it seems, it is not possible to run OCaml-code linked with thread
 > support while letting C-threads perform callbacks.  This has already
 > been a topic on the list a while ago.

Correct.  This is still on my "to do" list.  It sounds feasible but
requires some intervention in the runtime system and the threading
library, so it's not something that can be done on the side by
3rd-party code.

========================================================================
11) cyclic types
Archive: http://caml.inria.fr/archives/200501/msg00315.html
------------------------------------------------------------------------
** Radu Grigore said and Damien Doligez answered:

 > For now I have setteled for
 >   type forest = Forest of forest StringMap.t
 >
 > Can you give an example of why rectypes by default is dangerous?

IIRC, rectypes are off by default because they trade a small increment
in expressive power for a large degradation of the intelligibility of
type-checking error messages.  I don't think they are dangerous in the
sense of breaking the type system.

** Xavier Leroy also answered:

 > For now I have setteled for
 >   type forest = Forest of forest StringMap.t

This is a very reasonable thing to do.  That, or compile with -rectypes.

 > Can you give an example of why rectypes by default is dangerous?

Recursive types don't break type soundness and are handled fine by the
OCaml typechecker -- objects and variants use them in an essential way.

The "danger" is that they cause obviously wrong code to pass
type-checking and receive "impossible" recursive types, so you notice
the problem not at the point of definition of the bad code, but at
point of use.  A simplified example is this:

       let f x = x :: x

where the author of that code really intended

       let f x = x @ x

With -rectypes, the wrong definition (with ::) is accepted with type

val f : ('a list as 'a) -> 'a list = <fun>

and it's only when you try to apply f to a "normal" list that the
problem arises, with a hard-to-understand error message:

f [1;2;3];;
    ^
This expression has type int but is here used with type 'a list as 'a

========================================================================
12) Debian apt-proxy/apt-cacher replacement
Archive: http://caml.inria.fr/archives/200501/msg00343.html
------------------------------------------------------------------------
** Eric C. Cooper announced:

Approx is a proxy server, written in OCaml, that can be used as an
alternative to apt-proxy or apt-cacher.  I've been using it for about
a month, and I find it faster and more robust than apt-proxy.

You can find the source and a Debian binary package at
     http://www.cs.cmu.edu/~ecc/software.html

(If any Debian gurus have suggestions on whether/how to announce this
to the broader Debian community, please contact me off-list.)

========================================================================
13) developing apps with ocaml exercices web pages
Archive: http://caml.inria.fr/archives/200501/msg00313.html
------------------------------------------------------------------------
** Radu Grigore asked and Stefano Zacchiroli answered:

 > The web pages with exercises in "Developing applications with OCaml"
 > are unreadable with mozilla/firefox (i guess that the "layer"
 > attribute "visibility" is ignored). Maybe there is a quick fix? I'd
 > rather have the solutions always visible (i.e. remove all related
 > javascript).

I while ago I patched the debian package of the o'reilly book to avoid
exercises texts and solution be layered one on top of the other (which
made both exercises and solutions unreadeable).

This is the relevant part of the package changelog:

   ocaml-book (1.0-3) unstable; urgency=low
   ...
   * {fr,en}/html/videoc.js
     - hacked JavaScript's {open,close}PopUp so that they output <div>
       and </div> tags around exercises' solutions. This avoid pop up
       mass on mozilla-like browsers. Solutions aren't popped up on
       request but at least they are available and exercises aren't
       hidden behind them (Closes: Bug#180799, Bug#185266)
   ...

You may have a look at the debian package and see if it fixes your
problem.

========================================================================
14) Ocaml license - why not GPL?
Archive: http://caml.inria.fr/archives/200501/msg00302.html
------------------------------------------------------------------------
** Editor's note:

There has been yet another huge thread on Ocaml's license. Please find  
below
some answers from members of the Ocaml team. You may read the whole  
thread online.

** Jozef Kosoru asked and Luc Maranget answered:

 > I would like to ask O'Caml developers why they have chosen QPL license
 > for the compiler and GPL for libraries?
 >
 > Of course they have a full right to choose a license they want but I
 > think that GPL for the compiler and LGPL for the libraries would be a
 > much better choice.

Hello,

Some explanations on the license choice for O'Caml can be found on
the web
http://caml.inria.fr/ocaml/LICENSE.html
It may answer some of your questions.

 >
 > Now it is for example impossible to distribute an O'Caml package as a
 > part of some O'Caml GPL project source package. Users have to know  
that
 > this program is written in some unusual programming language and they
 > have to download and compile the O'Campl compiler first. For them it
 > would be much better to just download the application sources and type
 > /configure; make; make install
 > .and build process would compile the ocaml compiler (if it's not  
already
 > present) and then compile application sources and install native
 > executable (just like C/C++ apps).

As far as I understand, nothing in a licence prevents easy configuration
and installation (and indeed installing Ocaml from the site
http://caml.inria.fr/index-eng.html is what you describe
(configure/make/make install)

As I see it, different packaging organizations have different policies
as regards licenses...

** Jacques Garrigue also answered:

 > I would like to ask O'Caml developers why they have chosen QPL license
 > for the compiler and GPL for libraries?
 >
 > Of course they have a full right to choose a license they want but I
 > think that GPL for the compiler and LGPL for the libraries would be a
 > much better choice.

Actually, this is already LGPL (with an exception to make it even more
liberal!) for the runtime and the libraries.
So your only problem with the QPL would be if you need to modify the
compiler itself, and are not happy with the conditions of the QPL.

 > Now it is for example impossible to distribute an O'Caml package as a
 > part of some O'Caml GPL project source package. Users have to know  
that
 > this program is written in some unusual programming language and they
 > have to download and compile the O'Campl compiler first. For them it
 > would be much better to just download the application sources and type
 > /configure; make; make install
 > .and build process would compile the ocaml compiler (if it's not  
already
 > present) and then compile application sources and install native
 > executable (just like C/C++ apps).

The QPL is an official open-source license.
There is nothing preventing you to include the compiler in your
package, as long as you make it clear that the compiler itself is
copyrighted and under the QPL.
(One question is whether you need to include all the tools and
libraries from the distribution, as the QPL seems to imply. I believe
this can be clarified with the developpers if needed.)

So I don't really see your problem...

** Alex Baretta said and Xavier Leroy answered:

 > Hmmm... This is an interesting point! The toplevel library includes
 > the compiler code, which is licensed under the QPL,

Correct.

 > but yet somehow must be allowed to link to GPLed libraries and
 > programs.

You meant: "I (Alessandro Baretta) needs to link it to GPLed libraries
and programs".  There is no moral imperative of being able to link
something with GPLed stuff.

 > If the toplevel library may not be linked with GPLed code,
 > then the toplevel itself become hardly usable,

Again, you meant "... usable to me because of my choice of the GPL".

 > and a significant
 > portion of my code,  which is GPLed and links the toplevel library,
 > would be illegal.
 > Might the caml breeders please comment on this issue?

Only if you stop calling me a "caml breeder".  Makes me feel like a
nuclear reactor :-)

More seriously:

- The toplevel library is indeed covered by the QPL.

- Clause 6 of the QPL is pretty clear.  In summary, it stipulates that
   a QPL-ed library can be linked with pretty much any code that is
   distributed as open source.  But please don't take my words for it:
   read the license.

- The problem in your case is most likely to be with the GPL, which
   puts much stronger requirements on any piece of code that comes
   in contact with GPL-ed code.  But don't take my word for it, as
   I have no expertise (and no interest) in license compatibility issues.
   Read the GPL, consult license experts, make up your mind.

- If it turns out you have a QPL/GPL incompatibility, you have exactly
   three options:
       1) don't use the toplevel library
       2) put your code under another license than the GPL
       3) get a more liberal license for OCaml by becoming a member
          of the Caml Consortium.

 > This bothers me quite a bit. Am I to expect a legal pursuit from INRIA
 > for violating the QPL for having released mixed GPL+QPL code?

No, because you didn't violate our license (the requirements set by
the QPL are met).

 > Or am I to pursue myself because the QPL breaks my own GPLed code?

This is more like it :-)  You, or your customers.  Remember,
inconsistent license = no license = nobody can do anything with your  
code.

 > I would really appreciate an official response from the INRIA people.  
I
 > think Ocaml is a great tool for commercial free software development,
 > but in order to be able to build a thriving business I must make sure
 > that Xavier et al. won't meet me with a team of Dobermans to settle
 > copyright issues...

Again, your problems are not with us.  The ones that could come after
you are your customers.

** Nicolas Cannasse said and Xavier Leroy answered:

 > If I understand well, Alex can choose the (3) and get a license that  
is GPL
 > compatible. But as it has been said before the only licenses  
compatible with
 > GPL are weaker license, that are "at least" GPL. So a company getting  
into
 > the Caml Consortium might get rights to redistribute the compiler as  
GPL ?
 > Are you sure about that ?

Yes, that would be allowed as part of the Consortium agreement.  But
you have to keep in mind that Consortium membership is a contract, not
a license, and that this contract is to be renewed every year.  This
means that INRIA can unilaterally refuse that someone becomes a member
of the consortium, or refuse to renew the membership.

So, if you come to us and say "I want to become a consortium member
and my sole purpose is to redistribute the OCaml compilers under the
GPL", your membership application will most likely be rejected.  And
if you don't tell us but become a member, then redistribute the OCaml
compilers under the GPL, your membership will not be renewed and
you'll lose your special privileges for subsequent OCaml releases.

However, if Alex Barretta comes to us with a licensing plan that
solves his issue but is acceptable to us (i.e. no GPL relicensing of
the whole OCaml compilers), we'll do our best to help.

You see, consortium membership is based on mutual trust and the desire
to do things that will be beneficial to both parties (the member and
INRIA).  Abuse is possible but won't get you very far (except being
labeled as a weasel).

========================================================================
Using folding to read the cwn in vim 6+
------------------------------------------------------------------------
Here is a quick trick to help you read this CWN if you are viewing it  
using
vim (version 6 or greater).

:set foldmethod=expr
:set foldexpr=getline(v:lnum)=~'^=\\{78}$'?'<1':1
zM
If you know of a better way, please let me know.

========================================================================
Old cwn
------------------------------------------------------------------------

If you happen to miss a CWN, you can send me a message
(alan.schmitt at polytechnique.org) and I'll mail it to you, or go take a  
look at
the archive (http://sardes.inrialpes.fr/~aschmitt/cwn/) or the RSS feed  
of the
archives (http://sardes.inrialpes.fr/~aschmitt/cwn/cwn.rss). If you  
also wish
to receive it every week by mail, you may subscribe online at
http://lists.idyll.org/listinfo/caml-news-weekly/ .

========================================================================

Alan Schmitt
-------------- next part --------------
A non-text attachment was scrubbed...
Name: PGP.sig
Type: application/pgp-signature
Size: 186 bytes
Desc: =?ISO-8859-1?Q?Ceci_est_une_signature_=E9lectronique_PGP?=
Url : http://lists.idyll.org/pipermail/caml-news-weekly/attachments/20050201/64be73da/PGP-0001.bin


More information about the caml-news-weekly mailing list