Re: [Caml-list] Binding the Lua library [was: adding a scripting language to an ocaml program]
Paolo Donadeo a écrit : So I wrote the binding to some basic functions and a stress test designed to reveal memory leaks of the binding. The test passed and so I consider the code quite stable, but I had to stop the development due to the chronic lack of time and due to a specific problem: I don't know how to handle the impedance mismatch between the two garbage collectors. Yes. This kind of issue is tough. I also had it in the OCaml-R code. And the solution is far from perfect, but works. I do not know about Lua, though. And again: how to translate (read: how to bind) in OCaml functions like these: void *lua_newuserdata (lua_State *L, size_t size); [4] or void *lua_touserdata (lua_State *L, int index); [5] Is Obj.magic the only possible way? It's ugly and, of course, "Obj.magic is not part of the OCaml language", but in this case you use a cast in C, so why not cast a spell in OCaml? You might want to check out the code sample I published here (at the bottom). http://ocaml.janestreet.com/?q=node/59 Unfortunately, using this recursive subtyping trick (which can be extended to more sophisticated recursive subtyping between more than 2 type systems) raises issues in the presence of OCaml classes: The compiler goes in an infinite loop when doing type inference. The issue should be solved in 3.12. It's not yet used in the OCaml-R binding because of compiler infinite loop problem. But it is used in my (unpublished) Python binding. If anyone is interested in my prototype I could clean up the source, remove comments in Italian and publish it on GitHub or OCamlCore. I'm always interested in language bindings... And I think a few other people are interested in an Lua binding. And, of course, any ideas or help on the garbage collector(s) issue are welcome. I do not know much about Lua's GC. My experience (for R, Python and Java) is that it's doable. The first shot is often imperfect and inefficient becauses GCs are not designed in the spirit of being binded. (R's API only provides a cumbersome stack-based mechanism to interact with R's GC, which is wholly inadequate). I guess that with more available time, it is indeed possible to do clean tricks in order to get the GCs to cooperate efficiently... (I have a few tricks in mind for R that will have to wait.) All the best, -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] adding a scripting language to an ocaml program
Guillaume Yziquel a écrit : I do not have much time available on this one, and I currently have other interests. But if someone is interested in the code, please email me to see what is possible to do... I mean: privately. All the best, -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] adding a scripting language to an ocaml program
Thomas Fischbacher a écrit : The last thing I remember is that Guillaume had contacted me about wanting to re-write it, but not much seems to have happened on that front so far. Well, things have happened on this front so far. And a few people have the code that I've written. Unfortunately, for rather awkward reasons, I am not in a position to release it. But hope to be in the rather not distant future. It's basically a rewrite. It works, but isn't fully featured yet. I believe memory management is done properly. There are also some C varargs functions in the Python API that have been properly binded with the libavr library (or something called like that). A (yet basic) syntax extension allows to write things like: module X = python module mypython module It does introspection and dumps the OCaml code needed to access values of the module. I've been hitting type inference issues in Python for this. But there is some work (like shedskin) to capitalise in order to make the syntax extension more interesting when it comes to typing. And there's a Debian package, also. Do not hold your breath on this code, as a release might take a while. But if someone is willing to carve out of shedskin the code needed to do type inference and bind it to OCaml, that would be a nice contribution to the syntax extension. I do not have much time available on this one, and I currently have other interests. But if someone is interested in the code, please email me to see what is possible to do... All the best, Guillaume Yziquel. -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
[Caml-list] Linking with libstdc++.so
Hello. I've been trying to compile a library with C++. With something like: ocamlc -verbose -a -dllib dllmystuff_stubs.so -dllib libstdc++ -o myStuff.cma myStuff.cmo However, on Debian systems, there is a libstdc++.so.5 and a libstdc++.so.6 file. No libstdc++.so file. So the -dllib libstdc++ option doesn't locate properly the library. How do you manage to have more control over the name of the library without resorting to using an ugly symlink in /usr/lib/ocaml/stublibs? All the best, Guillaume Yziquel. ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
[Caml-list] Sending compiler into an infinite loop or stack overflow.
Hello. Here is a compiler infinite loop / stack overflow error. In the toplevelm yuo get the following, but using ocamlc, you get an infinite loop. yziq...@seldon:~$ ocaml Objective Caml version 3.11.2 # type untyped;; type untyped # type -'a typed = private untyped;; type 'a typed = private untyped # type -'typing wrapped = private sexp and +'a t = 'a typed wrapped and sexp = private untyped wrapped;; type 'a wrapped = private sexp and 'a t = 'a typed wrapped and sexp = private untyped wrapped # class type ['a] s3 = object val underlying : 'a t end;; class type ['a] s3 = object val underlying : 'a t end # class ['a] s3object r : ['a] s3 = object val underlying = r end;; Fatal error: exception Stack_overflow I've tracked it down it down on some other but similar code to the Ctype module. Objective Caml Debugger version 3.11.1 (ocd) start Loading program... done. `start not meaningful in outermost frame. (ocd) step 6516537 Time : 6516537 - pc : 392692 - module Ctype 134 let name = match path with Path.Pident id -> <|b|>Ident.name id (ocd) run Time : 6516782 Program end. Uncaught exception: Stack_overflow (ocd) Unfortunately, I'm getting quite lost in the compiler source code, so I'd appreciate some background information on how to deal with this issue. All the best, Guillaume Yziquel. -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] Recursive subtyping issue
David Allsopp a écrit : Guillaume Yziquel wrote: Stéphane Glondu a écrit : Why don't you just declare 'a t to be synonym for obj in the implementation of your module, declare them as abstract in its interface, and export the specially typed identities f and g? Because subtyping seems more efficient than applying a noop function. I wholeheartedly agree that doing this in the type system is much cleaner than using noop/coercion functions but I don't think that there's any difference in terms of efficiency. If the noop/coercion functions are correctly coded then they will be of the form: external foo_of_bar : bar -> foo = "%identity" in *both* the .ml and .mli file for the module in question. I'm virtually certain that ocamlopt eliminates calls to the %identity primitive. yziq...@seldon:~$ grep magic /usr/lib/ocaml/obj.mli external magic : 'a -> 'b = "%identity" So far so good. Moreover, having conversion functions is not really handy, from a syntactic point of view: It's quite convenient to write something like let f : string -> obj :> string -> float t = blah blah blah... than doing the explicit, runtime, casting in the definition of f. Agreed - this is where your approach is really neat! I'm not so sure how far we can push the idea. You can, in one ':>', do subtyping at every type in the type 'a -> 'b -> 'c. This is quite handy. But I'll have to check in which way this can be integrated in the calling conventions of, say, Python. I then tried to go the whole way, and get rid of conversion functions altogether. Being pedantic, what you mean is getting rid of *coercion* functions; *conversion* functions could never eliminated OK. This is tremendously clean - as long as the types are clearly documented! The problem is that ocamldoc doesn't let you "document" coercions (by which I mean that having a conversion function provides means for the documentation of that particular usage). Thank you. The ocamldoc problem isn't really a problem, I believe. You just have to write it cleanly in bold letters. What is more a problem is the fact that inferred .mli files tend to leave out the contravariance on tau: http://caml.inria.fr/mantis/view.php?id=4988 And hence drops part of the subtyping facility. -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] Recursive subtyping issue
Stéphane Glondu a écrit : Guillaume Yziquel a écrit : Because subtyping seems more efficient than applying a noop function. And this code might run really often, so I do not like very much the idea of having noop functions running really often. FWIW, I don't think you have any penalty if you declare your identities as externals like Obj.{repr,obj,magic}. Yuk, some might say... but we are in the context of bindings to other languages anyway. Yuk indeed. The subtyping was also a way to avoid Obj.magic in the first place and keep doing things cleanly. I'm not so sure about runtime penalty in this context. Moreover, having conversion functions is not really handy, from a syntactic point of view: It's quite convenient to write something like let f : string -> obj :> string -> float t = blah blah blah... than doing the explicit, runtime, casting in the definition of f. It's more convenient for me write letters and parentheses than the symbol ":>" :-) That's a matter of taste, I guess :-) IIUC, these conversion function are not to be used often, are they? What you want is the equivalent of Obj.{repr,obj}, but for values of some other language, right? Yes, for the values of some other language. It depends: they are to be used often for people wanting to make bindings of R / Python code. (Even tough I plan to use syntax extensions to ease the pain, something like 'module Nltk = python module nltk'. But that's a long term perspective. For people using the binded code, subtyping shouldn't be necessary. Are you planning to leak your "tau", "typed" and "untyped" types out of the module? If so, inferred types are likely to refer to those, which might be very confusing (unless you resort to a lot of type annotations). If not, you'll have to use explicitly the coercion functions outside of the module anyway. Yes. I'm not satisfied with this. (Renaming 'tau' to 'wrapped' would be better, I guess). But somehow, I believe that it's an OCaml issue rather than an issue with my approach. I mean, why should it be impossible to *express* in the .mli file something like type 'a t = private obj and obj = private 'a t without resorting to extra intermediary types and contravariant phantom types? Couldn't we just dump the type inequations and co/contra-variance information (which would require another syntax for types, I guess)? But there's another problem for weirder typings that would need 3 different categories of types (R ?). 2 conversion functions is OK. 6 conversion functions is clearly a pain... And concerning R's quirky type system, I'm probably optimistic with the number 3. -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] Recursive subtyping issue
Stéphane Glondu a écrit : Guillaume Yziquel a écrit : # type untyped;; type untyped # type 'a typed = private untyped;; type 'a typed = private untyped # type -'typing tau = private obj and 'a t = 'a typed tau and obj = private untyped tau;; type 'a tau = private obj and 'a t = 'a typed tau and obj = private untyped tau # let f : 'a t -> obj = fun x -> (x : 'a t :> obj);; val f : 'a t -> obj = # let g : obj -> 'a t = fun x -> (x : obj :> 'a t);; val g : obj -> 'a t = # Why don't you just declare 'a t to be synonym for obj in the implementation of your module, declare them as abstract in its interface, and export the specially typed identities f and g? Because subtyping seems more efficient than applying a noop function. And this code might run really often, so I do not like very much the idea of having noop functions running really often. Moreover, having conversion functions is not really handy, from a syntactic point of view: It's quite convenient to write something like let f : string -> obj :> string -> float t = blah blah blah... than doing the explicit, runtime, casting in the definition of f. Haven't tried the line above, so do not quote me on this, but using covariance and contravariance can make your code cleaner, with less parentheses. What happened is that I was (am currently) doing only the 'a t :> obj subtyping in OCaml-R, and I also have a R.cast function to cast from obj to 'a t. I thought this solution was cleaner than having two conversion functions. I then tried to go the whole way, and get rid of conversion functions altogether. -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] Recursive subtyping issue
Goswin von Brederlow a écrit : Doing 'a t = private underlying allows you to create a type inference barrier. However, you also want to be able to cast from underlying to 'a t, when you get the result of a function in R or Python, for instance. So that's exactly the use case you mentionned above. Why not supply conversion functions that do any additional checks to ensure the conversion is a valid one? Consider the following: Because that's exactly what I try to avoid. R and Python are already slow enough and dynamically type-checked at every corner. I'm not happy to add another type-checking layer. But if you do not check then someone can convert a float q into w and back into int q. That would hide the error in the conversion until such a time as the type is later used in some function that does check the type. I would rather have those checks than go hunting for the real error for hours. Yes and no. In some sense, when you do bindings of C code, you do have to be careful. There's no reason that it should be different for binding Python code or R code. I mean, having a slick binding without dynamic type checks is, from my point of view, a good thing. But this subtyping is for the person binding R or Python code. The user of the binded code should not see any subtyping. That's the goal: having a good framework to do the bindings. Not exposing low level R or Python details the the OCaml coder using the bindings. I've been looking all over at this issue, but simply cannot find a way out. While experimenting on this, I've stumbled on a number of quirky issues with the type system. First one: http://ocaml.janestreet.com/?q=node/26 Second one: # type 'a q = ;; type 'a q = < m : 'a > # let f : 'a q -> 'a q = fun x -> x;; val f : 'a q -> 'a q = # let o = object method m : 'a. 'a -> 'a = fun x -> x end;; val o : < m : 'a. 'a -> 'a > = # f o;; Error: This expression has type < m : 'a. 'a -> 'a > but an expression was expected of type 'b q The universal variable 'a would escape its scope # All these issues seem to be somehow related, in a way I'm not yet able to articulate clearly. # class ['a] foo = object method map (f : 'a -> 'b) = ((Obj.magic 0) : 'b foo) end;; class ['a] foo : object method map : ('a -> 'a) -> 'a foo end As I recently learned there seems to be no way to make that actualy produce a 'b foo. I think that hits the same problem. MfG Goswin Will have a look at that when I find the time. -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] Recursive subtyping issue
Guillaume Yziquel a écrit : Guillaume Yziquel a écrit : Andreas Rossberg a écrit : On Feb 27, 2010, at 14:11, Guillaume Yziquel wrote: # type q = private w and w = private q;; type q = private w and w = private q # let f (x : q) = (x : q :> w);; val f : q -> w = # let f (x : q) = (x : w);; Error: This expression has type q but an expression was expected of type w # Interesting, but these are vacuous type definitions. In fact, I would call it a bug that the compiler does not reject them (it does when you remove at least one of the "private"s). In any case, I don't quite understand how this pathological behaviour is supposed to help, because the types are uninhabited anyway. From OCaml world exclusively, yes, they are uninhabited. I'm using C code to populate these types. [...] you then have an interesting way to type Python code that you want to bring to OCaml. That's the purpose. Got it! Hope it may be useful for others: Here's a cleaner version, without the object type system: yziq...@seldon:~$ ocaml Objective Caml version 3.11.2 # type untyped;; type untyped # type 'a typed = private untyped;; type 'a typed = private untyped # type -'typing tau = private obj and 'a t = 'a typed tau and obj = private untyped tau;; type 'a tau = private obj and 'a t = 'a typed tau and obj = private untyped tau # let f : 'a t -> obj = fun x -> (x : 'a t :> obj);; val f : 'a t -> obj = # let g : obj -> 'a t = fun x -> (x : obj :> 'a t);; val g : obj -> 'a t = # -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] Recursive subtyping issue
Guillaume Yziquel a écrit : Andreas Rossberg a écrit : On Feb 27, 2010, at 14:11, Guillaume Yziquel wrote: # type q = private w and w = private q;; type q = private w and w = private q # let f (x : q) = (x : q :> w);; val f : q -> w = # let f (x : q) = (x : w);; Error: This expression has type q but an expression was expected of type w # Interesting, but these are vacuous type definitions. In fact, I would call it a bug that the compiler does not reject them (it does when you remove at least one of the "private"s). In any case, I don't quite understand how this pathological behaviour is supposed to help, because the types are uninhabited anyway. From OCaml world exclusively, yes, they are uninhabited. I'm using C code to populate these types. [...] you then have an interesting way to type Python code that you want to bring to OCaml. That's the purpose. Got it! Hope it may be useful for others: yziq...@seldon:~$ ocaml Objective Caml version 3.11.2 The rectypes option is not necessary here. # type -'a tau = private q and 'a w = < m : 'a > tau and q = private < > tau;; type 'a tau = private q and 'a w = < m : 'a > tau and q = private < > tau We're using the < m : 'a > :> < > subtyping with contravariant polymorphism to get q :> < > tau :> < m : 'a > tau = 'a w. The converse is rather easy: 'a w = < m : 'a > tau :> q. # let f : 'a w -> q = fun x -> (x : 'a w :> q);; val f : 'a w -> q = # let g : q -> 'a w = fun x -> (x : q :> 'a w);; val g : q -> 'a w = So this subtyping type checks correctly. # let h : 'a w -> q = fun x -> x;; Error: This expression has type 'a w = < m : 'a > tau but an expression was expected of type q # And the two types are not equivalent. As this opens the way to correctly typing dynamic languages bindings for OCaml (at least in my humble point of view), I'd like to know what the bug/feature type q = private w and w = private q with q != w will become in the future. -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] Recursive subtyping issue
Andreas Rossberg a écrit : On Feb 27, 2010, at 14:11, Guillaume Yziquel wrote: # type q = private w and w = private q;; type q = private w and w = private q # let f (x : q) = (x : q :> w);; val f : q -> w = # let f (x : q) = (x : w);; Error: This expression has type q but an expression was expected of type w # Interesting, but these are vacuous type definitions. In fact, I would call it a bug that the compiler does not reject them (it does when you remove at least one of the "private"s). It does indeed reject them without the private keyword, even with the rectypes option. I'd appreciate a statement from someone of the OCaml team as to whether this is a bug or a feature. Because I intend to use this feature in my code. In any case, I don't quite understand how this pathological behaviour is supposed to help, because the types are uninhabited anyway. From OCaml world exclusively, yes, they are inhabited. I'm using C code to populate these types. Say you have what I would like to have, i.e. type 'a t = private obj and obj = private 'a t then you could have an external get_value : string -> obj = "my_get_value" you could then retrieve a value for a Python function and another as its argument. They are both obj, but you could subtype them respectively to a (string -> int) t and to a string t. Suppose you also have defined an external eval : ('a -> 'b) t -> 'a t -> 'b t = "my_eval" you then have an interesting way to type Python code that you want to bring to OCaml. That's the purpose. I've been looking all over at this issue, but simply cannot find a way out. While experimenting on this, I've stumbled on a number of quirky issues with the type system. First one: http://ocaml.janestreet.com/?q=node/26 That's indeed a slight oversight in the design of the module type system. (FWIW, this is possible in SML.) Very probably. It seems that the author, 'skweeks', comes from the SML world. Second one: # type 'a q = ;; type 'a q = < m : 'a > # let f : 'a q -> 'a q = fun x -> x;; val f : 'a q -> 'a q = # let o = object method m : 'a. 'a -> 'a = fun x -> x end;; val o : < m : 'a. 'a -> 'a > = # f o;; Error: This expression has type < m : 'a. 'a -> 'a > but an expression was expected of type 'b q The universal variable 'a would escape its scope This example would require full impredicative polymorphism, because you would need to instantiate 'a q with a polymorphic type. Yes. The ML type system does not support that, because it generally makes type inference undecidable. Could you sum up, in a nutshell, the argument that concludes to undecidability of such a type system? But see e.g. Le Botlan & Remy's work on ML^F for a more powerful approach than what we have today. Thanks. /Andreas Still looking for workarounds... I've still got a few ideas to develop, but I'va got a feeling that I'm running short on oil, here... -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] Recursive subtyping issue
Goswin von Brederlow a écrit : Guillaume Yziquel writes: My goal is to implement a type inference barrier. You can do type 'a q = private w and from the type inference point of view, int q and float q are two distinct types, that you can subtype to a common type. What I want is also to have the reverse, i.e. type w = private 'a q But that doesn't work out this way because of the fact that 'a is unbound. But then int q :> w :> float q and float q :> w :> int q. That would make the whole thing somewhat pointless. Everyone could convert the type to anything. I guess it would protect from accidentally passing the wrong 'a q while allowing purposefully to pass any 'a q. Exactly. It's the situation you have when you're trying to do OCaml binding of libraries written in dynamic languages: You want to have type inference on the side of semantics, hence a typing reflecting this. Bt you also want to type lower-level details about objects. This last sentence is not so true with Python, for instance, but with R, it is (despite the argument I had with Simon Urbanek on the r-devel@ mailing list). You want to have an 'a t type with 'a reflecting the corresponding typing in OCaml. And an 'underlying' type representing the low-level value. Doing 'a t = private underlying allows you to create a type inference barrier. However, you also want to be able to cast from underlying to 'a t, when you get the result of a function in R or Python, for instance. So that's exactly the use case you mentionned above. Why not supply conversion functions that do any additional checks to ensure the conversion is a valid one? Consider the following: Because that's exactly what I try to avoid. R and Python are already slow enough and dynamically type-checked at every corner. I'm not happy to add another type-checking layer. module M : sig type w = Int of int | Float of float Ugly. (IMHO) type 'a q = private w val add : 'a q -> 'a q -> 'a q val print : w -> unit val as_int : w -> int q val as_float : w -> float q Ugly. (IMHO) end = struct I've been looking all over at this issue, but simply cannot find a way out. While experimenting on this, I've stumbled on a number of quirky issues with the type system. First one: http://ocaml.janestreet.com/?q=node/26 Second one: # type 'a q = ;; type 'a q = < m : 'a > # let f : 'a q -> 'a q = fun x -> x;; val f : 'a q -> 'a q = # let o = object method m : 'a. 'a -> 'a = fun x -> x end;; val o : < m : 'a. 'a -> 'a > = # f o;; Error: This expression has type < m : 'a. 'a -> 'a > but an expression was expected of type 'b q The universal variable 'a would escape its scope # All these issues seem to be somehow related, in a way I'm not yet able to articulate clearly. -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] Recursive subtyping issue
Andreas Rossberg a écrit : On Feb 27, 2010, at 02:52, Guillaume Yziquel wrote: I've been struggling to have a type system where I could do the following subtyping: 'a t1 :> t2 and t2 :> 'a t1 Hm, what do you mean? Subtyping ought to be reflexive and antisymmetric (although the latter is rarely proved for most type systems), which means that your two inequations will hold if and only if 'a t1 = t2, regardless of recursive types. /Andreas Antisymmetric? yziq...@seldon:~$ ocaml Objective Caml version 3.11.2 # type q = private w and w = private q;; type q = private w and w = private q # let f (x : q) = (x : q :> w);; val f : q -> w = # let f (x : q) = (x : w);; Error: This expression has type q but an expression was expected of type w # Not exactly, it seems. My goal is to implement a type inference barrier. You can do type 'a q = private w and from the type inference point of view, int q and float q are two distinct types, that you can subtype to a common type. What I want is also to have the reverse, i.e. type w = private 'a q But that doesn't work out this way because of the fact that 'a is unbound. You can move around this specific problem by using contravariant polymorphism, as is done in my previous email, but somehow, you cannot have a recursive subtyping from 'a q to w and from w back to 'a q. There always seem to be something wrong, with a problematic more or less analoguous to adjoint functors in category theory. Hence my last email. All the best, -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
[Caml-list] Recursive subtyping issue
Hello. I've been struggling to have a type system where I could do the following subtyping: 'a t1 :> t2 and t2 :> 'a t1 So I've tried to do the following: yziq...@seldon:~$ ocaml Objective Caml version 3.11.2 # #rectypes;; # module Q = struct type -'a e type 'a q = private w and w = w e and 'a r = 'a q e end;; module Q : sig type -'a e type 'a q = private w and w = w e and 'a r = 'a q e end It almost seems to work: # let f x = (x : Q.w Q.e :> 'a Q.q Q.e);; val f : Q.w Q.e -> 'a Q.q Q.e = # let f' x = (x : Q.w :> 'a Q.r);; val f' : Q.w -> 'a Q.r = # let g x = (x : 'a Q.q :> Q.w);; val g : 'a Q.q -> Q.w = We can subtype from 'a Q.q to Q.w and from Q.w to 'a Q.r. So I now only need to equate 'a Q.r with 'a Q.q in one way or another... I therefore tried the following, unsuccessfully: # module W = struct type -'a e = ('a -> unit) q and 'a q = private w and w = w e and 'a r = 'a q e end;; Error: The type abbreviation q is cyclic # What's going wrong? And how can one get to do the proposed recursive subtyping? -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] Wrapping var_args, or C ... in ocaml?
Guillaume Yziquel a écrit : Florent Monnier a écrit : Le dimanche 14 février 2010 23:46:10, Guillaume Yziquel a écrit : I mean, it seems that varargs means on the receiving end "the number of arguments you'r giving me, as a function, is not limited", whereas on the sending end, you hard-code the number of arguments in your C code. Is there a way to map an OCaml list to an ellipsis? Or is it a C limitation? Yes, as long as I know, for this you should use these kind of tools: http://sourceware.org/libffi/ http://www.gnu.org/software/libffcall/avcall.html http://www.nongnu.org/cinvoke/ Phew! These tools are quite tough to handle! (I just tried to use avcall.h on this ellipsis.) Got it. The correct code is: CAMLprim value ocamlpython_py_tuple_pack (value ml_len, value ml_pyobjs) { av_alist argList; PyObject * retVal; av_start_ptr(argList, &PyTuple_Pack, PyObject*, &retVal); #if defined(__s390__) || defined(__hppa__) || defined(__cris__) #define av_Py_ssize_t av_long #else #define av_Py_ssize_t av_int #endif av_Py_ssize_t(argList, Pyoffset_val(ml_len)); while (ml_pyobjs != Val_emptylist) { av_ptr(argList, PyObject*, Pyobj_val(Field(ml_pyobjs, 0))); ml_pyobjs = Field(ml_pyobjs, 1); } av_call(argList); return(Val_owned_pyobj(retVal)); } Hope that will be useful to people wishing to wrap up varargs (though it's probably a bad idea, since the stack is limited...) Python function calls are now possible by constructing the argument tuple. -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
[Caml-list] Re: Embedding OCaml - manual not up to date.
Guillaume Yziquel a écrit : Hi. The manual is not up to date when it comes to embedding OCaml code into C code. http://caml.inria.fr/pub/docs/manual-ocaml/manual032.html#toc134 Specifically the section 18.7.5 Embedding the Caml code in the C code and the piece of compilation code I'm having trouble with is the following: ocamlopt -output-obj -o camlcode.o unix.cmxa other .cmx and .cmxa files cc -o myprog C objects and libraries \ camlcode.o -L/usr/local/lib/ocaml -lunix -lasmrun This code complains about missing symbols from pervasives. So I adapt it by compiling with pervasives.cmx, and I get ocamlopt -output-obj -o camlcode.o pervasives.cmx ld: /usr/lib/ocaml/pervasives.o: No such file: No such file or directory File "caml_startup", line 1, characters 0-1: Error: Error during linking make: *** [camlcode.o] Erreur But I cannot find pervasives.o anywhere. Well I found it in stdlib.a, but looking back at the thread started by Aaron Bohannon mid-december http://caml.inria.fr/pub/ml-archives/caml-list/2009/12/3375527140f0de987a9dc6d2553990c8.en.html it seems to me that there is little need for the -output-obj option, as shown in the manual. Why not document the embedding by simply compiling the C code tha provides the main function, which itself calls caml_startup, and then linking it with the .cmx with ocamlopt? Why the need for -output-obj, libasmrun.a, etc...? -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
[Caml-list] Embedding OCaml - manual not up to date.
Hi. The manual is not up to date when it comes to embedding OCaml code into C code. http://caml.inria.fr/pub/docs/manual-ocaml/manual032.html#toc134 Specifically the section 18.7.5 Embedding the Caml code in the C code and the piece of compilation code I'm having trouble with is the following: ocamlopt -output-obj -o camlcode.o unix.cmxa other .cmx and .cmxa files cc -o myprog C objects and libraries \ camlcode.o -L/usr/local/lib/ocaml -lunix -lasmrun This code complains about missing symbols from pervasives. So I adapt it by compiling with pervasives.cmx, and I get ocamlopt -output-obj -o camlcode.o pervasives.cmx ld: /usr/lib/ocaml/pervasives.o: No such file: No such file or directory File "caml_startup", line 1, characters 0-1: Error: Error during linking make: *** [camlcode.o] Erreur But I cannot find pervasives.o anywhere. -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] Wrapping var_args, or C ... in ocaml?
Richard Jones a écrit : On Mon, Feb 15, 2010 at 12:13:17AM +0100, Guillaume Yziquel wrote: Richard Jones a écrit : On Sun, Feb 14, 2010 at 11:46:10PM +0100, Guillaume Yziquel wrote: However I'm still confused what you are trying to do here. If you're trying to bind the above, maybe look first at PyCaml? Well, somehow, PyCaml seems to never have wanted to work with me. I tried Art Yerkes' version, Thomas Fishbacher's version, Henrik Stuart's version, and Yoann Padioleau's merge of these versions. Somehow things always seem wrong. I get a segfault with Yoann Padioleau's version due to the layout of the Python table function (WTF!? BTW). So I'm rewriting a Python embedding. http://yziquel.homelinux.org/gitweb/?p=ocaml-python.git;a=shortlog;h=refs/heads/yziquel http://yziquel.homelinux.org/debian/pool/main/o/ocaml-python/ http://yziquel.homelinux.org/topos/api/ocaml-python/Python.html Sample session: yziq...@seldon:~$ ocaml Objective Caml version 3.11.1 # #use "topfind";; - : unit = () Findlib has been successfully loaded. Additional directives: #require "package";; to load a package #list;; to list the available packages #camlp4o;;to load camlp4 (standard syntax) #camlp4r;;to load camlp4 (revised syntax) #predicates "p,q,...";; to set these predicates Topfind.reset();; to force that packages will be reloaded #thread;; to enable threads - : unit = () # #require "python.interpreter";; /usr/lib/ocaml/python: added to search path /usr/lib/ocaml/python/python.cma: loaded /usr/lib/ocaml/python/oCamlPython.cmo: loaded # open Python;; # let dolfin = Module.import "dolfin";; val dolfin : Python.pymodule Python.t = # let dictionary = Module.get_dict dolfin;; val dictionary : Python.dict Python.t = # let keys = Dict.keys dictionary;; val keys : string list Python.t = # let key_list = list_from keys;; val key_list : string Python.t list = [; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ...] # let string_list = List.map string_from key_list;; val string_list : string list = ["restriction"; "gt"; "precedence"; "TrialFunctions"; "ale"; "as_tensor"; "cross"; "__path__"; "shape"; "PETScFactory"; "has_mpi"; "down_cast"; "differentiation"; "Mesh"; "has_scotch"; "rot"; "has_slepc"; "DOLFIN_PI"; "begin"; "le"; "outer"; "VectorElement"; "parameters"; "ln"; "uBLASVector"; "uBLASDenseMatrix"; "tr"; "Assembler"; "terminal"; "UnitCube"; "lt"; "CRITICAL"; "hermite"; "derivative"; "logger"; "uBLASDenseFactory"; "norm"; "MPI"; "info"; "triangle"; "R1"; "R2"; -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] Wrapping var_args, or C ... in ocaml?
Richard Jones a écrit : On Sun, Feb 14, 2010 at 11:46:10PM +0100, Guillaume Yziquel wrote: Not the case. [etc] It would help if you were to be more specific about the function that you're trying to bind. http://docs.python.org/c-api/arg.html There's quite a few there... -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] Wrapping var_args, or C ... in ocaml?
Richard Jones a écrit : On Sun, Feb 14, 2010 at 04:46:20PM +0100, Guillaume Yziquel wrote: Hello. I'm currently looking at: http://docs.python.org/c-api/arg.html and I would like to know how to wrap up C functions with va_list of with an ellipsis. Is this documented somewhere, or has someone already done something like this? It really depends on the function and how it will be used. It might translate to any of: (1) A collection of functions implementing different aspects of the C function. eg. The open(2) function in Unix is really a varargs function, and depending on whether you want to open a file for input, output, create, etc. you'd probably be better off with different functions in OCaml. (Unix.openfile does _not_ do this ...) Not the case. (2) A simple list, eg. for a C function that takes a NULL-terminated list of strings. Could be. (3) A variant list of variants, or option labels, eg. for a C function that takes 'type, value'(s), such TIFFSetField in libtiff. (http://www.remotesensing.org/libtiff/man/TIFFSetField.3tiff.html) No. (4) Something very specialized, eg. the 'printw' function in ncurses is like printf and so would need quite a tricky implementation in OCaml. (Probably best to use ksprintf to convert to a string in OCaml and then pass printw ("%s", str) in C). I do not think so. In libguestfs where we autogenerate bindings we avoided varargs altogether, because it's hard to map such a concept to all the different languages we support. True. But, I mean, from the point of view of the ABI, there's not much trickery in the concept. It looks that it is C that is not mapping the concept to its fullest potential. I mean, it seems that varargs means on the receiving end "the number of arguments you'r giving me, as a function, is not limited", whereas on the sending end, you hard-code the number of arguments in your C code. Is there a way to map an OCaml list to an ellipsis? Or is it a C limitation? -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
[Caml-list] Wrapping var_args, or C ... in ocaml?
Hello. I'm currently looking at: http://docs.python.org/c-api/arg.html and I would like to know how to wrap up C functions with va_list of with an ellipsis. Is this documented somewhere, or has someone already done something like this? -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
[Caml-list] [ANN] OCaml-R binding for the R language.
This post is to announce the 0.2 release of OCaml-R. OCaml-R is a binding embedding the R interpreter into Objective Caml code. Home page: http://home.gna.org/ocaml-r/ Download page: http://download.gna.org/ocaml-r/ Deb packages: http://yziquel.homelinux.org/debian/pool/main/o/ocaml-r/ Tutorial: http://home.gna.org/ocaml-r/gettingstarted.en.html OCamlDoc API: http://yziquel.homelinux.org/topos/api/ocaml-r/index.html http://home.gna.org/ocaml-r/refdoc/index.html The goal of OCaml-R is to provide adequate integration of the R interpreter into Objective Caml, and a framework suitable to bind R library into OCaml code. Version 0.2 is a near-complete rewrite of the 0.1 version by Maxence Guesdon, with an incompatible API. Main features are: - Safe handling of R default environment variables at compile time, following what is done in littler. - R Signal handlers do not conflict with OCaml code. - Integration with findlib, enabling the #require "R.interpreter" to initialise statically the R interpreter. Compiling with 'ocamlfind ocamlopt -package R.interpreter' also initialises the R interpreter at compile-time, so to speak. - Some (most?) functionalities of the R standalone library are wrapped. - Low-level binding, in the sense that you construct low-level R calls to execute them. You can also parse R code to execute it, if you wish. - R exceptions are chained back to Objective Caml. - R's garbage collector is chained with OCaml's garbage collector. This is done rather inefficiently for the moment (freeing n R values in O(n^2) time complexity), and we expect to bring this down to O(n) with a thin garbage collecting layer in the future. - We provide a double typing scheme, with some subtyping features. A first typing mimics the dynamic typing of the R language, while a second typing, for the end-user, aims at providing a static typing of R values and functions. (This can be bettered). - S3 classes are supported (static typing is however still unsatisfying). S4 classes are not yet supported. Help welcome. - Some basic R datatypes, such as dataframes, are wrapped, and a framework to wrap the standard library has been put in place. - Basic data structures can be converted back and forth between OCaml and the R interpreter. - Ability to inspect (read-only) the inner structure of R values, which is quite convenient: you get to know rather quickly what a given piece of R code returns, which you need to know to type R code statically in order to bind it to OCaml. - Not thread-safe at all. At least, not more than R is... Lwt-style multithreading of R code could be possible, modulo some simple and deep (i.e. below R API) changes in the R evaluation functions. POSIX threading a single R thread with multiple OCaml threads is not yet possible, but is within reach. - Doesn't interact well the R "Defaults" package. While most of the code sticks or could stick to the R API, or at least to the public part of the R headers, there are some functionalities which are outright out of the scope of the R API. Some of these functionalities are for convenience only (i.e. inspecting internals of R values), while others are crucial to the binding (chaining R exceptions to OCaml). Hopefully, this lays down a foundation on which one could import R functionalities, libraries and packages to OCaml. -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] define incompatible type
David Allsopp a écrit : David Rajchenbach-Teller wrote: Hi Grégoire, It's not directly possible in OCaml, but there are at least three methods for doing what you want. The first one is to wrap your integers behind a constructor, e.g. You can also use (post OCaml 3.11.0) private types if you want to be able to use the ID values as integers but only explicitly. Private types is indeed the way to go. For instance, imagine that you have value wrapping C pointers. You may want to declare something like: type pointer type type_1 = private pointer type type_2 = private pointer When you write your code, you essentially use only types type_1 and type_2. The type inference system won't look into the "private" part of the type, so the type checker will cough on something like function (x : type_1) (y : type_2) -> x = y But, you can subtype (i.e. use :> to tell the typechecker to use the private declaration). And this will be valid OCaml: function (x : type_1) (y : type_2) -> (x :> pointer) = (y :> pointer) -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
[Caml-list] debugging in toplevel
Hi. I've been working on Yoann Padioleau's version of ocaml-python bindings. I unfortunately get the following error: yziq...@seldon:~$ ocaml Objective Caml version 3.11.1 # #use "topfind";; - : unit = () Findlib has been successfully loaded. Additional directives: #require "package";; to load a package #list;; to list the available packages #camlp4o;;to load camlp4 (standard syntax) #camlp4r;;to load camlp4 (revised syntax) #predicates "p,q,...";; to set these predicates Topfind.reset();; to force that packages will be reloaded #thread;; to enable threads - : unit = () # #require "python";; /usr/lib/ocaml/unix.cma: loaded /usr/lib/ocaml/str.cma: loaded /usr/lib/ocaml/python: added to search path /usr/lib/ocaml/python/pycaml.cma: loaded Exception: Invalid_argument "index out of bounds". # How do you debug something like this? ocamldebug and #trace do not seem to be very useful. What would you recommend doing to debug this toplevel error? -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] The need to specify 'rec' in a recursive function defintion
Gerd Stolpmann a écrit : Am Dienstag, den 09.02.2010, 22:58 +0100 schrieb Guillaume Yziquel: Gerd Stolpmann a écrit : Am Dienstag, den 09.02.2010, 15:50 -0500 schrieb Saptarshi Guha: Besides the different way of defining "let" and "let rec" there are also differences in typing. Well, at least you can have new effects. Look for "polymorphic recursion". You mean something like this? http://alaska-kamtchatka.blogspot.com/2009/05/polymorphic-recursion.html With the following code type length = { length : 'a . int -> 'a vec -> int } let length v = let rec f = { length = fun n l -> match l with Nil -> n | Zerops -> f.length (2 * n) ps | One (_, ps) -> f.length (1 + 2 * n) ps } in f.length 0 v you get to use a function, here f.length, in two different contexts for type inference, allowing it to be used with multiple types? 'a * 'a instead of 'a? Am I getting this post right? But then, this seems to go into rather elaborate constructions (existential types with OCaml records), which are quite remote from the simple 'let rec' issue we were talking about. Is it possible to have polymorphic recursion with vanilla 'let rec' invocations? Or am I getting you wrong? All the best, -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] The need to specify 'rec' in a recursive function defintion
Gerd Stolpmann a écrit : Am Dienstag, den 09.02.2010, 15:50 -0500 schrieb Saptarshi Guha: Besides the different way of defining "let" and "let rec" there are also differences in typing. Which ones? Gerd -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] The need to specify 'rec' in a recursive function defintion
Saptarshi Guha a écrit : Hello, I was wondering why recursive functions need to be specified with "rec". According to Practical Ocaml, to "inform the compiler that the function exists". But when entering the function definition, can't the compiler note that the function is being defined so that when it sees the function calling itself, it wont say "Unbound value f"? Essentially, the fact that "rec" means anything is mostly due to the fact that you want to be able to redefine stuff. let f = fun x -> x + 1 let f x = f (f x) is valid in ocaml, and you're function f is the function that adds 2. whereas let rec f x = f (f x) has a completely different meaning. If you avoided the use of rec, saying "if unbound, assume rec", then the line let f x = f (f x) has two entirely different meaning, depending on whether f is defined before or not. That would be quite a chaotic feature. Wouldn't one of way of detecting a recursive function would be to see if the indeed the function calls itself? No. Because you never know if you intended to call the function recursively, or if you intended to call an homonymous function you defined before. All the best, -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] camlp4
Guillaume Yziquel a écrit : Tiphaine Turpin a écrit : Andy Ray a écrit : What should one do? Complaining on the list about lack of camlp4 documentation is a good start :-). To help you decide (and increase the pressure on the Ocaml team), I would like to mention some of the difficulties that I encountered when trying to understand camlp4 as a user: -2- A good hands-on introduction, to be read in conjunction with up-to-date camlp4 code: http://martin.jambon.free.fr/extend-ocaml-syntax.html http://ambassadortothecomputers.blogspot.com/search/label/camlp4 is also a good link, covering the essentials to get started with camlp4, I think. -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] Re: How to wrap around C++?
Luca de Alfaro a écrit : Thank you very much! I follow the general lines, but... * Wrap your OCaml includes in 'extern "C" { ... }" Here, I am not sure what you mean. You mean, extern "C" { #include ... } ? See the code in my email: /* Including OCaml system. */ #define CAML_VALUE value extern "C" { #include #include #include #include #include #include #include } on one hand, and extern "C" CAML_VALUE _wrap_tokenizer_tokenize (CAML_VALUE ocaml_arg1, CAML_VALUE ocaml_arg2) { CAMLparam0(); SWIG_CAMLlocal1(caml_result); tokenizer *arg1 = (tokenizer *) 0 ; std::string *arg2 = 0 ; CAMLxparam1(ocaml_arg1); CAMLxparam1(ocaml_arg2); std::list< word > result; arg1 = *((tokenizer * *) Data_custom_val(ocaml_arg1)); { std::string arg2_str(String_val(ocaml_arg2), caml_string_length(ocaml_arg2)); arg2 = &arg2_str; } result = (arg1)->tokenize((std::string const &)*arg2); { caml_result = caml_alloc_custom(&custom_swigtype_ocaml_operations, sizeof (void *), 0 ,1); *((void **) Data_custom_val(caml_result)) = new std::list< word >((const std::list< word > &)result); } CAMLreturn(caml_result); } on the other... * Export all your stub functions with C linkage (extern "C") Ok, evidently, I need to learn this extern "C" construct. Yes. It's essentially here to cope with C++ name mangling. * Compiling is tricky, since the OCaml compiler driver doesn't know what to do with C++. The Swig documentation[1] has a workaround for this, useful even if you don't use Swig. Why would the Ocaml compiler driver need to know what to do with C++? Because it knows how to compile C, but doesn't know how to compile C++. The C++ I need to link to is rather huge, and I will need to compile it with its own build setup. Compile your C++ on one hand as you usually would. No issue there. You could even wrap a .so file generated from C++ code without knowing anything about the source code of the .so file. OK, except headers, and vendor info and version info of your C++ compiler. But, you have to compile the C glue as above with extern "C" and the trick I gave you in the Makefile, which btw come from the Swig website. Once that is built, I need to compile the stubs, the Ocaml, and link the three together (Ocaml, stubs, and C++), in native mode, but why would the Ocaml compiler need to deal with C++? The OCaml compiler does not deal with C++. It only knows about C. It's the C stub that need to: -1- be linked in OCaml code, and therefore, no C++ name mangling exported from these C stubs, hence the export "C". -2- be linked with C++ code. Hence the C++ code within the Extern "C" brackets. Another question: I could also try to do the vice-versa, and use Ocaml as libraries from C++. Has anybody tried doing this? Is it easy to do? I would stick with embedding C++ code into OCaml than the reverse. It's likely that you'd get more answers this way. Luca -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] Re: How to wrap around C++?
Luca de Alfaro a écrit : I am trying another approach... it might make more sense for me to embed the Ocaml into C++. This is not the way you'll get the most help out of this list. People are more familiar with making C bindings. Making C++ bindings is rather close to it. I have read the instructions, and it seems feasible, except that I have a few questions: - All I need to pass, as arguments, are int, float, string, and arrays of these. Any example of how to deal with the arrays? You need to construct them from C side, and it's more a pain than taking C structs and wrapping them into OCaml. The manual describes the structure of OCaml values rather precisely. There are also some pages by Richard Jones on his blog which explain rather nicely the internals of OCaml values. One advice: stick to the macros provided. Do not try to construct manually, say, OCaml strings on the C side. Use caml_copy_string and friends. - How can I return arrays, in a way that C or C++ understands? How can I return tuples, i.e., how can I return multiple values from Ocaml to C? These are documented in the manual and in Richard Jones' blog. For couples, you can do value couple = caml_alloc(2, 0); Store_field(couple, 0, my_ocaml_val); Store_field(couple, 1, my_other_ocml_val); For arrays, you'll have seamless integration by using Bigarrays. - Finally, do I need to worry about the Ocaml garbage collector, if I call Ocaml from C/C++? Will it run every now and then? How can the garbage collector know whether a value returned by an Ocaml function is still being used in C/C++? How can I tell it that it is no longer used? Essentially, the garbage collector will run potentially each time you allocate an OCaml value. caml_copy_string? the GC may run. You have to register values being used on the C side as a GC root. It's easier and more documented to do it the other way round by calling C++ from OCaml. The problem I am trying to solve seems to be a can of worms from whichever angle I take it... No. The solution I proposed with Swig is very verbose, but it is a clean solution if you do it manually. You have Makefile compilation instructions to compile C++ with OCaml (the main issue with C++ and the extern "C" is essentially the name mangling of symbols provided by your C++ object files. All the rest is pretty similar to C. This is really the *main* point). You have at the end of my last email and example of how to construct an object and feed it back to OCaml. It may not be really clean, it lacks finalisers, but these last two points are stuff that you're going to have to deal with anyway if you're going with the OCaml/C interface. Look up "custom blocks" and finalisation in the OCaml manual section concerning the C interface. Luca All the best, -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] How to wrap around C++?
CAML_VALUE x = 0, y = 0; \ CAMLxparam2 (x, y) #define SWIG_CAMLlocal3(x, y, z) \ CAML_VALUE x = 0, y = 0, z = 0; \ CAMLxparam3 (x, y, z) #define SWIG_CAMLlocal4(x, y, z, t) \ CAML_VALUE x = 0, y = 0, z = 0, t = 0; \ CAMLxparam4 (x, y, z, t) #define SWIG_CAMLlocal5(x, y, z, t, u) \ CAML_VALUE x = 0, y = 0, z = 0, t = 0, u = 0; \ CAMLxparam5 (x, y, z, t, u) #define SWIG_CAMLlocalN(x, size) \ CAML_VALUE x [(size)] = { 0, /* 0, 0, ... */ }; \ CAMLxparamN (x, (size)) /* Declarations for custom block operations. */ /* For more information of Objective Caml custom blocks, * consult the Objective Caml manual, section 18.9. */ static struct custom_operations custom_swigtype_ocaml_operations = { "org.homelinux.yziquel.ocaml.swig", custom_finalize_default, custom_compare_default, custom_hash_default, custom_serialize_default, custom_deserialize_default }; #define SWIGVERSION 0x010340 #define SWIG_VERSION SWIGVERSION #define SWIG_as_voidptr(a) (void *)((const void *)(a)) #define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a)) #include "freeling.h" #include #if defined(__GNUC__) # if __GNUC__ == 2 && __GNUC_MINOR <= 96 # define SWIG_STD_NOMODERN_STL # endif #endif #include #include #include #include extern "C" CAML_VALUE _wrap_new_tokenizer (CAML_VALUE ocaml_arg1) { CAMLparam0(); SWIG_CAMLlocal1(caml_result); std::string *arg1 = 0 ; CAMLxparam1(ocaml_arg1); tokenizer *result = 0 ; { std::string arg1_str(String_val(ocaml_arg1), caml_string_length(ocaml_arg1)); arg1 = &arg1_str; } result = (tokenizer *)new tokenizer((std::string const &)*arg1); { caml_result = caml_alloc_custom(&custom_swigtype_ocaml_operations, sizeof (void *), 0, 1); *((void **) Data_custom_val(caml_result)) = (void *)result; } CAMLreturn(caml_result); } extern "C" CAML_VALUE _wrap_tokenizer_tokenize (CAML_VALUE ocaml_arg1, CAML_VALUE ocaml_arg2) { CAMLparam0(); SWIG_CAMLlocal1(caml_result); tokenizer *arg1 = (tokenizer *) 0 ; std::string *arg2 = 0 ; CAMLxparam1(ocaml_arg1); CAMLxparam1(ocaml_arg2); std::list< word > result; arg1 = *((tokenizer * *) Data_custom_val(ocaml_arg1)); { std::string arg2_str(String_val(ocaml_arg2), caml_string_length(ocaml_arg2)); arg2 = &arg2_str; } result = (arg1)->tokenize((std::string const &)*arg2); { caml_result = caml_alloc_custom(&custom_swigtype_ocaml_operations, sizeof (void *), 0 ,1); *((void **) Data_custom_val(caml_result)) = new std::list< word >((const std::list< word > &)result); } CAMLreturn(caml_result); } -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
[Caml-list] camlp4 unbound value
Hi. This is for camlp4 gurus: I've been using a modified version of Mauricio Fernandez' relational algebra camlp4 extension for postgresql. (I'm trying to adapt it to another database system, so I've functorised a bit of the original code). You can find the modified code and a Debian package at: http://yziquel.homelinux.org/debian/pool/main/o/ocaml-relational/ http://yziquel.homelinux.org/gitweb?p=ocaml-relational.git;a=summary My question is the following: Relational.Conv_Postgresql.encode_int is properly defined, and available from the toplevel, and yet considered unbound in the camlp4-generated code. How can this be? yziq...@seldon:~$ ocaml Objective Caml version 3.11.1 # #use "topfind";; - : unit = () Findlib has been successfully loaded. Additional directives: #require "package";; to load a package #list;; to list the available packages #camlp4o;;to load camlp4 (standard syntax) #camlp4r;;to load camlp4 (revised syntax) #predicates "p,q,...";; to set these predicates Topfind.reset();; to force that packages will be reloaded #thread;; to enable threads - : unit = () # #thread;; /usr/lib/ocaml/threads: added to search path /usr/lib/ocaml/unix.cma: loaded /usr/lib/ocaml/threads/threads.cma: loaded # #camlp4o;; /usr/lib/ocaml/dynlink.cma: loaded /usr/lib/ocaml/camlp4: added to search path /usr/lib/ocaml/camlp4/camlp4o.cma: loaded Camlp4 Parsing version 3.11.1 # #require "relational.postgresql";; /usr/lib/ocaml/pcre: added to search path /usr/lib/ocaml/pcre/pcre.cma: loaded /usr/lib/ocaml/netsys: added to search path /usr/lib/ocaml/netsys/netsys.cma: loaded /usr/lib/ocaml/netstring: added to search path /usr/lib/ocaml/netstring/netstring.cma: loaded /usr/lib/ocaml/netstring/netstring_mt.cmo: loaded /usr/lib/ocaml/netstring/netstring_top.cmo: loaded /usr/lib/ocaml/netstring/netaccel.cma: loaded /usr/lib/ocaml/netstring/netaccel_link.cmo: loaded /usr/lib/ocaml/relational: added to search path /usr/lib/ocaml/relational/relational.cma: loaded /usr/lib/ocaml/postgresql: added to search path /usr/lib/ocaml/postgresql/postgresql.cma: loaded /usr/lib/ocaml/relational/pa_relational.cmo: loaded /usr/lib/ocaml/relational/pa_relational_postgresql.cmo: loaded # TABLE user users COLUMN id SERIAL AUTO PRIMARY KEY END;; Error: Unbound value Relational.Conv_Postgresql.encode_int # module X = Relational.Conv_Postgresql;; module X : sig val encode_string : string -> string val decode_string : string -> string val decode_bool : string -> bool val encode_bool : bool -> string val encode_int : int -> string val decode_int : string -> int val encode_float : float -> string val decode_float : string -> float val encode_nullable : ('a -> string) -> 'a option -> string val decode_timestamp : string -> float val decode_timestampz : string -> float val encode_timestamp : float -> string val encode_timestampz : float -> string val decode_time : string -> float val decode_timez : string -> float val encode_time : float -> string val encode_timez : float -> string val decode_date : string -> Relational.Types.date val encode_date : Relational.Types.date -> string end # Relational.Conv_Postgresql.encode_int;; - : int -> string = # -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] camlp4
Tiphaine Turpin a écrit : Andy Ray a écrit : What should one do? Complaining on the list about lack of camlp4 documentation is a good start :-). To help you decide (and increase the pressure on the Ocaml team), I would like to mention some of the difficulties that I encountered when trying to understand camlp4 as a user: I fully agree. I've been working on understanding Camlp4 recently to handle one of Mauricio Fernandez' library on relational algebras. You can, eventually, if you take time, get to understan how everything works out. But that involves a lot of trial and error, and I still believe I do not have the full picture in mind. I'd just keep two things in mind concerning camlp4: -1- It's not hugely different from Camlp5. It is different, but not hugely, at least from the newcommer's point of view. So my advice is simply to work on an existing camlp4 extension, and to try groking with existing camlp5 documentation, while doing trials and errors the whole way long. It is painful, but it's doable. -2- A good hands-on introduction, to be read in conjunction with up-to-date camlp4 code: http://martin.jambon.free.fr/extend-ocaml-syntax.html Now, if someone, or a group of people, has the courage to update Martin's page to the current camlp4, that would be hugely helpful: I'm pretty sure there's quite a lot of people willing to use camlp4 that are simply laid back by the lack of documentation. Concerning the functorial design of the source code of camlp4, I fully agree with Tiphaine. It is probably a good design choice, and when you get to study it closely, it is quite remarkably done. However, a *huge* pain to read and to navigate through. All the best, -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
[Caml-list] mlsize_t and size_t.
Hi. I've been wanting to wrap a size_t value to ocaml. I therefore have a few questions about this: -1- What is the rationale that makes OCaml uses an mlsize_t instead of size_t? On Linux platforms, it seems that both are unsigned long ints. -2- would a 'type size = private nativeint' do the trick? All the best, -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
[Caml-list] Toplevel debugging.
Hello. I've been trying to reuse the mlgame codebase, and I've encountered a weird issue. When linked into native code or into bytecode, the library works fine, and the system exits with a 0 errorlevel. However, when trying to #require the package from the toploop, I get the following error. yziq...@seldon:~/git/mlgame$ ocaml Objective Caml version 3.11.1 # #use "topfind";; - : unit = () Findlib has been successfully loaded. Additional directives: #require "package";; to load a package #list;; to list the available packages #camlp4o;;to load camlp4 (standard syntax) #camlp4r;;to load camlp4 (revised syntax) #predicates "p,q,...";; to set these predicates Topfind.reset();; to force that packages will be reloaded #thread;; to enable threads - : unit = () # #require "mlgame";; /usr/lib/ocaml/unix.cma: loaded /usr/lib/ocaml/bigarray.cma: loaded /usr/lib/ocaml/sdl: added to search path /usr/lib/ocaml/sdl/sdl.cma: loaded /usr/lib/ocaml/sdl/sdlloader.cma: loaded /usr/local/lib/ocaml/3.11.1/mlgame: added to search path /usr/local/lib/ocaml/3.11.1/mlgame/mlgame.cma: loaded [Debug][Video] Driver: x11 Hardware: false HWBlit: false HWBlitCK: false WHBlitAlpha: false HWFill: false Mem: 0 # Fatal error: exception Sys_blocked_io yziq...@seldon:~/git/mlgame$ I am wondering how to use a debugger with libraries in the toplevel. As /usr/bin/ocaml is bytecode and that the exception is raised from OCaml and not from C code, I do not have a backtrace: yziq...@seldon:~$ gdb --args ocamlrun /usr/bin/ocaml GNU gdb (GDB) 7.0-debian Copyright (C) 2009 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-linux-gnu". For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>... Reading symbols from /usr/bin/ocamlrun...(no debugging symbols found)...done. (gdb) run Starting program: /usr/bin/ocamlrun /usr/bin/ocaml [Thread debugging using libthread_db enabled] Objective Caml version 3.11.1 # #use "topfind";; - : unit = () Findlib has been successfully loaded. Additional directives: #require "package";; to load a package #list;; to list the available packages #camlp4o;;to load camlp4 (standard syntax) #camlp4r;;to load camlp4 (revised syntax) #predicates "p,q,...";; to set these predicates Topfind.reset();; to force that packages will be reloaded #thread;; to enable threads - : unit = () # #require "mlgame";; /usr/lib/ocaml/unix.cma: loaded /usr/lib/ocaml/bigarray.cma: loaded /usr/lib/ocaml/sdl: added to search path /usr/lib/ocaml/sdl/sdl.cma: loaded /usr/lib/ocaml/sdl/sdlloader.cma: loaded /usr/local/lib/ocaml/3.11.1/mlgame: added to search path /usr/local/lib/ocaml/3.11.1/mlgame/mlgame.cma: loaded [New Thread 0x734c0910 (LWP 32029)] [Debug][Video] Driver: x11 Hardware: false HWBlit: false HWBlitCK: false WHBlitAlpha: false HWFill: false Mem: 0 # Fatal error: exception Sys_blocked_io [Thread 0x734c0910 (LWP 32029) exited] Program exited with code 02. (gdb) bt No stack. (gdb) My humble guess is that there is a IO conflict with the toplevel's interactive write/read on stdin/stdout, but I'd like to know how to trace that. All the best, -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] porter's stemmer implementation
Yoann Padioleau a écrit : On Jan 16, 2010, at 11:01 PM, Grégoire Seux wrote: There is one in nltk, a very complete python library for NLP and there is ocamlpython to link ocaml and python code. As the stemmer interface is very simpler (string -> string), it's very easy to use ocamlpython to do that. open Pycaml module Py = Python let modul = Py.cpr (Pycaml.pyimport_importmodule "nltk_ocaml") let dict = Py.cpr (Pycaml.pymodule_getdict modul) let stem s = let py_str = Pycaml.pystring_fromstring s in let f = Py.cpr (Pycaml.pydict_getitemstring(dict, "stem")) in let args = Py.cpr (Pycaml.pytuple_fromsingle py_str) in let res = Py.cpr (Pycaml.pyeval_callobject (f,args)) in Pycaml.guarded_pystring_asstring res I'm afraid I do not understand where you get your Python module from and you Py.cpr value from. I get from the Debian pycaml package: # #require "pycaml";; /usr/lib/ocaml/unix.cma: loaded /usr/lib/ocaml/pycaml: added to search path /usr/lib/ocaml/pycaml/pycaml.cma: loaded # module X = Python;; Error: Unbound module Python # module X = Pycaml.Python;; Error: Unbound module Pycaml.Python # module X = Pycaml;; module X : sig type funcptr = Pycaml.funcptr type pyobject = Pycaml.pyobject type funcent = funcptr * int * int type pymodule_func = Pycaml.pymodule_func = { pyml_name : string; pyml_func : pyobject -> pyobject; pyml_flags : int; pyml_doc : string; } type pyobject_type = Pycaml.pyobject_type = TupleType | StringType | IntType | FloatType | ListType | NoneType | CallableType Where did you get your pycaml from? All the best, -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] GPL with linking exception?
Stefano Zacchiroli a écrit : On Sun, Jan 17, 2010 at 05:47:10PM +0100, Guillaume Yziquel wrote: Well, you create a bytecode executable under GPL. You therefore include the OCaml bytecode runtime. Uh? Why "therefore"? Because I was indeed thinking of -custom when talking about "executable"... If you just distribute the bytecode (no -custom compilation involved), you will be not distributing the OCaml runtime with it, just your own program compiled to bytecode. Is it the only issue with the GPL? If that's the only issue, then it's perfectly fine with me... All the best, -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] GPL with linking exception?
Dario Teixeira a écrit : Hi, My question about GPL is mostly the following: Can you distribute GPL bytecode files? Do you have any issues when 'linking' the runtime with the GPL bytecode? Or are there other issues preventing from releasing GPL OCaml code? If you want a waterproof lawyerly response you should consider contacting an organisation like the Software Freedom Law Center [1]. Nevertheless, IMHO I see no obstacle in using the GPL with Ocaml code, and there are in fact plenty of Ocaml projects using this license. Could you elaborate on why you feel that the GPL could in theory prevent the release of Ocaml code? Well, you create a bytecode executable under GPL. You therefore include the OCaml bytecode runtime. You'd be distributing part of the bytecode runtime under the GPL, and I somehow feel there's a fish in doing so. This is just a question I'm asking myself. I do not have a hard opinion on that. Im just asking to collect advice from people on this list who might have wondered the same kind of things. That's all. All the best, -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] C++ parser
Kihong Heo a écrit : Dear all. Is there anybody knowing about existing C++ parser that is not so big? I've already know EDG and ELSA. But they are so big and hard to see. I don't want a perfect C++ parser. If it can parse common and simple C++, that's OK. The perfect C++ parser: GCC XML. I thing that there is an OCaml binding to it. Otherwise, depending on what you want to do, there is Swig. It parses only C++ declarations. I need your advice. For a new project, I'd use GCC XML. Thank you. -- Kihong Heo. All the best, -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] GPL with linking exception?
Dario Teixeira a écrit : Hi, I've been looking around on the net to see if I could find a GPL3 + linking exception copyright notice lying around. I only found LGPL + linking exception. Does anyone know what to write for GPL3 + linking exception? Is it even possible, or is only LGPL + linking exception possible? IANALNDIPOOTV (I am neither a lawyer nor do I play one on TV), but I'm under the impression that the linking exception only makes sense to appease the requirements of LGPL. The LGPL requires that the main binary may be used with an updated version of the LGPL library, which in most cases implies some form of dynamic linking. However, this conflicts with the most common way of building Ocaml programs, where all Ocaml libraries are statically linked into the main executable. Hence the need for a linking exception, which relaxes the LGPL requirement. If, on the other hand, the library is GPL, then all source code is available (library + main), which renders this point moot. Best regards, Dario Teixeira I acknowledge that you are not a lawyer, nor that you play one on TV. To my understanding the LGPL requires that you be able to replace the LGPL'd library by another library (including an updated version of the library). To this extent, it (very roughly and very quickly) imposes conditions on the stub code interfacing the two libraries, and you need to be able to reproduce the compilation steps. Very roughly... I'm not a lawyer either. Nor do I play one on TV. I do not believe (but I may be mistaken) that this conflicts with the static linkage of the main executable. But if you have the ocaml runtime getting linked in some way or the other, then the LGPL becomes somehow not very handy. Is this the main reason? My question about GPL is mostly the following: Can you distribute GPL bytecode files? Do you have any issues when 'linking' the runtime with the GPL bytecode? Or are there other issues preventing from releasing GPL OCaml code? All the best, -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
[Caml-list] GPL with linking exception?
Hello. I've been looking around on the net to see if I could find a GPL3 + linking exception copyright notice lying around. I only found LGPL + linking exception. Does anyone know what to write for GPL3 + linking exception? Is it even possible, or is only LGPL + linking exception possible? All the best, -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] Controlling module loading order.
Guillaume Yziquel a écrit : Gerd Stolpmann a écrit : Hi Guillaume, if you want to control from findlib that a certain function is invoked, the usual way to do it is to put a .cmo/.cmx file into the "archive" variables. The problem is that the linker drops all unused modules from .cma/.cmxa archives, and as a consequence the initialization code of these modules is not executed. So you could make R.interpreter a .cmo/.cmx - in this case the module is always initialized. Thank you so much! Just a complementary remark: when using a .cmo instead of a .cma, one should ship a .o file in place of the .a file. For the sake of exhaustivity. -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] problem creating .cma library
ygrek a écrit : On Sat, 09 Jan 2010 20:36:07 +0100 Guillaume Yziquel wrote: So if I want to call R code that multithreads with OCaml, I should write something like enter_blocking_section(); PROTECT(e = R_tryEval(Sexp_val(sexp_list), R_GlobalEnv, &error)); UNPROTECT(1); leave_blocking_section(); Am I correct? I bet no. It is not safe to access block ocaml value inside blocking_section. In this particular case Sexp_val(v) is Field (v,0) whis in turn is v[0] or *v. So you read the pointer, then in another thread GC moves things around and old copy of the pointed value is overwritten, then you read the value through the old pointer and get garbage. Put Sexp_val call before caml_enter_blocking_section(). OK. Thanks -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] Controlling module loading order.
Gerd Stolpmann a écrit : Hi Guillaume, if you want to control from findlib that a certain function is invoked, the usual way to do it is to put a .cmo/.cmx file into the "archive" variables. The problem is that the linker drops all unused modules from .cma/.cmxa archives, and as a consequence the initialization code of these modules is not executed. So you could make R.interpreter a .cmo/.cmx - in this case the module is always initialized. Thank you so much! The other workaround is to provide an init function in R.interpreter like let init() = () By calling this function the user references the interpreter, and all the initialization code is executed. That's exactly what I want to avoid. -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] problem creating .cma library
Daniel Bünzli a écrit : So if I want to call R code that multithreads with OCaml, I should write something like enter_blocking_section(); PROTECT(e = R_tryEval(Sexp_val(sexp_list), R_GlobalEnv, &error)); UNPROTECT(1); leave_blocking_section(); Am I correct? Yes, but the functions have now a caml_ prefix. Make sure that there is no interaction whatsoever with ocaml's runtime system (e.g. ocaml value allocation) between the two calls. I will have interaction, because I plan to be able to make R call OCaml code (not in the foreseeable future). But it's just a question of wrapping the call back to Ocaml with a caml_leave_blocking_section() callingOCamlcode() caml_enter_blocking_section() construct. As far as I've understood. Note also that in case you need to use some caml value after the leave call you have to declare it with a CAMLparam macro as it may move during the blocking section even if the stub itself doesn't allocate. Very helpful. Thanks a lot. -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] problem creating .cma library
Gerd Stolpmann a écrit : Would it be legitimate to include CAMLlocal2 inside the error-handling braces? No. You would start a new context for local roots, and there is no way to end it (CAMLreturn ends the context). There are the macros Begin_roots and End_roots that should be used in this case, e.g. if (error) { value ml_error_call = Val_unit; value ml_error_message = Val_unit; Begin_roots2(ml_error_call, ml_error_message); ... End_roots(); raise_with_arg(...) } End_roots before caml_raise_with_arg? Why not after? I mean, you do not do a CAMLreturn before a caml_raise_with_args, so why should't this be the same for End_roots()? The macros are only documented in memory.h. So far I know, raising an exception from within Begin_roots/End_roots is not allowed. It seems to me that the major issue is how caml_local_roots gets restored. With the CAMLparam/CAMLreturn macros, this is done by storing its original value in caml__frame and restoring it via CAMLreturn. As it is written in memory.h Your function may raise an exception or return a [value] with the [CAMLreturn] macro. I assume that caml_local_roots gets restored by a mechanism in the 'try' of the 'try / with' construct after the siglongjmp of caml_raise. Therefore it should be OK to use caml_raise_with_args before End_roots(). Am I right, or is this plainly wild guessing? -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] problem creating .cma library
Daniel Bünzli a écrit : Section 2) of this paper also has a very gentle and readable introduction to the gc : http://portal.acm.org/citation.cfm?id=141130 Thanks for the link. Another thing you need to know, if you have long running pieces of C code that don't interact with ocaml's runtime system, is the two functions : caml_enter_blocking_section caml_leave_blocking_section They are explained in this message : http://caml.inria.fr/pub/ml-archives/caml-list/2001/06/58d7a7e8747056c3842e53b4e9454f44.en.html OK. So if I want to call R code that multithreads with OCaml, I should write something like enter_blocking_section(); PROTECT(e = R_tryEval(Sexp_val(sexp_list), R_GlobalEnv, &error)); UNPROTECT(1); leave_blocking_section(); Am I correct? -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] problem creating .cma library
Richard Jones a écrit : Why is this a problem? Because you might in your C code have some value on the stack. 'value' is (or can be) a pointer. The OCaml garbage collector can move pointed-to-objects around, firstly from the minor heap to the major heap, secondly when compacting the major heap. So your C value (pointer) *could* become an invalid pointer if what it was pointing to got moved. Yes, I understood the nature of the problem. The way to avoid this small chance is to register the value with the garbage collector, which is essentially what the CAMLparam* and CAMLlocal* macros do. So if the GC needs to move that object, it will update the pointer for you. If your function never allocates (and never calls anything which allocates), then you don't need to register values, because no allocation => they can't be moved. [In fact there are some other exceptions as well where you can prove that an allocation won't move your pointer, eg. if you only allocate one thing and immediately return the value.] I've been looking at the pcre bindings, and these bindings make minimal usage of CAMLparam, CAMLlocal and CAMLreturn. For instance, here is the piece of code that executes R code ad catches errors. I've tried to follow guidelines available on the net, and inspired myself from pcre. CAMLprim value r_eval_sxp (value sexp_list) { CAMLparam0(); CAMLlocal2(ml_error_call, ml_error_message); SEXP e; int error = 0; PROTECT(e = R_tryEval(Sexp_val(sexp_list), R_GlobalEnv, &error)); UNPROTECT(1); if (error) { ml_error_call = Val_sexp(error_call); error_call = NULL; ml_error_message = caml_copy_string(error_message); error_message = NULL; value error_result = caml_alloc_small(2, 0); Store_field(error_result, 0, ml_error_call); Store_field(error_result, 1, ml_error_message); raise_with_arg(*caml_named_value("OCaml-R generic error"), error_result); } CAMLreturn(Val_sexp(e)); } Do you see GC / allocation / threading problems with it? Would it be legitimate to include CAMLlocal2 inside the error-handling braces? You might find my series on the garbage collector interesting if you want to look into this further: http://rwmj.wordpress.com/?s=ocaml+internals These are very interesting. Could not find part 6, though... Also if you are calling C functions which don't allocate from OCaml code, you might want to read about noalloc: http://camltastic.blogspot.com/2008/08/tip-calling-c-functions-directly-with.html Two comments on this: -1- I remember a post by Jon Harrop concerning external mathematical functions such as the exponential in Pervasives. He was arguing that it could be done directly from the .ml file by using such "tags". Where can I find a list of all these tags for external functions? There's "float", but are there others? -2- If I understand this post well, the following function CAMLprim value init_r (value argv, value sigs) { /* -1- argv is an OCaml array of strings, which gives the command line arguments used to invoke the R interpreter. Code segfaults if the array does not contain a first element, which is the name of the program, typically "R", or "OCaml-R". Other arguments typically are "--vanilla", "--slave"... -2- sigs is an OCaml int. When set to 0, R signal handlers are not removed. When set to, say, 1, R signal handlers are removed. It is very useful to remove signal handlers when embedding R. */ int length = Wosize_val(argv); char* argv2[length]; int i; // We duplicate the OCaml array into a C array. for (i=0; i= 2.3.1. */ if (Int_val(sigs)) R_SignalHandlers = 0; // This is the libR.so function. i = Rf_initEmbeddedR(length, argv2); // Returns 1 if R is correctly initialised. return Val_int(i); } could be called with "noalloc"? By the way, here's a question I've been wondering about this section. Rule 3: When I have a Abstract_tag block used to wrap a pointer in the C heap, it seems to me that you can just do it with a Field(v,0)= assignment. Do you need Store_field for that? This is to do with the Remembered Set. See part 5 of the above series. The remembere set, in this context, explains why I would need Store_field when dealing with pure OCaml world. When wrapping pointers to the C heap in abstract blocks, I do not see the point of Store_field, and it seems to me that Field= assignment is fine. Am I mistaken? All the best, -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] problem creating .cma library
David Allsopp a écrit : Guillaume Yziquel: So, no allocation of OCaml values (or in place modification, either, I guess) implies no need for CAMLparam/CAMLreturn stuff? Chapter 18 of the manual in Section 18.5 describes pretty much everything you need to know about writing safe stubs that work with the garbage collector. Yes. It is all I need to know to write safe stubs. But it does not answer the question above. It does state that you do not need registration of the result value if there's no allocation going on between the moment result get its value and the return statement. But it does not say when you can avoid CAMLparam macros. By the way, here's a question I've been wondering about this section. Rule 3: When I have a Abstract_tag block used to wrap a pointer in the C heap, it seems to me that you can just do it with a Field(v,0)= assignment. Do you need Store_field for that? I want to understand them so that I can abstract away in some other file / .so, some rather usual constructs involving OCaml structures. I think it is smarter to take some time doing this, with detailed comments all over, than repeating the same mistakes over and over (or worse: wondering if you made mistakes) when doing C bindings. Having written a few C stubs myself, I'd also highly recommend just following the manual and not worrying about what the macros do - if you want/need to improve allocation performance then you can use the lower-level interface for allocation (but that still involves CAMLparamn/CAMLreturn). I usually find that tricks like this (think Obj.magic) mean that when something goes wrong, there's always a niggling thought in the back of your mind that it's the trick which has broken everything when in fact it's something blindly obvious but you waste hours double-checking the tricks! Yes, but it's also quite a pain not to optimise the binding when you're trying to bind a columnar database that compiles SQL to its own language and tat tries to make the best use of CPU cache. You tend to feel guilty... In the ideal world, the C written for C stubs would be parsed by a camlp4-like pre-processor which would automatically insert the expansion of those macros where required. If you have CAMLparamn and CAMLreturn on functions which don't strictly need them then you're only creating a few more local roots than are strictly necessary which isn't likely to hurt that much... Maybe. I'm not so sure about that... David All the best, -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] problem creating .cma library
Basile STARYNKEVITCH a écrit : Why do these functions not follow the usual CAMLparam/CAMLreturn macro stuff? Because they are written by the Ocaml guys (Damien knows really well the Ocaml garbage collector; he wrote it). And also, because these particular functions do not do any allocation of Ocaml values (either directly or indirectly). So, no allocation of OCaml values (or in place modification, either, I guess) implies no need for CAMLparam/CAMLreturn stuff? My advice for people coding C code for ocaml is the following: 1. *always* use the CAMLparam/CAMLreturn/... macros. 2. if you dare not using them for some very few functions (because they don't allocate, ...) add a big fat comment with a warning inside. Regards I want to understand them so that I can abstract away in some other file / .so, some rather usual constructs involving OCaml structures. I think it is smarter to take some time doing this, with detailed comments all over, than repeating the same mistakes over and over (or worse: wondering if you made mistakes) when doing C bindings. All the best, -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] problem creating .cma library
Damien Doligez a écrit : On 2009-12-31, at 00:30, Guillaume Yziquel wrote: #include #include #include "../mylib/mylib.h" CAMLprim value my_print_stub(value v) { CAMLparam1(v); /* is missing here, for garbage collection purposes. */ char* str = (char*)String_val( v ); /* You do not need the right-hand side (char*) casting. */ my_print( str ); return Val_unit; } If you use CAMLparam1, you must use CAMLreturn instead of return. Yes. Indeed. Didn't see it. However, I had a look at https://yquem.inria.fr/caml/svn/ocaml/version/3.09/byterun/sys.c and more specifically at the function CAMLprim value caml_sys_exit(value retcode) { #ifndef NATIVE_CODE caml_debugger(PROGRAM_EXIT); #endif exit(Int_val(retcode)); return Val_unit; } or the function CAMLprim value caml_sys_close(value fd) { close(Int_val(fd)); return Val_unit; } Why do these functions not follow the usual CAMLparam/CAMLreturn macro stuff? -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
[Caml-list] Controlling module loading order.
Hi. I've been reimpleminting the OCaml-R binding, and implemented a simple wrapper around the Quantmod package in R: http://yziquel.homelinux.org/gitweb/?p=ocaml-r.git;a=tree http://yziquel.homelinux.org/gitweb/?p=ocamlr-quantmod.git;a=tree Testing these modules from the toplevel is quite fine. However, when compiling stuff using these pieces of code, I have issues with the way the modules are loaded, since the order in which they are loaded has side-effects: Initialisation of the R interpreter in the good case, segfaults in the bad case... For instance, the META file of OCaml-R: 1 name = "R" 2 version = "0.2" 3 description = "R bindings for OCaml" 4 requires = "unix" 5 archive(byte) = "r.cma" 6 archive(native) = "r.cmxa" 7 8 package "interpreter" ( 9 version = "0.2" 10 description = "Embedded R interpreter" 11 requires = "R" 12 archive(byte) = "oCamlR.cma" 13 archive(native) = "oCamlR.cmxa" 14 ) The stub functions are in package "R", and package "R.interpreter" contains a module with and empty signature, whose side-effects are to initialise the R interpreter through an application of the functor 19 module Interpreter (Env : Environment) : Interpreter = struct 20 21 let () = init ~name: Env.name 22 ~argv: Env.options 23 ~env: Env.env 24 ~sigs: Env.signal_handlers 25 () 26 27 end My issue concerns the Quantmod wrapper: How can I make sure that when the Quantmod module is loaded, the OCamlR module of the "R.interpreter" findlib package gets loaded before? Currently the ocamlbuild _tags file for ocamlr-quantmod is 1 : pkg_R.interpreter, pkg_CRAN-zoo But that doesn't seem to do the trick... My question is: do I have to put a line like "module X = OCamlR" in quantmod.ml, or is there a way to load OCamlR beforehand just by tweaking the build process, order of modules when linking, etc... All the best, -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] Dynamically loaded BSS not initialised to 0.
Richard Jones a écrit : Problem solved: This is in fact a symbol collision problem on the symbol 'box'. There's one in libncurses, which is loaded by ocamlrun. Good ol' ELF loading model ... Uli wrote a really good introduction to writing DSOs which everyone should read: http://people.redhat.com/drepper/dsohowto.pdf Indeed, it's very very good. Thanks a lot for this pointer. The issue of symbol scope is covered there too, although I don't think it can help in this case. One or other of the libraries is just going to have to change the visibility of that symbol. Yes. This has been done on the MonetDB side. They're going to make 'box' locally static, and to rename it... In ncurses it's a public symbol, but if I understand the code correctly, in MonetDB it's just an accidentally leaked global variable (not part of the API). So MonetDB could control the visibility of that symbol using a linker script. Yes, they probably could, but it seems to me that they have other priorities for now. We use linker scripts extensively in libvirt to control which clients can see which sets of symbols, eg: http://libvirt.org/git/?p=libvirt.git;a=blob;f=src/libvirt_public.syms;hb=HEAD http://libvirt.org/git/?p=libvirt.git;a=blob;f=src/libvirt_private.syms;hb=HEAD In answer to your original question, initialization of the BSS is the job of the loader (ld-linux.so(8)). OCaml just calls dlopen(3), which calls into some extremely well-tested code, so it was always going to be unlikely that BSS initialization was the problem. Rich. Thanks. I was quite sure that the loader was doing a proper job. I wasn't sure however that OCaml was calling dlopen, and I was wondering at the time if the linking scheme used by OCaml depended or not on whether we're dealing with OCaml bytecode or OCaml native code. In this context I was wondering if the BSS was initialised to 0, since on some hardware, it's not necessarily the case (it seems... I would not bet my hand on this). I now know better. Anyway, it was an interesting bug: I'm growing fond of assembly. All the best, -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] Dynamically loaded BSS not initialised to 0.
Guillaume Yziquel a écrit : Hello. I encountered a rather weird issue. A binding of mine works fine when bundled as a .cmxa, but fails when bundled as a .cma. I'm running a Linux Debian amd64. I've tracked down the issue to the following point: it seems that when the BSS (uninitialised data section) of libmonetdb5.so is dynamically loaded, it doesn't get initialised to 0. And the code in libmonetdb5.so relies on the fact that BSS gets initialised to 0 when dynamically loaded. So: is ocaml failing to initialise memory to 0 when limonetdb5.so is dynamically loaded? Problem solved: This is in fact a symbol collision problem on the symbol 'box'. There's one in libncurses, which is loaded by ocamlrun. Thanks to Csaba Halasz (Jester01 on ##asm) for help with binary debugging. All the best, -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
[Caml-list] Dynamically loaded BSS not initialised to 0.
Hello. I encountered a rather weird issue. A binding of mine works fine when bundled as a .cmxa, but fails when bundled as a .cma. I'm running a Linux Debian amd64. I've tracked down the issue to the following point: it seems that when the BSS (uninitialised data section) of libmonetdb5.so is dynamically loaded, it doesn't get initialised to 0. And the code in libmonetdb5.so relies on the fact that BSS gets initialised to 0 when dynamically loaded. To reproduce my problem, do the following: You need to have the following Debian packages installed for MonetDB. libmonetdb-client-dev libmonetdb-client1 libmonetdb-dev-dbg libmonetdb1-dbg libmonetdb5-server-dev-dbg libmonetdb5-server5-dbg libmonetdb5-sql-dev libmonetdb5-sql2 monetdb-client monetdb5-server-dbg The *-dbg packages are packages I've changed and recompiled with the -g option. They are available from my website: http://yziquel.homelinux.org/debian/pool/main/m/ The key signing the repo is located at http://yziquel.homelinux.org/debian/yziquel-debian-packages.asc and you just have to do cat yziquel-debian-packages.asc | sudo apt-key add - and include the following lines: deb http://yziquel.homelinux.org/debian stable main deb-src http://yziquel.homelinux.org/debian stable main deb http://yziquel.homelinux.org/debian testing main deb-src http://yziquel.homelinux.org/debian testing main deb http://yziquel.homelinux.org/debian unstable main deb-src http://yziquel.homelinux.org/debian unstable main The rest of the MonetDB packages can be found here: http://monetdb.cwi.nl/downloads/Debian/ and the monetdb5 binding is here: http://yziquel.homelinux.org/gitweb/?p=ocaml-monetdb5.git;a=tree (click on snapshot to download one). Now here is why I believe that the BSS is not properly initialised. The code in which I have my segfault is the following one, function findBox. Line 330 of: http://monetdb.cvs.sourceforge.net/viewvc/monetdb/MonetDB5/src/mal/mal_box.mx?revision=1.100&view=markup There is this line: if (box[i] != NULL && idcmp(name, box[i]->name) == 0) { I've followed machine code instructions step by step there, with ddd. In native code, box[i] == NULL. Evaluation stops there (i.e. box[i] != NULL is false). Everything is perfect. In bytecode, box[i] != NULL because BSS is not initialised to 0... And it then tries to access box[i]->name, and segfaults. For the record, you have: 211 typedef struct BOX { 212 MT_Lock lock; /* provide exclusive access */ 213 str name; 214 MalBlkPtr sym; 215 MalStkPtr val; 216 int dirty; /* don't save if it hasn't been changed */ 217 } *Box, BoxRecord; and 263 #define MAXSPACES 64 /* >MAXCLIENTS+ max modules !! */ 264 Box box[MAXSPACES]; For the disassembled code, you can have a look at: http://sourceforge.net/mailarchive/message.php?msg_name=4B3ED073.3050203%40citycable.ch I've also tried running ltrace to see how dynamic loading happens for the bytecode monetdb5.cma: http://yziquel.homelinux.org/monetdb_sql.byte.ltrace But it gives ma 95% of ocaml related lines, and the end is concerned only with ml_monetdb_sql. I'd like to see how the 'box' symbol gets loaded in BSS, but do not know how to do that. So: is ocaml failing to initialise memory to 0 when limonetdb5.so is dynamically loaded? -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] Wrapping C code using pthread.
Jake Donham a écrit : On Sun, Dec 27, 2009 at 1:33 PM, Guillaume Yziquel wrote: If someone knows how to use gdb on a bytecode executable to locate the segfault in MonetDB's .so file, I'd be quite happy to know. You can just gdb ocamlrun, then run with the bytecode file as argument. (Assuming you are not building in -custom mode.) Thanks Jake. For the record, here is the last mail I sent on the MonetDB users mailing list on this topic: http://sourceforge.net/mailarchive/forum.php?thread_name=4B3BDC5E.10801%40citycable.ch&forum_name=monetdb-users I encountered a weird issue while running gdb --args ocamlrun, which doesn't appear in native code. Here is the binded C source code in which gdb steps into: Line 330 of mal_box.mx, available at http://monetdb.cvs.sourceforge.net/viewvc/monetdb/MonetDB5/src/mal/mal_box.mx?revision=1.101&view=markup You got this function 322 Box 323 findBox(str name) 324 { 325 int i; 326 327 mal_set_lock(mal_contextLock, "findBox"); 328 329 for (i = 0; i < MAXSPACES; i++) 330 if (box[i] != NULL && name && idcmp(name, box[i]->name) == 0) { 331 #ifdef DEBUG_MAL_BOX 332 stream_printf(GDKout, "found the box '%s' %d\n", name, i); 333 #endif 334 mal_unset_lock(mal_contextLock, "findBox"); 335 return box[i]; 336 } 337 mal_unset_lock(mal_contextLock, "findBox"); 338 #ifdef DEBUG_MAL_BOX 339 stream_printf(GDKout, "could not find the box '%s' \n", name); 340 #endif 341 return 0; 342 343 } And gdb complains with bytecode OCaml. Segfault. (gdb) run Starting program: /usr/bin/ocamlrun test/monetdb_sql.byte [Thread debugging using libthread_db enabled] [New Thread 0x2f670910 (LWP 23863)] Program received signal SIGSEGV, Segmentation fault. [Switching to Thread 0x2f670910 (LWP 23863)] 0x2c66c42c in findBox (name=0x2aaab7ac6a37 "time") at mal_box.c:89 89if (box[i] != NULL && idcmp(name, box[i]->name) == 0) { (gdb) backtrace #0 0x2c66c42c in findBox (name=0x2aaab7ac6a37 "time") at mal_box.c:89 #1 0x2c66c54a in openBox (name=0x2aaab7ac6a37 "time") at mal_box.c:107 #2 0x2aaab7ac03b4 in MTIMEprelude () at mtime.c:2147 #3 0x2c67e7f6 in runMALsequence (cntxt=0x2c981000, mb=0x669348, startpc=1, stoppc=0, stk=0x2f66fb80, env=0x0, pcicaller=0x0) at mal_interpreter.c:3260 #4 0x2c67443a in runMAL (cntxt=0x2c981000, mb=0x669348, startpc=1, mbcaller=0x0, env=0x0, pcicaller=0x0) at mal_interpreter.c:272 #5 0x2c6738b7 in MALengine (c=0x2c981000) at mal_session.c:580 #6 0x2c671fdb in malBootstrap () at mal_session.c:37 #7 0x2c662fa5 in mal_init () at mal.c:61 #8 0x2b91ef60 in ?? () from /usr/lib/libembeddedsql5.so #9 0x2b39b73a in start_thread () from /lib/libpthread.so.0 #10 0x2b67c69d in clone () from /lib/libc.so.6 #11 0x in ?? () (gdb) print i $1 = 0 (gdb) print box[i] $2 = (Box) 0x0 (gdb) print name $3 = (str) 0x2aaab7ac6a37 "time" (gdb) But in native code, it works quite well: (gdb) break findBox Function "findBox" not defined. Make breakpoint pending on future shared library load? (y or [n]) y Breakpoint 1 (findBox) pending. (gdb) run Starting program: /home/yziquel/git/ocaml-monetdb5/test/monetdb_sql.native [Thread debugging using libthread_db enabled] [New Thread 0x2f467910 (LWP 15910)] [Switching to Thread 0x2f467910 (LWP 15910)] Breakpoint 1, findBox (name=0x2aaab78bda37 "time") at mal_box.c:86 86mal_set_lock(mal_contextLock, "findBox"); (gdb) info locals i = 10922 (gdb) step 88for (i = 0; i < MAXSPACES; i++) (gdb) info locals i = 10922 (gdb) step 89if (box[i] != NULL && idcmp(name, box[i]->name) == 0) { (gdb) info locals i = 0 (gdb) print i $1 = 0 (gdb) print box[i] $2 = (Box) 0x0 (gdb) step 88for (i = 0; i < MAXSPACES; i++) (gdb) print name $3 = (str) 0x2aaab78bda37 "time" (gdb) What's weird is the context seems to be exactly the same: i=0, box[i]=0, and name="time". The segfault happens, as I believe, when doing the comparison box[i] != NULL I'm quite baffled by a segfault on such an expression, as box[i] seems to be valid memory. Enlightenment would be highly appreciated. For some context, there are some pthreads going on and some dynamic loading. But it hardly seems to be the issue. All the best, -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] problem creating .cma library
roua...@softwarerealisations.com a écrit : Hi everyone. Hi. I am using ocaml 3.11.0 with the MingW toolchain on windows (vista). Cannot help you much there. Now I create the mylib_stub.c file which contains the marshalling code between the libmylib.dll library and ocaml. This file contains the following C code: === #include #include #include "../mylib/mylib.h" CAMLprim value my_print_stub(value v) { CAMLparam1(v); /* is missing here, for garbage collection purposes. */ char* str = (char*)String_val( v ); /* You do not need the right-hand side (char*) casting. */ my_print( str ); return Val_unit; } When I finaly build the test ocaml app which is supposed to use the mylib.cma library, ocamlc tells me: "Unbound module Mylib" Firs of all, mylib.cma is simply an archive of OCaml modules. It may contain multiple modules, and might not contain a module called Mylib. You have to ensure that mylib.cmo is included in mylib.cma. Moreover, when you create mylib.cma, you also need a compiled interface, i.e. a mylib.cmi file. It's an interface for mylib.cmo. Without it, there's no description of module Mylib in mylib.cma. The command used to compile the test app is ocamlc -verbose mylib.cma -c Main.ml You've got something fundamentally wrong here: Out of main.ml (lower case for the the first letter), you first create a main.cmo file. And also a main.mli file with ocamlc -i. You compile the main.mli file to main.cmi. Then you create the mylib.cma archive from main.cmo and main.cmi. And mylib.cma will contain the module Main. Not the module Mylib. The Main.ml file contains the following code: === open Mylib let main () = my_print "my_print = ok" main () === Here, you're declaring the submodule Mylib of the module Main. Also known as Main.Mylib. Not as Mylib. Is there a way to verify that the .cma library was created correctly? There are some tools, such as ocamldumpobj and ocamlobjinfo. Forgot which one applies to .cmas. I had to install flexlink for ocaml to get the dll linking to work on windows. Can't help you here. Kind regards Rouan. All the best, -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] Wrapping C code using pthread.
ygrek a écrit : On Sun, 27 Dec 2009 13:19:36 +0100 Guillaume Yziquel wrote: In fact, my trouble is that when things are compiled to native code, it works fine. However, things get screwed up when compiled to bytecode, resulting in a segfault. Are pthreads compatible with OCaml bytecode? I believe so. Could you post some code and instructions how to build for investigation? I'm working on it. Will look at ocamlforge for this purpose. I now think, however, that it's not a thread issue. MonetDB loads dynamically at startup some other libraries for its own low-level language, MAL (for MonetDB Assembly Language). I believe this kind of dynamic loading works fine in native code, but doesn't in bytecode. I've got no issues in native code at all... Only with bytecode. Haven't located the place in MonetDB where this dynamic loading happens, so it's just conjectures for now. If someone knows how to use gdb on a bytecode executable to locate the segfault in MonetDB's .so file, I'd be quite happy to know. All the best, -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] Wrapping C code using pthread.
ygrek a écrit : On Fri, 25 Dec 2009 21:57:21 +0100 Guillaume Yziquel wrote: Hello. I'm currently trying to wrap up together a C interface for the MonetDB5 database system. I'm getting quite a lot of segfaults (a lot of which come from MonetDB itself), and I'm therefore wondering the following about pthreads and OCaml: The server is started via a pthread: pthread_create(&sqlthread, NULL, start_sql_server, (void *) server); and I would like to know what kind of things I should look at with C-side pthreads in order to avoid segfaults... How does the OCaml code gets executed? Via callbacks from this thread? If so, have a look at http://caml.inria.fr/mantis/view.php?id=4702 Thanks for the pointer. No this is not the case. In fact, it's a library that starts an embedded database server in its own pthread. Completely distinct from OCaml. In fact, my trouble is that when things are compiled to native code, it works fine. However, things get screwed up when compiled to bytecode, resulting in a segfault. Are pthreads compatible with OCaml bytecode? All the best, -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
[Caml-list] Wrapping C code using pthread.
Hello. I'm currently trying to wrap up together a C interface for the MonetDB5 database system. I'm getting quite a lot of segfaults (a lot of which come from MonetDB itself), and I'm therefore wondering the following about pthreads and OCaml: The server is started via a pthread: pthread_create(&sqlthread, NULL, start_sql_server, (void *) server); and I would like to know what kind of things I should look at with C-side pthreads in order to avoid segfaults... All the best, -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
[Caml-list] Re: React switch with newly created events.
Daniel Bünzli a écrit : However, it may happen (and it does happen) that as soon as this new React.event is created, an event is fired before the React.E.switch has been executed to replace the old event by the new event. You are creating a new update cycle inside another update cycle and this is disallowed. No primitives are allowed to update in an update cycle (to be precise unless the primitive does not belong to the dependency graph of the update cycle). No, this is not the case. There's only one update cycle. I was confused and sked the question too quickly. It works perfectly... -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
[Caml-list] React switch with newly created events.
Hello. I've recently been working again of React, and I have the following question. Current code is below. I'm creating an event with React.E.switch, that creates a new event through the schedule function, and this new events replaces the old event. React.E.switch is used for this replacement. React.E.switch initial_event (React.E.map begin function () -> schedule (rescheduler ()) end tick) However, it may happen (and it does happen) that as soon as this new React.event is created, an event is fired before the React.E.switch has been executed to replace the old event by the new event. This is due to Lwt concurrency. I therefore have two potential solutions: -1- clutter my code with mutexes to synchronise the whole stuff, with the disadvantage that there is not, to my knowledge, to execute a function just after the React.E.switch function has effectively switched events. -2- look for a way in React to do it within React only. Which would mean to somehow implement within React a way to switch to a newly created event, without race conditions. What would you do in this context? Here's the code: let reschedule ?attach:(f = begin fun x -> x end) start rescheduler = (* The let define tick in E.fix define is the proper way to implement recursive events. define has type React.event -> (React.event * React.event) and its argument is a placeholder for the event at time t-dt. *) let attach initial_event = let define tick = (* Here is something I worry about: It is possible that the event created with the schedule function is fired before it is attached to the switched event, hence losing an event, and stalling the whole regular event. *) let tick' = React.E.switch initial_event (React.E.map begin function () -> schedule (rescheduler ()) end tick) in tick', tick' in f (React.E.fix define) in schedule ~attach:attach start let regular_schedule ?attach:(f = begin fun x -> x end) start period = reschedule ~attach:f start (fun () -> Calendar.add (Calendar.now ()) period) -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] Re: Recursion on React.events.
Daniel Bünzli a écrit : Unfortunately, it seems to me that Daniel's module is fairly low-level in the sense that it implements the bare mechanics and semantics of FRP. Yes, react is low-level and will remain. The rationale is that I want the client of the module to be able to decide the application structure. This makes react more flexible and easier to embed were you need to. That's perfect. You should perhaps think of creating a Convenience submodule where some useful patterns could be thrown in by third parties. After having been 'moderated' by you, of course. I could have decided that react has a global queue and every primitive update has to go through that queue (for the client this would have simplified the feedback of primitives into the reactive system). But then the module is not thread-safe and you get compositional problems when you want to integrate two libraries using react in a threaded environment. I could have decided that the reactive engine runs on its own thread but maybe you don't want to use threads etc. No no no! Indeed, it's much better as it is today. For example with the current design two part of a program may use react as they wish internally without any problem even on different threads as long as their signals and events don't interact. With the current structure it also means that a library designer using react has to make sure the way he design should play nice with other part defining their own primitive events. Yes, indeed. But that's also the tricky part where some useful constructs would indeed be... useful. So yes it means a little bit more work and understanding for the client. But I think it pays to have a reactive engine that doesn't impose too much on you. The client always knows better the abstraction he's after and the setting in which it has to implement it. But if a consistent and compositional pattern of use emerges I'm always willing to support it directly in the library. All to true. But that would be the purpose of a Convenience submodule (once you get constructive feedback). For example, make a parser of the Asterisk Manager Interface with React around OCamlNet's Uq_engine module proved to be quite tricky, in a similar way as the issue that started this thread (here, I had no event, but in the Asterisk parser, I had doubled events, and I solved it in a very very ugly way). Note that as we discussed I highly suspect you used the wrong abstraction there (events vs. signals). Very possibly. I will have to get back to it one day to make it clean. Now that I know where to find the documentation for E.fix, it's only a question of *cough* time *cough*. It's true that I may not completely understand how React works, as Daniel stated it before (a bit better now) Btw this was not intended to be offensive. It was to say the reactive engine has a well defined way to work that should be respected (the update cycle) so don't try to trick around too much with it when you cannot achieve want you want. Yes. It's also here where I worry about a few things concerning Lwt: In Lwt, you have a monadic way to do context switches for multithreading withing a single real thread. So if you use Lwt inside the update cycle, you could well jump out of the update cycle with a Lwt context switch. As long as you do not encounter a Lwt construct within definition of signals and events, you can be pretty sure that the update cycle will go through to its end without using Lwt inside an event/signal. But at the same time, it seems that the monadic way Lwt is built avoids us such problems. But I may be mistaken. This issue can be interesting and important. 'a Lwt.t represents the type of a promise of something of type 'a, essentially. So you could use in parallel processing: Imagine that 'a Remote.t represents the type of something computed on a remote computer. You could use type 'a Remote.t Lwt.t to represent the promise of a computation of 'a done on a remote computer. It therefore could make sense to have a single computer in charge of receiving React.events with a unique update cycle, and transfering the computation to other computers, represented as non-primary 'a Remote.t Lwt.t React.signal-s. Using S.fix, one could also feed events to such a signal, using S.fix to bind the t-dt Lwt.t value of the signal to the t value of the same signal. That may seem quite involved, but conceptually, it could be a clean way to type rather efficiently parallel computations. When binding such signals, you could also implement code mobility, marshaling features to take care of the work load of multiple computers. So the compatibility of Lwt and React seems to me a worthwile question if one wants to use OCaml for high availability, reactive, parallel computations. And in this context, making E/S.switch easy to use woul
[Caml-list] Re: Recursion on React.events.
Daniel Bünzli a écrit : Maybe I was looking in the wrong place, but I haven't found "the second case of the semantics of E.switch" on your website. In fact, the way I learned about React.E.switch was from the .mli-style webpage on your website, and by trial and error. Here : http://erratique.ch/software/react/doc/React.E.html#VALswitch Second bullet. I think you should really make a direct link to this page from either http://erratique.ch/software/react/doc/React.html or http://erratique.ch/software/react/doc/index.html because I've been on your website quite a few times, and it's the first time I see this page. (Which is really useful). One thing that really troubles me, is that I do not understand why define returns a couple of two identical element. And the typing of E.fix is rather confusing: val fix : ('a React.event -> 'a React.event * 'b) -> 'b Yes it's confusing. It's here to allow to define mutually recursive definitions and still expose them to the outside world. It is also usefull if you have other values that depend on the delayed value and you want to expose them to the outside world. There are example of this in the breakout.ml example. [snip] I tried to rexeplain E.fix and S.fix but I came up with what's written in their documentation sorry. Daniel Same comment for E.fix as for E.switch. I have never seen its documentation before. It's much much clearer now. All the best, -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
[Caml-list] Re: Recursion on React.events.
x () = let (e, set_e) = React.E.create () in Lwt_mutex.lock task_mutex >>= fun () -> task_channel := Some {schedule = date; trigger = set_e;}; Lwt_unix.write write_control_fd "X" 0 1 >>= function | 1 -> Lwt.return e | _ -> assert false in Lwt_main.run (aux ()) let regular_schedule start period = (* The let define tick in E.fix define is the proper way to implement recursive events. define has type React.event -> (React.event * React.event) and its argument is a placeholder for the event at time t-dt. *) let define tick = let tick' = React.E.switch (schedule start) (React.E.map begin function () -> schedule (Calendar.add (Calendar.now ()) period) end tick) in tick', tick' in React.E.fix define -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
[Caml-list] Re: Recursion on React.events.
Daniel Bünzli a écrit : Daniel Bünzli's module is great, but sometimes a bit rough to get by, specifically on examples such as this one. I would just like to point out that this has nothing to do with the module per se but understanding frp in general and this is the reason why I went to great length to document the semantics for each of the combinators I provide --- something most frp libraries won't bother to do, leaving you with testing or looking into the implementation for understanding things when tricky simulateneity issues arise. I appreciate the documentation effort you put up. Really. Thus to understand why your event didn't work you could have done the following. Provided you understand the notations given here : http://erratique.ch/software/react/doc/React#sem I do. I've done quite a lot of maths after all, and this doesn't frighten me. Since we have [schedule st]_st = Some (), by the semantics of E.map we have [ee]_st = Some ev. Thus we are in the second case of the semantics of E.switch (see doc) and the semantics of the switch reduces to the semantics of ev, i.e. Maybe I was looking in the wrong place, but I haven't found "the second case of the semantics of E.switch" on your website. In fact, the way I learned about React.E.switch was from the .mli-style webpage on your website, and by trial and error. Pure equational reasoning, it's not that hard, or is it ? Less than semi-algebraic geometry. More seriously, the point was not understanding why it failed. I came to the same conclusions from empirical evidence. The point was how to overcome it. And while I do not doubt that your documentation is rather explicit, I was nevertheless confused by your fixed point operators, and thus rather reluctant to use them. The example on your website: let history ?(eq = ( = )) s = let push v = function | [] -> [ v ] | v' :: _ as l when eq v v' -> l | l -> v :: l in let define h = let h' = S.l2 push s h in h', h' in S.fix [] define One thing that really troubles me, is that I do not understand why define returns a couple of two identical element. And the typing of E.fix is rather confusing: val fix : ('a React.event -> 'a React.event * 'b) -> 'b Why do we return a 'b type with E.fix? While the webpage mentions this dependence on the value at t-dt, it's quite hard to infer from the use of the fix point operator in the example how it's really supposed to behave and to be called. Clarifying these issues would be welcome. All the best, -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] Re: Recursion on React.events.
Richard Jones a écrit : On Wed, Dec 09, 2009 at 03:53:36PM +0800, Daniel Bünzli wrote: Daniel Bünzli's module is great, but sometimes a bit rough to get by, specifically on examples such as this one. I would just like to point out that this has nothing to do with the module per se but understanding frp in general [...] Personally I've yet to read any comprehensible introduction to FRP. I'm interested in whether FRP can be used to write Gtk interfaces with reduced code complexity. Apparently it can, but I've no idea how. Rich. Concerning documentation, Daniel's documentation is pretty good, and it's all that's been necessary to get me going. You should try having a look at it. I have little experience with Gtk, but I've written an Eliom web application using the ExtJS framework for windowing in browsers. In some sense, it's more complex than a Gtk application, because you have to manage lots of users, sessions, et ceteræ. Moreover the Eliom module was keeping track of the state of an Asterisk server, and initiating phone calls. I must say that using React was the only way to write the application cleanly and in a minimum amount of time. I was basically using signals for: -1- proxying persistent information such as user data and configuration in the SQLite database -2- parsing the output of the text-based Asterisk Manager Interface -3- keeping track of the state of the Asterisk server, and interacting with it (making phone calls, when the phone hangs up, when a call could not be made, etc...) -4- Keeping track of the IP of users of the web application coming from Ocsigen, and reconciliation with the IP of the softphones as registered by Asterisk (this allowed to avoid using passwords on the LAN) -5- Keeping track of the history of the phone calls made by agent, and feed it back to the administrator's web session -6- Doing all the "real-time" AJAX interaction for updating tables, windowing, et ceteræ. Doing it in a FRP way allowed to focus on the semantics, and moreover React update cycles integrate nicely with Lwt as used by Ocsigen. So you can do really cool stuff with it. It took me roughly one and half to two weeks from scratch (including learning the ExtJS library, troubleshooting the Asterisk Manager Interface, et ceteræ), with quite a lot of other concurrent obligations to handle. So yes, FRP is really cool. Unfortunately, it seems to me that Daniel's module is fairly low-level in the sense that it implements the bare mechanics and semantics of FRP. For real world application, you have to be quite nifty with tricky details about update cycles. For example, make a parser of the Asterisk Manager Interface with React around OCamlNet's Uq_engine module proved to be quite tricky, in a similar way as the issue that started this thread (here, I had no event, but in the Asterisk parser, I had doubled events, and I solved it in a very very ugly way). It's true that I may not completely understand how React works, as Daniel stated it before (a bit better now), but, for instance, the React.E.switch or React.S.switch is something that you'll be using a lot. And I feel the need for higher-level functions to deal with it, even though I do not have yet a precise idea of which such functions. All the best, -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
[Caml-list] Re: Recursion on React.events.
Guillaume Yziquel a écrit : Hello. I've been dabbling with recursive definition of React events. Suppose I have a function called schedule of type val schedule : Calendar.t -> unit React.event which throws out an event at the specified time or date. I've been trying to create a regular_schedule function that throws events at a regular pace. Daniel Bünzli's module is great, but sometimes a bit rough to get by, specifically on examples such as this one. So I came up with a recursive definition of such a React.event: let rec regular_schedule start_time period = React.E.switch React.E.never begin React.E.map begin fun () -> regular_schedule (Calendar.add (Calendar.now ()) period) period end begin schedule start_time end end First question: It almost works, in the sense that if you insert a print_endline after the fun (), well, it indeeds prints stuff on stdin at the specified pace. However, somehow, the event as a whole behaves as React.E.never. So it doesn't work. I guess it has to do with the way React.switch works synchronously, but I really do not get it. OK. The following piece of code works out, but it seems to me that using a React.E.select in this position is a rather ugly hack. let rec regular_schedule start period = let waiting_for = schedule start in React.E.switch React.E.never begin React.E.map begin fun () -> React.E.select [waiting_for; regular_schedule (Calendar.add (Calendar.now ()) period) period] end waiting_for end Second question: Is there somehow a notion of 'tail recursion' for such constructs? I gave some thought to it, and it seems quite plausible that what is done in the first place is analoguous to tail recursion. And that using React.E.select breaks the tail recursion. Am I offtrack? All the best, -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
[Caml-list] Recursion on React.events.
Hello. I've been dabbling with recursive definition of React events. Suppose I have a function called schedule of type val schedule : Calendar.t -> unit React.event which throws out an event at the specified time or date. I've been trying to create a regular_schedule function that throws events at a regular pace. Daniel Bünzli's module is great, but sometimes a bit rough to get by, specifically on examples such as this one. So I came up with a recursive definition of such a React.event: let rec regular_schedule start_time period = React.E.switch React.E.never begin React.E.map begin fun () -> regular_schedule (Calendar.add (Calendar.now ()) period) period end begin schedule start_time end end First question: It almost works, in the sense that if you insert a print_endline after the fun (), well, it indeeds prints stuff on stdin at the specified pace. However, somehow, the event as a whole behaves as React.E.never. So it doesn't work. I guess it has to do with the way React.switch works synchronously, but I really do not get it. Second question: Is there somehow a notion of 'tail recursion' for such constructs? All the best, -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
[Caml-list] Wrapping sigsetjmps/siglongjmps in OCaml.
Hello. I'm having some problems wrapping up the API for the R interpreter, namely because R seems to be using sigsetjmps and siglongjmps everywhere: that's how looping is implemented, for instance. (At least that's how I understand the source code). So I was wondering: what's the "best" way to wrap up such jumps in OCaml code? It may be that the jumps would happen in one single C function. Or it may be, due to a rather restrictive API for R, that I may have to reimplement some C code entirely in OCaml. In which case, the jumps would go over OCaml code. How would you deal with that? Here's the LONGJMP: SETJMP and LONGJMP are just macros to sigsetjmp and siglongjmp. /* jumpfun - jump to the named context */ static void jumpfun(RCNTXT * cptr, int mask, SEXP val) { Rboolean savevis = R_Visible; /* run onexit/cend code for all contexts down to but not including the jump target */ PROTECT(val); R_run_onexits(cptr); UNPROTECT(1); R_Visible = savevis; R_ReturnedValue = val; R_GlobalContext = cptr; /* this used to be set to cptr->nextcontext for non-toplevel jumps (with the context set back at the SETJMP for restarts). Changing this to always using cptr as the new global context should simplify some code and perhaps allow loops to be handled with fewer SETJMP's. LT */ R_restore_globals(R_GlobalContext); LONGJMP(cptr->cjmpbuf, mask); } Here's the SETJMP SEXP applyClosure(SEXP call, SEXP op, SEXP arglist, SEXP rho, SEXP suppliedenv) { SEXP body, formals, actuals, savedrho; volatile SEXP newrho; SEXP f, a, tmp; RCNTXT cntxt; /* formals = list of formal parameters */ /* actuals = values to be bound to formals */ /* arglist = the tagged list of arguments */ formals = FORMALS(op); body = BODY(op); savedrho = CLOENV(op); [...] /* Set a longjmp target which will catch any explicit returns from the function body. */ if ((SETJMP(cntxt.cjmpbuf))) { if (R_ReturnedValue == R_RestartToken) { cntxt.callflag = CTXT_RETURN; /* turn restart off */ R_ReturnedValue = R_NilValue; /* remove restart token */ PROTECT(tmp = eval(body, newrho)); } else PROTECT(tmp = R_ReturnedValue); } else { PROTECT(tmp = eval(body, newrho)); } endcontext(&cntxt); if (RDEBUG(op)) { Rprintf("exiting from: "); PrintValueRec(call, rho); } UNPROTECT(3); return (tmp); } All the best, -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] C stubs with many args.
Guillaume Yziquel a écrit : Hi. I've been recently reworking Maxence Guesdon's OCaml-R binding in order to provide a tighter integration with, and I'm currently trying to reverse-engineer the way closures are handled in R. So I've written up this small C stub code for a function with 6 parameters: OK. Figured it out. Stupid me: void Rf_begincontext (RCNTXT * cptr, int flags, SEXP syscall, SEXP env, SEXP sysp, SEXP promargs, SEXP callfun); CAMLprim value r_reveng_begin_context_native (value flags, value syscall, value env, value sysp, value promargs, value callfun) { CAMLparam5(flags, syscall, env, sysp, promargs); CAMLxparam1(callfun); CAMLlocal1(result); result = caml_alloc(1, Abstract_tag); Rf_begincontext ( (context) Field(result, 0), Int_val(flags), Sexp_val(syscall), Sexp_val(env), Sexp_val(sysp), Sexp_val(promargs), Sexp_val(callfun)); CAMLreturn(result); } CAMLprim value r_reveng_begin_context_bytecode (value * argv, int argn) { return r_reveng_begin_context_native(argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]); } All the best, -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
[Caml-list] C stubs with many args.
Hi. I've been recently reworking Maxence Guesdon's OCaml-R binding in order to provide a tighter integration with, and I'm currently trying to reverse-engineer the way closures are handled in R. So I've written up this small C stub code for a function with 6 parameters: void Rf_begincontext (RCNTXT * cptr, int flags, SEXP syscall, SEXP env, SEXP sysp, SEXP promargs, SEXP callfun); CAMLprim value r_reveng_begin_context_native (value flags, value syscall, value env, value sysp, value promargs, value callfun) { CAMLparam5(flags, syscall, env, sysp, promargs); CAMLxparam1(callfun); CAMLlocal1(result); result = caml_alloc(1, Abstract_tag); Rf_begincontext ( (context) Field(result, 0), Int_val(flags), Sexp_val(syscall), Sexp_val(env), Sexp_val(sysp), Sexp_val(promargs), Sexp_val(callfun)); CAMLreturn(result); } CAMLprim value r_reveng_begin_context_bytecode (value * argv, int argn) { } I've been trying to follow section 18.1.2 of: http://caml.inria.fr/pub/docs/manual-ocaml/manual032.html Unfortunately, I'm a bit confused as to what should the CAMLparam and such be for the bytecode stub. Could someone provide me with an example somewhere? All the best, -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] solicitation for ocamlbuild examples to go in a new repository
Erick Matsen a écrit : Hello Ocaml-folk-- As the previous and many other posts on this list demonstrate, there is a need for a collection of ocamlbuild examples which can be adapted to various setting. I've started such a project (at Sylvain LeGall's suggestion) at http://forge.ocamlcore.org/projects/obuild-examples/ I hope that the community will take a bit of time to sumbit examples. The point is, in my humble opinion, that we do need examples, but we'd better try to have a generic plugin that solves most of the use cases. And *precise* documentation of ocamlbuild to be able to write such a plugin, or other plugins. For now, the pain/benefit ratio of writing ocamlbuild plugins is clearly not worth it. Due to lack of documentation. I'd be very happy if others were interested in joining the project, but it might be easiest just to email examples directly to me. An ideal "package" from my perspective would have - a short description of what it does, just a sentence or two. - a commented myocamlbuild.ml file - the corresponding _tags file If you receive such examples, it would be useful to make them as generic as possible. There's no point, from a tutorial point of view, in having 'complex' myocamlbuild plugins that you have to wrap your head around in order to reuse. I'm thinking about examples on the wiki pages. I hope to get examples of all levels, from very basic to advanced. However, I think that there is a distinct need for simple examples which do one or two interesting things (a flood of 10 page myocamlbuild files isn't going to help people get off the ground). Yes. Exactly. Thanks, Erick There's definitely a know how out there. I'm thinking of bluestorm who helped me out with the ".inferred.mli" target for the plugin on the wiki. http://brion.inria.fr/gallium/index.php/Using_ocamlfind_with_ocamlbuild I gave feedback, and its been since then on the wiki page above. Maybe I'm mistaken, but this plugin hasn't evolved much since then. I'm fairly disappointed that it has not been augmented to fit the needs of C stubs in a generic way. All the best, -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] Re: Simple ocamlbuild example for C stubs?
Sylvain Le Gall a écrit : On 28-11-2009, Guillaume Yziquel wrote: Hello. I'm trying to build a .cma with C stubs with ocamlbuild. Linking and includes are supposed to be set to non-standard directories. You probably need to add some 'A"-ccopt"; A"your-option"' to the good tag. Can you give more details/actual layout of your myocamlbuild.ml ? OK. Yes, I could meddle with my myocamlbuild.ml file. My myocamlbuild.ml file is the same as the one on the wiki: http://brion.inria.fr/gallium/index.php/Using_ocamlfind_with_ocamlbuild But I mean, if I'm supposed to write a myocamlbuild.ml for every project I make, I might as well use Makefiles, as below. I was wondering if there was a myocamlbuild.ml that would solve the C stub problem and bottleneck. For instance, being able to _tag in the tags file for a given .c file the directories in which to look for headers (here /usr/share/R/include), and for .o files, all linking information (here, /usr/lib/R/lib/libR.so). The ideal would be to have all that available only from _tags. Because if you need to write a myocamlbuild.ml for each and every project, you might as well write Makefiles... That's the point of a generic plugin. yziq...@seldon:~/git/ocaml-r$ cat Makefile RLIBDIR=/usr/lib/R/lib RINCLUDES=-I . -I /usr/share/R/include INCLUDES= -I +ocamldoc -I `ocamlc -where`/caml $(RINCLUDES) COMPFLAGS=$(INCLUDES) LINKFLAGS=$(INCLUDES) -ccopt -L$(RLIBDIR) -cclib -lR LINKFLAGS_BYTE=$(INCLUDES) -ccopt -L$(RLIBDIR) -cclib -lR all: build #build: r.cma r.cmxa oCamlR.cma oCamlR.cmxa build: r.cma r.cmxa r.cma: dllr_stubs.so camlobjs ocamlc -a -dllpath /usr/lib/R/lib -dllib dllr_stubs.so -dllib libR.so -o r.cma r.cmo r.cmxa: dllr_stubs.so camlobjs ocamlopt -a -ccopt -L/usr/lib/R/lib -cclib -lr_stubs -cclib -lR -o r.cmxa r.cmx oCamlR.cma: camlobjs ocamlc -a -o oCamlR.cma oCamlR.cmo oCamlR.cmxa: camlobjs ocamlopt -a -o oCamlR.cmxa oCamlR.cmx camlobjs: standard.ml # ocamlbuild -classic-display r.cmo r.cmx oCamlR.cmo oCamlR.cmx ocamlbuild -classic-display r.cmo r.cmx cp _build/r.cmi . cp _build/r.cmo . cp _build/r.cmx . cp _build/r.o . # cp _build/oCamlR.cmi . # cp _build/oCamlR.cmo . # cp _build/oCamlR.cmx . standard.ml: r/standard.R R --silent --vanilla --slave < r/standard.R > r/standard.ml r_stubs.o: r_stubs.c ocamlopt -ccopt -Wall $(COMPFLAGS) -ccopt -fPIC -c $< libr_stubs.a: r_stubs.o ar rcs libr_stubs.a r_stubs.o dllr_stubs.so: libr_stubs.a r_stubs.o ocamlmklib -o r_stubs r_stubs.o clean: rm -f r/tandard.ml rm -f *.o *.so *.a *.cmi *.cmo *.cmx *.cma *.cmxa ocamlbuild -clean test: build ocaml -init ocamlinit install: cp META *.a *.cm[ai] *.cmxa /usr/lib/ocaml/R/ cp dllr_stubs.so /usr/lib/ocaml/stublibs/ All the best, -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] Partially hiding modules in packages
blue storm a écrit : Regarding your original problem, I've had the same needs and came up with a slightly different solution : in order to avoid the additional indirection level related to -pack (Foobar.Foo), is used a flattened representation by adding a "foobar.ml" file containing only : include Foo (and possibly include of other modules in the package). Then the foobarl.mli is : type foo_t val initial : foo_t val show : foo_t -> string And values can be referred with Foobar.foo, instead of Foobar.Foo.foo. Of course this is only useful if you don't want the user to see the internal module hierarchy, wich may not be what you had in mind. Where do you put the foobar.ml? I've been trying it all over, I do not see how you can flatten something that you pack. Do you put foobar.ml at the same level of your directory foobar/, or in you directory foobar/ ? Or am I understanding you wrong? All the best, -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
[Caml-list] Simple ocamlbuild example for C stubs?
Hello. I'm trying to build a .cma with C stubs with ocamlbuild. Linking and includes are supposed to be set to non-standard directories. Is there a state-of-the-art, and *simple* example lying around? Is there an ocamlbuild plugin that is more generic than the one on the Wiki http://brion.inria.fr/gallium/index.php/Ocamlbuild_example_with_C_stubs which I unfortunately find quite obscure. All the best, -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
[Caml-list] Polymorphic functors / modules and OCaml-R
Hello. I've been trying stuff like these: # module type 'a A = sig Error: Parse error: [a_UIDENT] expected after "type" (in [str_item]) # module type ['a] A = sig Error: Parse error: [a_UIDENT] expected after "type" (in [str_item]) # module type A = sig module type B end ;; Error: Failure: "abstract/nil module type not allowed here" # Is there a way, somehow, of introducing such polymorphism in modules / functors? That would help me a lot. I'm currently try to write bindings for R code, with OCaml-R, and I can come up with stuff like this: module Description : R.LibraryDescription = struct let name = "xts" let symbols = ["xts"] end module Library : R.Library = OCamlR.Require (Description) let [xts] = Library.root What would be nice would be Description to be polymorphic in some sense or another, so that I could describe the various R symbols that are made available by the xts library. The other, rather unrelated solution I see would be to replace stuff above by something like: module Description : R.LibraryDescription = struct let name = "xts" let symbols = ["xts"; "print_xts"] end module Library : R.Library = OCamlR.Require (Description) type t external list_to_tuple : 'a list -> 'b = "list_to_tuple" let ( (xts : unit -> t), (print_xts : t -> unit) ) = list_to_tuple Library.root where list_to_tuple would be a function constructing the tuple (no fixed size) representing a given list. This is rather unsafe... A polymorphic module, with argument a module type, would be something very useful to describe a R library... All the best, -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] Including code from a .cm[ox] into another .cm[ox]
Philippe Veber a écrit : You're right this is a linking issue and now the question is at which level you want to "link" your code. I do not see the point of including a cmo in another like you describe : i believe there are simpler and mainstream options. Maybe I miss some details about your problem ? Using findlib to help the linker is one way to do it, but if you insist on loading a single module then you have two other options : - code inclusion -> m4, camlmix, camlp4 or any preprocessor (not that ugly, but still) - the -pack option for combining several cmo in a single one (but then all your modules are included in a "toplevel" module) sorry if i still didn't get your problem ;o). ph. You're getting my problem right. I'm working on the OCaml-R binding of Maxence Guesdon. The thing is, I have a r.ml file, where all the binding work is done. However, in order to launch the shared library containing the code of the R interpreter, some environment variables must be set up first. Therefore I have a small R script, based on Dirk Eddelbuettel's littler software, that generates an .ml file, rstdenv.ml, containing the environment variables that need to be set up correctly. Maybe it's trying to be a bit too pretty, but I do not like the name Rstdenv for a module. I'd rather have R.Standard.env... So I'm looking for a way to include a module as a submodule, without having to link it to rstdenv.cmo, which I really do not want to be available from the r.cma archive. That's why I was wondering if there is a clean, camlish way, to link-substitute code from one .cmo into another .cmo... The -pack option is clearly overkill, camlp4 seems overkill too, m4 is ugly, do not know camlmix. There's also a package from Gerd Stolpmann, xstrp4 or something like that which could be useful. But as I want to minimise dependencies on extra stuff, I was wondering if there was an out-of-box obscure compiling option to do so. All the best, Guillaume Yziquel. 2009/11/12 Guillaume Yziquel Philippe Veber a écrit : Hi maybe you can have a look at findlib and its #require statement. For instance, pxp (xml related library) depends on many cma, but everything loads automagically when invoking #require : No, no, no... this is not the issue at all. My issue is not about loading stuff with findlib, it's about including a .cmo into another .cmo. I'd like to create a .cma with only a.ml, and not containing b.ml. It's not a toplevel issue, but a 'linking' issue. Thanks anyway. Guillaume. 2009/11/12 Guillaume Yziquel Hello. Imagine I have a file named a.ml containing module C = struct include B end and a file named b.ml containing the code let f x = x + 1 When I compile everything to .cmo files, I cannot load a.cmo from the toplevel without loading b.cmo beforehand. Is there a way to make the 'include B' statement to include the code of the B module in the C submodule directly so that it is not required to load the b.cmo file before loading the a.cmo file? That would be extremely useful to me... All the best, -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
[Caml-list] Including code from a .cm[ox] into another .cm[ox]
Hello. Imagine I have a file named a.ml containing module C = struct include B end and a file named b.ml containing the code let f x = x + 1 When I compile everything to .cmo files, I cannot load a.cmo from the toplevel without loading b.cmo beforehand. Is there a way to make the 'include B' statement to include the code of the B module in the C submodule directly so that it is not required to load the b.cmo file before loading the a.cmo file? That would be extremely useful to me... All the best, -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] Cannot safely evaluate the definition of the recursively-defined module
Hello. Sorry for reviving this short thread. I have the same error message, but I really do not understand what "safety" means in this context. If I specify the signature of the recursive module, shouldn't the type checker work out right out of the box? Sorry, but I'm a bit confused. You'll find the recursive submodule that I'm having problems with below Hugo's email. All the best, Guillaume Yziquel. Hugo Ferreira a écrit : Michael Furr wrote: On Wed, 18 Mar 2009, Hugo Ferreira wrote: I hope this is not a beginners questions. I am trying to reuse code via functors, however I am getting the following error: Cannot safely evaluate the definition of the recursively-defined module (refers to "AA.empty" when implemented as a constant value) I circumvented the problem by not using a constant value but a function instead. As I understand it this may cause run-time errors. My question is: is their any way to make the following example work. If you only need to store a constant value in the module, then you can get around the restriction by splitting the module into a (recursively-)safe module, and an extension that adds the constants. Here is a slightly modified version of your code showing the transformation: Ok, I understand this. Thanks, Hugo F. module type AA_Safe = sig type q type t = string val compare: t -> t -> int val add: t -> q -> q (* omit empty here, since it is not "safe" *) end module rec A1 : AA_Safe with type q = ASet.t = struct type q = ASet.t type t = string let compare s1 s2 = Pervasives.compare s1 s2 let add e s = ASet.add e s end and ASet : Set.S with type elt = A1.t = Set.Make(A1) (* now create the full module *) module type AA = sig include AA_Safe val empty: q end module A2 : AA = struct include A1 let empty = ASet.empty end module type Wrap_A = sig type t type q val init: q val add: t -> q -> q end module Make_A (An_A : AA) : Wrap_A = struct type t = An_A.t type q = An_A.q (*let init = ASet.empty*) let init = An_A.empty let add t q = An_A.add t q end module Wrap_A1 = Make_A( A2 ) Cheers, -Mike Here's my recursive submodule: module rec Registry : sig val new_status_signal : t -> status React.signal val registry : (t * status React.signal) list React.signal val status_of_agent : t -> status end = struct let new_status_signal agent = React.S.fold begin function current_status -> function | AgentPresent (agent_of_signal, status_information) -> begin match agent = agent_of_signal with | false -> current_status | true -> status_information end | AsteriskStatus (Asterisk.Active activity) -> let agent_ip = match Registry.status_of_agent agent with | Present ip -> Some ip | Online (ip, _) -> Some ip | _ -> None in begin match agent_ip with None -> current_status | Some ip -> current_status (* To do... *) end | AsteriskStatus _ -> current_status end Offline (React.E.select [ agent_status_notification; (React.E.map begin function s -> AsteriskStatus s end (Asterisk.server # status_change)) ]) let registry = React.S.fold begin fun live_registry new_agent -> new_agent::live_registry end begin Lwt_main.run (persistent_registry >>= Ocsipersist.get >>= begin function a_list -> Lwt.return (List.map begin function (nom, prenom) -> let a = {nom = nom; prenom = prenom} in a, (Registry.new_status_signal a) end a_list) end) end begin React.E.map begin function agent -> agent, (Registry.new_status_signal agent) end adding_to_registry end let status_of_agent agent = try React.S.value (List.assoc agent (React.S.value Registry.registry)) with Not_found -> raise (invalid_arg ("Agent.status_of_agent: "^agent.prenom^" "^agent.nom)) end -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
[Caml-list] Re: React.E.switch issue.
Daniel Bünzli a écrit : My issue is that the 'reinitialise_with' function is called in a function 'phi' which is used in the following way: let message_event = React.E.map phi to_be_parsed_event. Cannot really make sense out of your snippets of code. What I want to do is the following: The server sends events with chunks of string that I want to parse. I accumulate the string chunks (with React.E.fold) until I can parse some server message out of it. When some message is parsed, I discard this part of the event, and I install another "accumulating event" (accumulating with React.E.fold). In order to discard and renew the "accumulating event", I send an event to the event of event. This is why I use the React.E.switch construct. The output of React.E.switch is an event that can hold, for example the following sequence of values: My fi My first mes My first message. My s (Here is where the event of event is renewed:) My s My secon My second mess etc... However this phi functions seems to invoke a primitive event sending function Yes. phi is the function that parses the messages from the server. So it has to send an event to renew the "accumulating event". and that's explicitely prohibited by the documentation. Primitive event sending/signal setting functions cannot be invoked as side effects inside update cycles (see doc of E.create/S.create). OK. So this is not a bug, nor a feature. Not sure what you are trying to achieve but I suspect fixed point combinators (E.fix/S.fix) may help you to solve your problem. I tried to look into this, but I did not see how they could help me with my specific issue. Best, Daniel For now, I'm using a workaround, but I'll try to see how I can make this clean... Many thanks for your answer. -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
[Caml-list] Re: React.E.switch issue.
Guillaume Yziquel a écrit : Hello. Hi again. Here is a piece of code that I am having issue. I'm trying to use React to parse reactively a server output. I have the following event definition: let event_starting_at str = React.E.fold begin fun accu chunk -> accu^chunk end str received_event in let to_be_parsed_event_of_event, set_to_be_parsed_event_of_event = React.E.create () in let to_be_parsed_event = React.E.switch (event_starting_at "") to_be_parsed_event_of_event in let reinitialise_with unparsed_text = set_to_be_parsed_event_of_event (event_starting_at unparsed_text) in I've replaced the previous code by the following piece of code, and it now works... let event_starting_at ?drop:(drop = false) str = React.E.fold begin fun accu chunk -> accu^chunk end str begin match drop with | false -> received_event | true -> React.E.drop_once received_event end in let to_be_parsed_event_of_event, set_to_be_parsed_event_of_event = React.E.create () in let to_be_parsed_event = React.E.switch (event_starting_at "") to_be_parsed_event_of_event in let reinitialise_with unparsed_text = set_to_be_parsed_event_of_event (event_starting_at ~drop: true unparsed_text) in Now, is this a bug or a feature? All the best, Guillaume Yziquel. -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
[Caml-list] React.E.switch issue.
Hello. Here is a piece of code that I am having issue. I'm trying to use React to parse reactively a server output. I have the following event definition: let event_starting_at str = React.E.fold begin fun accu chunk -> accu^chunk end str received_event in let to_be_parsed_event_of_event, set_to_be_parsed_event_of_event = React.E.create () in let to_be_parsed_event = React.E.switch (event_starting_at "") to_be_parsed_event_of_event in let reinitialise_with unparsed_text = set_to_be_parsed_event_of_event (event_starting_at unparsed_text) in String chunks from the server are received by the 'received_event' event, on the first line. My issue is that the 'reinitialise_with' function is called in a function 'phi' which is used in the following way: let message_event = React.E.map phi to_be_parsed_event. phi is the parsing function, so I'm not reproducing it directly here. However, you would have the behaviour described further below with the following code: let phi string_chunk = let new_string_chunk = String.copy string_chunk in reinitialise_with new_string_chunk; new_string_chunk This creates hiccups in the events. For example, at different time intervals, with to_be_parsed_event, I get: q qqw qqwwe qqwweer qqwweerrt etc... where I'd like in fact to have q qw qwe qwer qwert Advice would be appreciated on how to correct this. All the best, -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] polymorphic method.
Jacques Garrigue a écrit : From: Guillaume Yziquel To continue on the example of nil: the current definition of nil (i.e. the one with type ) would be written as class nil : object polymorphic method hd = raise Empty polymorphic method tl = raise Empty end and the definition class nil : object method hd = raise Empty method tl = raise Empty end would not compile since the 'a and the 'b would not be bound in the definition of class nil. Just to be sure we are talking about the same thing. This is indeed what you are proposing. But from my point of view the distinction is not really relevant: one can easily build examples where methods should be polymorphic, but not maximally. A typical example is fold: class nil = object polymorphic method fold f x = x end fold would here have type 'a 'b. 'b -> 'a -> 'a with the proposed use of the polymorphic keyword. class nil : object method fold : 'a 'b. 'a -> 'b -> 'b end OK. Same type. class ['a] cons (h:'a) (t : 'self) = object (self : 'self) polymorphic method fold f x = f h (t#fold f x) end fold would have type 'c. ('a -> 'c -> 'c) -> 'b -> 'c And if you take into account the nil construct, then you would have 'b = 'c. But that's not the case here. class ['a] cons : 'a -> 'b -> object ('b) method fold : 'c. ('a -> 'c -> 'c) -> 'c -> 'c end Yes, we broadly agree here. As you can see, the right type is going to be inferred for cons (and a polymorphic one!), but again the type for nil is wrong. In order to obtain the right one, you must be fully explicit: class ['a] nil = object polymorphic method fold (f : 'a -> 'b -> 'b) (x : 'b) = x end I perfectly agree that one needs to be fully explicit to get the right types. Or what would perhaps be best, use a class type. But, without wanting to offend you, this is rather theoretical. I do not say that it is not important, far from it. But you're showing the use of two different interacting classes and showing me that using the polymorphic keyword, I might not get what I want. From a practical point of view, I'm using (now) only one class with lots of methods, and lots of parameters. Which is a rather common situation. So we're not here in the exact same situation. If I do not use the polymorphic keyword, I would still get the problem of having to type explicitely the fold method of the nil element. Using the polymorphic keyword, I still would. I do not see any improvement or any disadvantage from this point of view when it comes to the 'polymorphic' keyword. class ['a] nil = object polymorphic method fold (f : 'a -> 'b -> 'b) x = x : 'b end would be perfectly fine for me. At least better than class ['a] nil = object method fold : 'b. (('a -> 'b -> 'b) -> 'b -> 'b) = fun f x -> x end The polymorphic keyword's only purpose would to avoid having to manually set types when developing methods incrementally, like adding arguments, erasing the only occurence of an argument in the method's code. Without a polymorphic keyword, these are a pain. The former is neater when it comes to developing OO code. The latter is a pain because you have to mentally disconstruct the method type, match the right argument, et ceterae. Of course, like any other thing, (seesaws, teddy bears, demineralised watter), wrong usage might lead to adverse consequences. The 'polymorphic' keyword wouldn't be a typing miracle, just a mere convenience for OO development. Isn't that inconsistent to allow 'a coming from exceptions to get bound, while not doing so for some other 'a? (Sorry if I'm being unclear and using approximative terminology). This doesn't work because of raise, but because I used an immediate object rather than a class. Immediate objects may have implicit polymorphism at the object level (not at the method level), while everything must be explicit in classes (because classes define types also). I'll have to slowly swallow this one. Humm... I still do not see why there would be ambiguity in choosing 'the most general' polymorphic type... Can't 'the most polymorphic one' be properly defined? The most polymorphic one is properly defined, as a function of the current type system (which may always be improved). But the most polymorphic one is not necessarily the one you want, as my example with nil shows. And once you have a polymorphic type, there exists an infinity of other valid polymorphic types for the same method (obtained by instantiating repeatedly type variables with ['a option] for instance). Well if
Re: [Caml-list] polymorphic method.
blue storm a écrit : With a camlp4 extension, you could inspect the (syntaxically explicit) parameters of you method, and (syntaxically) generate a polymorphic type for each one : "polymorphic method foo bar baz = ..." would be translated into "method foo : 'a 'b . 'a -> 'b -> 'c = fun (bar : 'a) (baz : 'b) -> ...". This is probably not what you want. Indeed, it's not what I want. but my general advice is not to try to much to do type-level transformation by syntaxic transformations : they tend to get flawed in ways you don't expect, and this is just not the right tool for the job. Too bad there's no "type checking extension" in Objective Caml. That would be huge fun. Thanks. -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] polymorphic method.
Jacques Garrigue a écrit : From: Guillaume Yziquel By the way, I do not exactly understand the "you might end up with types more polymorphic than you expected" part. This is actually the main problem. At some point, I actually considered generating automatically polymorphic method types where possible. The idea would be simply to first give all the methods in a class monomorphic types (to avoid the undecidability of polymorphic recursion), and then generalize all type variables that do not "escape": i.e. do not appear in class parameters, value fields, or global references. Technically this is perfectly doable. Yes, I figured that out. Theoretically, there are problems with principality, as there is no most generic type for a polymorphic method (all types are incompatible with each other). It is easier to see that on a practical example. Say that I defined lists: class ['a] cons x l = object (_ : 'self) method hd : 'a = x method tl : 'self = l end class nil = object method hd = raise Empty method tl = raise Empty end Cute way of defining lists. Now, both cons and nil would be typable (cons is already typable), and the inferred types would be: class ['a] cons : 'a -> 'b -> object ('b) method hd : 'a method tl : 'b end class nil : object method hd : 'a method tl : 'b end At first glance, it seems that the type of nil being completely polymorphic, we could pass it as second argument to cons. However, it is not the case. cons has two monomorphic methods, while nil has two polymorhic methods, and their types are incomparable. If we look at object types, type 'a cons = < hd : 'a; tl : 'b > as 'b type nil = < hd : 'a.'a ; tl : 'b.'b > Of course, you could argue that what is wrong is the definition of nil. But basically there is no way to decide what is the right type for nil as soon as we allow inferring polymorphic methods. To continue on the example of nil: the current definition of nil (i.e. the one with type ) would be written as class nil : object polymorphic method hd = raise Empty polymorphic method tl = raise Empty end and the definition class nil : object method hd = raise Empty method tl = raise Empty end would not compile since the 'a and the 'b would not be bound in the definition of class nil. Just to be sure we are talking about the same thing. Interestingly, currently you can define nil as an immediate object and have immediately the right type without any annotation: exception Empty let nil = object method hd = raise Empty method tl = raise Empty end ;; val nil : < hd : 'a; tl : 'b > = So you're saying that what I proposed up there, saying that it would not compile properly, indeed works out fine in the current setting? Isn't that inconsistent to allow 'a coming from exceptions to get bound, while not doing so for some other 'a? (Sorry if I'm being unclear and using approximative terminology). let l = new cons 3 nil ;; val l : int cons = So, the current approach is to privilege the monomorphic case, requiring type annotations for the polymorphic case. Your suggestion of allowing to give a hint that you want a polymorphic type makes sense, but it does not say which polymorphic type: there might be several, with different levels of polymorphism, with no way to choose between them. Probably it would be ok to choose the most polymorphic one, but one can always find counter-examples. Humm... I still do not see why there would be ambiguity in choosing 'the most general' polymorphic type... Can't 'the most polymorphic one' be properly defined? So the meaning of your "polymorphic" keyword would be: "give me the most polymorphic type for this method, I hope I understand what it will be, but if I'm wrong and it breaks my program I won't complain". This may be practically ok, Yes. For me, it would be OK. Even more if 'the most polymorphic one' is properly defined. I wouldn't worry too much about the 'I hope I understand what it will be' in this case. but this is a hard sell as a language feature. Particularly when you think that future versions of the compiler may be able to infer more polymorphic types, thanks to improvements in type inference, and suddenly break your program. I'd like to suggest something naïve: for each 'a type, try to bind it to the class definition (what you call monomorphic I think), and if you can't, then bind it to the method definition (what you call polymorphic). (This, of course, in the presence of the 'polymorphic' keyword). This seems, at least naïvely, properly defined behaviour. And from a practical point of view, this is what I'd be looking for. Of
Re: [Caml-list] polymorphic method.
Jacques Garrigue a écrit : There are already polymorphic methods in ocaml. The syntax for your example would be: class myobject = object method id : 'a. 'a -> 'a = fun x -> x end Yes, I know that there are already polymorphic methods in ocaml. A "polymorphic" keyword might seem simpler, but it would be complex to handle the case where a polymorphic method type contains also class parameters: class ['a] cell (x : 'a) = object method pair : 'b. 'b -> 'a * 'b = fun y -> (x,y) end Indeed. But you could also write: class ['a] cell (x: 'a) = object polymorphic method pair y = (x, y) end The polymorphic keyword would only bind what can be bind. Since x is already of type 'a, it would escape the scope of the 'polymorphic' keyword. But y would not escape the scope of the polymorphic keyword. More generally, you might end up with types more polymorphic than you expected, and since differently instantiated polymorphic method types are incompatible, this would be a problem. Well, for now, when I write methods, my methods tend to be not polymorphic enough. One could keep the default behaviour without the keyword, and also use the keyword polymorphic to bind only what can be bound (i.e. not 'x' in your example). The problem I am facing now is cumbersome: writing types for methods arguments everywhere... That's not what people would expect for type inference, unfortunately. The 'polymorphic' keyword would only be a hint as to how type inference would be done. This way I wouldn't have to keep the typing of the method arguments in sync with the code of the method (or at least, much less). By the way, I do not exactly understand the "you might end up with types more polymorphic than you expected" part. Jacques Garrigue -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
[Caml-list] Re: polymorphic method.
Hello. When developing with objects in OCaml, I'm quite often faced with polymorphic methods. Such as: class myobject = object method id x = x end Sometimes you have many methods that you're tinkling with, and the compiler keeps saying to you that 'a is inbound in this class declaration. I'm therefore wondering if it would be a good idea to have a keyword 'polymorphic', and one would write class myobject = object polymorphic method id x = x end The polymorphic keyword would be a hint that the method is polymorphic and that there is no need to look at the class' type parameters. -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
[Caml-list] polymorphic method.
Hello. When developing with objects in OCaml, I'm quite often faced with polymorphic methods. Such as: class myobject = object method id x = x end Sometimes you have many methods that you're tinkling with, and the compiler keeps saying to you that 'a is inbound in this class declaration. I'm therefore wondering if it would be a good idea to have a keyword 'polymorphic', and one would write class myobject = object polymorphic method id x = x end The polymorphic keyword would be a hint that the method is polymorphic and that there is no need to look at the class' type parameters. -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] Compiling C++ in OCaml using Swig to native code
Tautrimas Pajarskas a écrit : Hello, Hello. I'm trying to access C++ code from OCaml using Swig. I successfully compiled C++ code as a shared library through swig's C++ wrapper but only in bytecode. Now, if I try the procedures listed in http://www.linux-nantes.org/~fmonnier/OCaml/ocaml-wrapping-c.php#ref_cplusplus for ocamlopt, I get an error: I'm sorry I can't help you, but you can help me: I'm also interested in binding C++ code to OCaml. Could I have a look at what you did so that I can have some guidance as to how to bind C++ code? I'd be perfectly happy with bytecode... Tautrimas Pajarskas All the best, Guillaume Yziquel. -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
[Caml-list] Re: Obj.magic and existential types.
Daniel Bünzli a écrit : Not directly responding to your question but you are looking for functional reactive programming (frp). http://erratique.ch/software/react I rewrote your example below with react (no magic used). Best, Daniel Thanks a lot. Very good to know. That will save me time. Just a side question: how thread-safe is React? All the best, Guillaume Yziquel. ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
[Caml-list] Obj.magic and existential types.
Hello. Please don't scream: I've been using Obj.magic... But the result is rather interesting. It can record a flow of computations, and recompute them only when upstream data has been modified: # let (n', n) = Dependent.encapsulate 1;; val n' : int Dependent.data = val n : int Dependent.t = # let (_, next) = Dependent.encapsulate (fun x -> x + 1);; val next : (int -> int) Dependent.t = # let m = Dependent.apply next n;; val m : int Dependent.t = # Dependent.access m;; - : int = 2 # Dependent.set n' 3;; - : unit = () # Dependent.access m;; - : int = 4 The piece of code responsible for this behaviour is at the end of the message. I learnt that I could perhaps overcome the use of Obj.magic by using existential types. I was advised to read the following post on this topic: http://caml.inria.fr/pub/ml-archives/caml-list/2004/01/52732867110697f55650778d883ae5e9.en.html However, I do not really understand how Daniel implemented existential types there, and I do not really see how it can be adapted to my code. Suggestions welcomed. Here's the code, rather disorganised at the moment. All the best, Guillaume Yziquel. type read;; type write;; type 'a computation = (Obj.t -> 'a) t * Obj.t t and ('a, 'b) aux_t = Dependent of ( 'a option ref * 'a computation option * Obj.t t list ref) and 'a data = ('a, write) aux_t and 'a t= ('a, read) aux_t;; let encapsulate (x : 'a) : ('a data) * ('a t) = let z = Dependent ((ref (Some x)), None, (ref [])) in (z, z);; let add_dependency (alpha : 'a t) (beta : 'b t) = let Dependent (_, _, dep) = alpha in dep := ((Obj.magic beta) : Obj.t t)::!dep;; let apply (f : ('b -> 'a) t) (x : 'b t) : 'a t = let computation : 'a computation = ((Obj.magic f) : (Obj.t -> 'a) t), ((Obj.magic x) : Obj.t t) in let f_x : 'a t = Dependent ( ((ref None) : 'a option ref), ((Some computation) : 'a computation option), ((ref []) : Obj.t t list ref)) in add_dependency f f_x; add_dependency x f_x; f_x;; exception Undefined;; module rec Aux : sig val access : 'a t -> 'a val update : 'a t -> ('b -> 'a) t -> 'b t -> 'a val reset : 'a t -> unit end = struct let rec access y = let Dependent (opt_ref_x, comp_opt, _) = y in match !opt_ref_x with | Some x -> x | None -> begin match comp_opt with | None -> raise Undefined | Some (fun_t, arg_t) -> Aux.update y fun_t arg_t end and update y fun_t arg_t = let Dependent (opt_ref_x, _, dependencies) = y in List.iter Aux.reset !dependencies; let result = (Aux.access fun_t) (Aux.access arg_t) in opt_ref_x := Some result; result and reset z = let Dependent (opt_ref_x, _, dependencies) = z in match !opt_ref_x with | None -> () | Some _ -> begin opt_ref_x := None; List.iter Aux.reset !dependencies end;; end;; include Aux;; exception Flawed_implementation;; let set (x : 'a data) (v : 'a) : unit = let Dependent (opt_ref_x, comp_opt, dependencies) = x in match comp_opt with | Some _ -> raise Flawed_implementation | None -> begin List.iter Aux.reset !dependencies; opt_ref_x := Some v end;; -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
[Caml-list] ocamlbuild and ocamlfind - infer_interface
Hello. A small comment on the ocamlbuild wiki, and more specifically on its plugin for ocamlfind: http://brion.inria.fr/gallium/index.php/Using_ocamlfind_with_ocamlbuild This plugin fails to generate .inferred.mli files. The following lines (thanks to bluestorm on #ocaml irc channel) are needed in the After_rules of the plugin: -1- flag ["ocaml"; "infer_interface"; "pkg_"^pkg] & S[A"-package"; A pkg]; -2- flag ["ocaml"; "infer_interface"; "syntax_"^syntax] & S[A"-syntax"; A syntax]; -3- flag ["ocaml"; "pkg_threads"; "infer_interface"] (S[A "-thread"]) Since I could not find a single occurrence of "infer_interface" on the Gallium wiki, and since I do not believe that using ocamlbuild and ocamlfind together to infer .mli files is "not a simple task", I sincerely believe that the documentation of ocamlbuild is insufficient, and insufficently structured. (This is to echo the debate between Daniel Bünzli and Romain Bardou, among others, two or three weeks ago concerning the lack of documentation). Could these three lines be added to the myocamlbuild.ml plugin for ocamlfind on the Gallium wiki, and could tags such as "infer_interface" be documented thoroughly on the wiki? That would be helpful! All the best, -- Guillaume Yziquel http://yziquel.homelinux.org/ ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
Re: [Caml-list] Compiling recursive modules into a .cma.
Stéphane Glondu a écrit : > > It seems that chain.cmo is linked before protection.cmo inside the .cma. > The order of modules inside of a .cma file is important. The behaviour > is the same as if they were #loaded in the same order in a toplevel. Try > writing explicitly all .ml files of $(SOURCE) in topological order. Yes. Indeed. This is the problem. I was misled by the fact that compiling things manually and in order didn't work at first, and I believed something else was wrong, but I was mistaken. It now works. Thanks. Guillaume. ___ Caml-list mailing list. Subscription management: http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list Archives: http://caml.inria.fr Beginner's list: http://groups.yahoo.com/group/ocaml_beginners Bug reports: http://caml.inria.fr/bin/caml-bugs
[Caml-list] Compiling recursive modules into a .cma.
Hello, list. I've been recently trying to compile a module I made. I can load the .cmo I generate out of it, but not the .cma I generate out of it. > [EMAIL PROTECTED]:~/svn/ocaml-yziquel$ ocaml > Objective Caml version 3.10.2 > > # #load "ocaml-yziquel.cma";; > Reference to undefined global `Protection' > # The issue is, I think, the fact that it is a recursive module. You'll find the code at the end of this email. I needed a recursive module because the following (simplified code) did not manage to type things "correctly". For instance protected_value was supposed to have type 'a protected -> 'a... > type 'a protected = > | Protected of 'a * ((Mutex.t * Condition.t) ref protected * Mutex.t) > | Unprotected of 'a > > let rec protect data = match data with > | Unprotected _ -> () > | Protected (_, (locking_data, mutex)) -> > Mutex.lock mutex; > let (mut, cond) = !(protected_value locking_data) in > Mutex.lock mut > > and (protected_value: 'a protected -> 'a) = > function protected_data -> match protected_data with > | Unprotected d -> d > | Protected (d, _) -> d > > and unprotect data = match data with > | Unprotected _ -> () > | Protected (_, (locking_data, mutex)) -> > let (mut, cond) = !(protected_value locking_data) in > Mutex.unlock mut; > unprotect locking_data; > Mutex.unlock mutex;; > > val protect : 'a protected -> unit = > val protected_value : > (Mutex.t * Condition.t) ref protected -> (Mutex.t * Condition.t) ref = > > val unprotect : (Mutex.t * Condition.t) ref protected -> unit = A look at protection.cmo with ocamlobjinfo gave the following output: > Unit name: Protection > Interfaces imported: > 8ba3d1faa24d659525c9025f41fd0c57Pervasives > 19e9e3e1586622e6bee0a641bcbccbd7Condition > da1ce9168f0408ff26158af757456948List > dc6994f75cfd14f73e718f81aa215803CamlinternalMod > 855af44384a5465360efe6e8bff546abMutex > 09ed2ebaeb54934aa3f583a41f71ca7bProtection > 5cfae708052c692ea39d23ed930fd64dObj > Uses unsafe features: no The modules CamlinternalMod and Obj are not pulled down to chain.cmo (which depends on the Protection module). I do not know what these modules stand for. To sum up, I'm able to load the .cmo in the ocaml toplevel, but not the .cma file generated out of the Protection and Chain modules... Any ideas / suggestions / explanations are welcome... (Please keep my adress in Cc: when replying). All the best, Guillaume Yziquel. Here is the code of the protection.ml file: > [EMAIL PROTECTED]:~/svn/ocaml-yziquel$ cat protection.ml > module rec Protection : > sig > > type 'a protected = > | Protected of 'a * ((Mutex.t * Condition.t) ref protected * Mutex.t) > | Unprotected of 'a > > val protect : 'a protected -> unit > val protected_value : ?protection:bool -> ?force:bool -> 'a protected -> 'a > val unprotect : ?strongly:bool -> ?force:bool -> 'a protected -> unit > val try_protect : ?strongly:bool -> 'a protected -> bool > val protected : ?protection:bool -> ?lockdata:(Mutex.t * Condition.t) list > -> 'a -> 'a protected > val mutually_protected : ?protection:bool -> ?lockdata:(Mutex.t * > Condition.t) list -> 'a list -> 'a protected list > val lock_of_protected : ?force:bool -> 'a protected -> (Mutex.t * > Condition.t) ref protected > > end = struct > > type 'a protected = > | Protected of 'a * ((Mutex.t * Condition.t) ref protected * Mutex.t) > | Unprotected of 'a;; > > let protect data = > match data with > | Unprotected _ -> () > | Protected (_, (locking_data, mutex)) -> > Mutex.lock mutex; > let aux_cond = ref None in > while not > ( let (mut, cond) = !(Protection.protected_value locking_data) in > aux_cond := Some cond; > let b = Mutex.try_lock mut in > Protection.unprotect locking_data; b > ) do match !aux_cond with >| None -> failwith "Protection.protected" >| Some c -> Condition.wait c (Mutex.create ()) > done;; > > let protected_value ?protection:(protection=true) > ?force:(force=false) > (protected_data: 'a protected) = > if not force then protect protected_