I'm reading some Ocaml project's source code and I'm new to Ocaml.I'm confused in the following code,which is a some kind of type definition in a .ml file.
type event = Event.t = ..
What's the meaning of '..' in the code,I searched the manual but get nothing. And in the event.mli,the type definition is :
type t = ..
type event = t = ..
Any help is appreciated,thanks.
Its new "extensible variant types". See http://caml.inria.fr/pub/docs/manual-ocaml/extn.html#sec251 for details.
You can declare a empty extensible variant type with
type t = ..
then later you can add new constructors like
type t += Foo | Bar of int
You can add constructors to extensible variants more than once places of programs. Instead, you cannot enjoy non-exhaustiveness check at pattern match, which is available for normal variants.
type event = t = .. declares an alias event of already existing extensible type t. = .. is required to make the new type also extensible.
type event = t = ..
type event += Poo (* you cannot do this if type event = t *)
Note
Extensible variant types may be useful when:
You do not want to fix the set of the constructors.
You feel constructors are rather loosely related each other and see no benefit to declare them in one place.
For example, the type of various errors of an application is a good candidate to define as an EVT: an app may fail due to a network issue, an auth failure, disk full and so on. They are unrelated with each other and come from many parts of the app. In that case you may want to define the type error as an EVT:
(* module Error *)
type t = ..
(* module Web *)
type Error.t += Http of int (* ex. 404 *)
(* module Tempfile *)
type Error.t += Diskfull of Path.t
(* module ErrorHandler *)
let print_error (e : Error.t) = match e with
| Web.HTTP stat -> ...
| Tempfile.Diskfull path -> ...
| ...
You may notice it looks like exceptions, actually EVT is generalized version of exception.
It is an extensible variant type. It's a variant to which you can add new cases in other places than the definition point. For example you can add to this event yourself in your code by writing:
type event +=
| Mouse_move of int * int
| Mouse_down of int * int
Extensible variant types are part of the language since 4.02 and are described in the manual in this section.
Related
When writing this function:
let make_new_instance class_name = new class_name
I get the error "unbound class class_name", however, this is just a function definition, not a function call. How do I delay the "new" so that it doesn't attempt to construct an object until the function is called?
You cannot do it in OCaml, which is a statically typed language. Classes must be statically specified at new and cannot be used as arguments to function applications. (new is not even a function but a special form new <classname>.)
One way to parameterize classes is to use functors:
module A = struct
class c = object
method x = 1
end
end
module Make(A : sig class c : object method x : int end end) = struct
let make_new_instance () = new A.c
end
module MakeA = Make(A)
but I am afraid this is far from you want.
This isn't really something you can do in OCaml. One way to see this is to think about what you would pass to the function. A class name is a type, not a value. Another way is to note that a function can only return values of one type. Different classes have different types.
Did you try to change you class_name parameter to unit ?
let make_new_class_name () = new class_name
Classes in a OCaml are like blueprints, but to create something, you usually do not start from blueprints, but go to factory. So, if you need a factory that creates an instances of certain class, then it can be done:
class blue_print x y = object ... end
let create_instance = new blue_print
let factory instance_maker x y = instance_maker x y
Of course, all this doesn't make big sense, since example is very reduced, but if it is coupled with some registry, where you store instace_makers, then you will get an abstract factory
I get the error unbound class class_name, however, this is just a function definition, not a function call. How do I delay the "new" so that it doesn't attempt to construct an object until the function is called?
The error you get comes from the fact that class_name here is the name of a function argument, but you try to have it carry the name of a class. In languages like PERL, PHP, or other similar languages, you have access at runtime to symbol tables, thus letting you define new functions, new classes, new variables, and reference them in variables. For instance, in PHP, the code:
<?php
function foo($var){ echo ${$var};}
$bar = "foo";
$bar($bar);
would render:
"Function"
by calling the function foo through the variable $bar.
In OCaml, you cannot do something like that with value names, in your precise case, the grammar strictly expects a class name after the keyword new (otherwise you would be confronted with problems typically encountered in dynamic languages, ie, how to check whether the variable content is really a class) - Jeffrey Scoffield is spot on there. However, being a functional language, the usual way is to pass around functions, and apply them to parameters in other functions:
class foo () = object
method m = "foo"
end
class bar () = object
method m = "bar"
end
Both class above have the same class type, and expect the same arguments to create instances of them, thus you may use them interchangeably without typing issues.
let mk_instance toggle : object method m : string end =
if toggle
then new foo ()
else new bar ()
the function mk_instance will produce either an instance of foo or an instance of bar depending on the value of toggle.
You can use that to your advantage by creating functions wrapping instantiations of foos and bars, and then pass them around:
let mk_foo = new foo
let mk_bar = new bar
let mk_instance mk : object method m : string end = mk ()
The above is trivial, but you may certainly envision cases with more involved class definitions, and with closures, it is always possible to align function signatures to make this easier, or embed them in sum types to indicate different possibilities.
I am trying to unit test a parser that parses a string and returns the corresponding abstract syntax tree (represented as a discriminated union). I figured it would be pretty compact to use Xunit.Extensions' attribute InlineData to stack all test cases on one another:
[<Theory>]
[<InlineData("1 +1 ", Binary(Literal(Number(1.0)), Add, Literal(Number(1.0))))>]
...
let ``parsed string matches the expected result`` () =
However, compiler complains that the second argument is not a literal (compile time constant if I understand it correctly).
Is there a workaround for this? If not, what would be the most sensible way to structure parser result tests while keeping every case as a separate unit test?
One possibility is to use xUnit's MemberData attribute. A disadvantage with this approach is that this parameterized test appears in Visual Studio's Test Explorer as one test instead of two separate tests because collections lack xUnit's IXunitSerializable interface and xUnit hasn't added build-in serialization support for that type either. See xunit/xunit/issues/429 for more information.
Here is a minimal working example.
module TestModule
open Xunit
type DU = A | B | C
type TestType () =
static member TestProperty
with get() : obj[] list =
[
[| A; "a" |]
[| B; "b" |]
]
[<Theory>]
[<MemberData("TestProperty")>]
member __.TestMethod (a:DU) (b:string) =
Assert.Equal(A, a)
See also this similar question in which I give a similar answer.
I'm trying to work with the ocaml-inotify package. The relevant parts for this question can be defined as follows
module Inotify : sig
type wd
val int_of_wd : wd -> int
end = struct
type wd = int
let int_of_wd wd = wd
end
This work is taking place in a setuid script, and I want the inotify parts to be handled unprivileged, so I'm forking and then setuid-ing down to an unprivileged user in the child. However, this means that I need to pass the wd entities back to the parent through a pipe, and so need to serialise and deserialise them, requiring a int_to_wd function.
I've tried extending the module as follows:
module Rich_Inotify : sig
include module type of Inotify with type wd := int
val wd_of_int : int -> wd
end = struct
include Inotify
let wd_of_int (wd:int) : wd = wd
end
module Inotify = Rich_Inotify
However, the compiler complains that wd is an int and not a wd. How do I persuade it that these types are the same?
If the Inotify module is really defined with this signature, that is sealed with an abstract type, there is no way you will be able to break its abstraction to re-define it as an int. I mean that your signature (module type of Foo with wd := int) is clever and describes the interface you want, but the implementation Foo does not satisfy it: if the type-checker allowed that, there would be no type abstraction at all.
You should request the ocaml-inotify maintainer to add marshalling primitives (and possibly fork it locally to do that if you need). Instead of exposing the fact that wd = int, he or she could either publish conversion functions to and from int (so that future implementation changes could still implement these functions), or directly to and from string if you're only interested in marshalling and want to expose less internal details.
There is a solution that exposes more internal details that back-and-forth conversions to an abstract type, which is to use private type abbreviations:
sig
type t = private int
val mk : int -> t
end
This signature exposes that the internal representation is int, and allows to cast from t to int explicitly with (foo :> int) or (foo : t :> int) (you know that this is a no-op at runtime), but does not allow the inverse cast, so you are forced to use the mk function which, I assume, will do some kind of range checking to make sure that this is a valid descriptor.
(Some people will probably suggest that, as a workaround, you break the type safety of the language by using an unsafe cast that should not be named. Do not; this is bad advice.)
I've heard that "first class modules" are coming in OCaml 3.12. What advantages will they offer? What kids of things will be easier? What problem are they trying to solve? A simple example would suffice.
It's only one possible applications, but first class modules make it easy to encode existential types, with basically a module packing an existential type and a value using this type). For example, See Alain Frisch work on Dynamic types (code taken from Alain Frisch work on dyntypes : http://caml.inria.fr/cgi-bin/viewvc.cgi/ocaml/branches/dyntypes/stdlib/dyntypes.ml?view=markup )
module type DYN = sig
type t
val x: t
val t: t ttype
end
type dyn = (module DYN)
let dyn (type s) t x =
let module M = struct
type t = s
let x = x
let t = t
end
in
(module M : DYN)
The idea here is that "ttype" is a concrete representation of that type, an algebraic datatype with Int, Float constructors and so on, and you have here a value, whose type is concealed, but that carries a concrete representation of that type, that you can use for example to get a safer serialization/deserialization.
Maybe a bit late, but the new paper First-class modules: hidden power and tantalizing promises is exactly on topic. It's a set of recipes/pearls around first-class modules, by Oleg Kiselyov (oleg) and Jeremy Yallop (author, for example, of the Deriving project).
I love Haskell style pattern matching.
I have my C++ code as follows:
ObjectPtr ptr;
if(ptr.isType<Foo>()) { // isType returns a bool
Ptr<Foo> p = ptr.convertAs<Foo>(); // convertAs returns a Ptr<Foo>
......
}
if(ptr.isType<Bar>()) {
Ptr<Bar> p = ptr.convertAs<Bar>();
......
}
Now, are there any macros I can do define to simplify this? I have been pondering this for a while, but can't simplify it further.
Thanks!
dynamic_cast would appear to do what you want
struct A {
virtual ~A() {}
};
struct B : struct A { ... };
struct C : struct A { ... };
A * a = new C;
if ( C * c = dynamic_cast<C*>( a ) ) {
c->someCfunc();
}
else if ( B * b = dynamic_cast<B*>( a ) ) {
b->someBfunc();
}
else {
throw "Don't know that type";
}
I love Haskell style pattern matching.
Then write your program in Haskell.
What you're trying to do is a switch over a type. That's a common thing people do if they want to avoid virtual functions. Now, the latter are a cornerstone of what OO in C++ is all about. If you want to avoid them, why do you program in C++?
As for why this is frowned upon: Imagine you have a lot of code like this
if(ptr.isType<Foo>()) ...
if(ptr.isType<Bar>()) ...
smeared all over your code and then someone comes and adds Baz to the possible types that ptr might represent. Now you're hunting through a big code base, trying to find all those places where you switched over a type, and trying to find out which ones you need to add Baz to.
And, as Murphy has it, just when your done, there comes along Foz to be added as a type, too. (Or, thinking again, if Murphy has his way it creeps in before you had a chance too complete adding Baz.)
Attempting to simulate a pattern matching style in C++ using RTTI is a neat idea, but it's bound to have shortcomings, because there are some significant differences between Haskell and Standard ML style type constructors and C++ subclasses. (Note: below, I use Standard ML syntax because I'm more comfortable with it.)
In Haskell and Standard ML, pattern matching can bind nested values to pattern variables for you (e.g. the pattern a::b::c::ds binds the first three elements of the list to a, b, and c, and the rest of the list to ds). In C++, you'll still have to dig around in the actual nested structures, unless you or someone else comes up with far more complicated macros than have been proposed here.
In Haskell and Standard ML, a type constructor datatype declaration like datatype 'a option = NONE | SOME of 'a defines one new type: 'a option. Constructors NONE and SOME are not types, they are values with types 'a option and 'a -> 'a option, respectively. In C++, when you define subclasses like Foo and Bar to simulate type constructors, you get new types.
In Haskell and Standard ML, constructors like SOME are first-class functions that construct values of the datatype to which they belong. For example, map SOME has the type 'a list -> 'a option list. In C++, using subclasses to simulate type constructors, you don't get this ability.
In Haskell and Standard ML, datatypes are closed, so no one can add more type constructors without changing the original declaration, and the compiler can verify at compile time that the pattern match handles all cases. In C++, you have to go well out of your way to restrict who can subclass your base class.
In the end, are you getting enough benefit from simulated pattern matching compared to using C++ polymorphism in a more typical way? Is using macros to make simulated pattern matching slightly more concise (while obfuscating it for everyone else who reads your code) worthwhile?
We co-authored a pattern matching library for C++ that allows you to do pattern matching and type analysis very efficiently. The library, called Mach7, has been released under BSD license and is available on GitHub: https://github.com/solodon4/Mach7. You can find videos, posters, slides, papers as well as the source code there. It currently supports GCC 4.4+, Clang 3.4+ and Visual C++ 2010+. Feel free to ask question's about the library by submitting a GitHub issue against its repository.
I'm assuming that your Ptr template has the concept of a NULL pointer.
ObjectPtr ptr;
if(Ptr<Foo> p = ptr.convertAs<Foo>()) { // convertAs returns a NULL pointer if the conversion can't be done.
......
}
if(Ptr<Bar> p = ptr.convertAs<Bar>()) {
......
}
Though, as others have noted, switching on type is usually a sign you're doing something wrong in C++. You ought to consider using virtual functions instead.
A think this macro does precisely what you want:
#define DYN_IF(dest_type, dest_ptr, src_ptr) \
if((src_ptr).isType<dest_type>()) \
if(int dest_type##dest_ptr = 1) \
for(Ptr<dest_type> dest_ptr = (src_ptr).convertAs<dest_type>(); \
dest_type##dest_ptr; \
dest_type##dest_ptr=0)
Usage:
ObjectPtr ptr;
DYN_IF(Foo, foo_ptr, ptr) {
// foo_ptr is Ptr<Foo>
}
DYN_IF(Bar, bar_ptr, ptr) // Works without braces too for single statement
// bar_ptr is Ptr<Bar>
I wouldn't recommend this sort of stuff in code that is meant to be read by somebody else, but since you mentioned the word "macro"...
Also, I wouldn't pretend this has anything to do with pattern matching in the Haskell/OCaml style. Check Scala if you want a language that has semantics similar to C++ (well, sort of) and true pattern matching.