I am trying to build a hierarchy of module types which depend on each other. In Coq I can write something like this:
Module Type Foo.
Parameter t:Type.
End Foo.
Module Type Bar1 (T:Foo).
Parameter f1: T.t -> T.t.
End Bar1.
Module Type Bar2 (T:Foo).
Parameter f2: T.t -> T.t.
End Bar2.
Module Ex (F:Foo) (B1: Bar1 F) (B2:Bar2 F).
End Ex.
How would I express it in OCaml?
Unfortunately, Ocaml does not directly support parameterised module types. However, you can emulate them by wrapping a parameterised module around them:
module type Foo =
sig
type t
end
module Bar (X : Foo) =
struct
module type T =
sig
val f : X.t -> X.t
end
end
module Ex (F : Foo) (B : Bar(F).T) = ...
A bit more clumsy, but has the same effect.
To elaborate on gsg's answer, if you have a more complex Foo module type, you can use with module instead of with type, and have a module specification in both Bar types, as in the following example:
module type Foo =
sig
type t
end
module type Bar1 = sig
module F: Foo
val f1: F.t -> F.t
end
module type Bar2 = sig
module F: Foo
val f2: F.t -> F.t
end
module Ex (F: Foo) (B1: Bar1 with module F = F) (B2: Bar2 with module F = F) =
struct
let f3 x = B2.f2 (B1.f1 x)
end
module Bar1_impl (F: Foo): Bar1 with module F = F = struct
module F = F
let f1 x = x
end
module Bar2_impl (F: Foo): Bar2 with module F = F = struct
module F = F
let f2 x = x
end
module F: Foo with type t = int = struct type t = int end
module M = Ex(F)(Bar1_impl(F))(Bar2_impl(F))
let x = M.f3 0;;
Module types do not take arguments. However, this particular pattern can be expressed by with type:
module type FOO = sig
type t
end
module type BAR1 = sig
type t
val f1 : t -> t
end
module type BAR2 = sig
type t
val f2 : t -> t
end
module Ex (F:FOO) (B1 : BAR1 with type t = F.t) (B1 : BAR2 with type t = F.t) = struct
end
Related
I have a class that looks like the following:
class Example {
Foo1 f1;
Foo2 f2;
Foo3 f3;
size_t hash;
};
Please note that FooX will be always different classes. I want to add a constructor which assigns the value to each fX element and computes the hash (for cacheing its value).
However I want to be able to omit any number of arguments and assign a default value to the corresponding member of the class. Obviously I could use the defaulting feature of C++:
Example(Foo1 f1 = DEFAULT4F1, Foo2 f2 = DEFAULT4F2, Foo3 f3 = DEFAULT4F3);
However for being able to omit f2, I need to omit f3, which I might want to specify. Then I could write a constructor for each possible order, but the amount of constructors grows with the factorial of elements, so for this case:
Example(Foo1 f1 = DEFAULT4F1, Foo2 f2 = DEFAULT4F2, Foo3 f3 = DEFAULT4F3);
Example(Foo1 f1 = DEFAULT4F1, Foo3 f3 = DEFAULT4F3, Foo2 f2 = DEFAULT4F2);
Example(Foo2 f2 = DEFAULT4F2, Foo1 f1 = DEFAULT4F1, Foo3 f3 = DEFAULT4F3);
Example(Foo2 f2 = DEFAULT4F2, Foo3 f3 = DEFAULT4F3, Foo1 f1 = DEFAULT4F1);
Example(Foo3 f3 = DEFAULT4F3, Foo1 f1 = DEFAULT4F1, Foo2 f2 = DEFAULT4F2);
Example(Foo3 f3 = DEFAULT4F3, Foo2 f2 = DEFAULT4F2, Foo1 f1 = DEFAULT4F1);
I don't want to specify the same constructor that many cases, because in my real case there are more than 3 parameters. I also want to consider forwarding their values (Foo&& arg and std::forward(arg))
Edit:
To sum up: desired constructor would act like this, but being able to omit any of the parameters, and use a default value for them
Example(Foo1&& f1, Foo2&& f2, Foo3&& f3) :
f1(std::forward(f1)),
f2(std::forward(f2)),
f3(std::forward(f3)),
hash(doSomethingForIt())
{
}
This is a workaround, not an initialization in C++ sense.
Because you need in advance all members of your class, you already know them:
class Example {
Foo1 f1;
Foo2 f2;
Foo3 f3;
size_t hash;
//default ctor, initializes all members with defaults defined somewhere
Example() : f1(defaultF1), f2(defaultF2), f3(defaultF3) {}
....
Now we add setters:
Example& setFoo1(Foo1 fo1 = defaultF1)
{
f1 = fo1;
return *this;
}
Example& setFoo2(Foo2 fo2 = defaultF2)
{
f2 = fo2;
return *this;
}
....
}; //class Example
And then the usage:
Example exple;
exple.setFoo2(someF2value).setFoo1(someF1value); //not all setFooX are used
Notice that we can call setFooX() in any order.
Adding to Ripi2 solution I would also add a method which computes the hash and returns an r-value.
class Example
{
Foo1 f1 = DEFAULT4F1;
Foo2 f2 = DEFAULT4F2;
Foo3 f3 = DEFAULT4F3;
size_t hash;
auto doSomethingForIt();
public:
Example() = default;
auto& initFoo1(Foo1&& f) { f1 = std::move(f); return *this; }
auto& initFoo2(Foo2&& f) { f2 = std::move(f); return *this; }
auto& initFoo3(Foo3&& f) { f3 = std::move(f); return *this; }
auto&& finalize()
{
hash = doSomethingForIt();
return std::move(*this);
}
};
This allows for stuff like this to work.
void foo(Example&& e);
foo(Example().initFoo1(f1).initFoo3(f3).initFoo2(f2).finalize());
I propose a solution where the constructor takes a parameter pack of arguments, forms a tuple with it and tries to reorder the tuple to the desired configuration.
#include <tuple>
namespace details {
// General case
// In : the type of input tuple with the out-of-order elements
// Out : a tuple with the desired element order
template<class In, class Out>
struct sort_tuple_impl;
// Implementation with specialization
template<class In, class ... T>
struct sort_tuple_impl<In, std::tuple<T...>>
{
static auto sort(In && params)
{
// Construct another tuple using the output type's elements
// to determine the order of the elements
return std::make_tuple(std::move(std::get<T>(params))...);
}
};
}
// Reorders a tuple
template<class Out, class In>
Out sort_tuple(In && params) {
return details::sort_tuple_impl<In, Out>::sort(std::move(params));
}
// Example types
struct Foo1 {};
struct Foo2 {};
struct Foo3 {};
class Example
{
public:
// A constructor that takes any kind and number of argument
template<class ... T>
explicit Example(T&& ... params) :
// Make a tuple with the arguments and reorder it according to `decltype(f)`
f{sort_tuple<decltype(f)>(std::make_tuple(std::forward<T>(params)...))}
{ }
private:
// The elements you want to be able to initialize
std::tuple<Foo1, Foo2, Foo3> f;
};
Usage example :
int main()
{
Foo1 f1;
Foo2 f2;
Foo3 f3;
Example e1{ f1, f2, f3 };
Example e2{ f2, f1, f3 };
Example e3{ f3, f2, f1 };
Example e4{ f3, f2 ,f1 };
// These fail to compile
// Example e5{ f1 };
// Example e6{ f1, f1, f2};
// Example e7{ f2, f3, f1, f3 };
}
Note that if the user provides the same Foo more than once or fails to provide one this will produce a compiler error because std::get fails if the requested type is not present exactly once. From std::get :
Extracts the element of the tuple t whose type is T. Fails to compile unless the tuple has exactly one element of that type.
It doesn't produce great error messages, but it prevents mistakes.
Edit : This fails the apparent requirement that some elements can be omitted. But I'll leave it here nonetheless as it may be useful. Perhaps another templated function could be used to add the default values to the missing elements.
I gave a second try to François Andrieux's solution and I achieved my requirements. Here is a working example (C++17) of it:
#include <tuple>
#include <iostream>
//Make a unique class for each foo, to prevent implicit casting
template <typename P>
struct Foo{
constexpr Foo(int x) : x(x) {}
int x;
};
using Foo1=Foo<struct Phatom_1>;
using Foo2=Foo<struct Phatom_2>;
using Foo3=Foo<struct Phatom_3>;
//Example class
class Example {
public:
//Default constructor, assingns default falues to all members
Example() :
f1(DEFAULT_F1),
f2(DEFAULT_F2),
f3(DEFAULT_F3)
{
}
template<typename... Types>
Example(Types&&... t) : Example() { //First of all, calls the default constructor
auto paramTpl = std::make_tuple(std::forward<Types>(t)...); //Creates a tuple with the parameters
assign(f1, paramTpl);
assign(f2, paramTpl);
assign(f3, paramTpl);
}
void show() const{
std::cout << "f1=" << f1.x << ", f2=" << f2.x << ", f3=" << f3.x << std::endl;
}
private:
static constexpr auto DEFAULT_F1 = Foo1(1);
static constexpr auto DEFAULT_F2 = Foo2(32);
static constexpr auto DEFAULT_F3 = Foo3(-1);
template<typename Type, typename... Types>
static void assign(Type& el, std::tuple<Types...> tpl){
struct has_type : std::disjunction<std::is_same<Type, Types>...>{};
if constexpr (has_type::value){
el = std::move(std::get<Type>(tpl));
}
}
Foo1 f1;
Foo2 f2;
Foo3 f3;
};
int main(){
Example ex1;
ex1.show();
Example ex2(Foo1(1), Foo3(1), Foo2(1));
ex2.show();
Example ex3(Foo1(2), Foo3(2));
ex3.show();
return 0;
}
Edit: I have simplified a bit
I have this code in Standard ML and I want to know what environments and what bindings are created at definition and at application time, and what's the difference between the both.
fun boo boo =
let
type boo = int
val boo : boo = boo
val boo : { boo : boo } = { boo = boo }
in
# boo boo
end
I searched but could not come with an accurate answer,
Thanks in advance.
I'm still somewhat new to SML, but I think I've got this:
fun boo boo (* 1 *) =
let
type boo (* 2 *) = int
val boo (* 3 *) : boo = boo (* 1 *)
val boo (* 4 *) : { boo (* 5 *) : boo } = { boo = boo } (* 6 *)
in
# boo boo (* 7 *)
end
I labeled each boo to keep track of them. They are:
A free parameter (to the function 'boo') of type int
A type, aliased to type int
A new value of type boo (int) which is bound to the parameter passed to the function
A record value...
with field 'boo' of type boo (int)...
that's assigned the "new" boo value from (3)
projection of field 'boo' from record 'boo' (has type 'boo' (int))
The overall function has type : int -> int
What's the difference between the types of bar1 and bar2?
int foo = 10;
auto bar1 = &foo;
auto *bar2 = &foo;
If both bar1 and bar2 are int*, does it makes sense to write the pointer declarator (*) in the bar2 declaration?
The declarations are exactly equivalent. auto works (almost) the same as template type deduction. Putting the star explicitly makes the code a bit easier to read, and makes the programmer aware that bar2 is a pointer.
Using auto * "documents intention". And auto *p = expr; can be deduced correctly only if expr returns pointer. Example:
int f();
auto q = f(); // OK
auto *p = f(); // error: unable to deduce 'auto*' from 'f()'
There is a big difference when you use const qualifiers:
int i;
// Const pointer to non-const int
const auto ip1 = &i; // int *const
++ip1; // error
*ip1 = 1; // OK
// Non-const pointer to const int
const auto* ip2 = &i; // int const*
++ip2; // OK
*ip2 = 1; // error
In this specific example both bar1 and bar2 are the same. It's a matter of personal preference though I'd say that bar2 is easier to read.
However, this does not hold true for references as seen in this example:
#include <iostream>
using namespace std;
int main() {
int k = 10;
int& foo = k;
auto bar = foo; //value of foo is copied and loses reference qualifier!
bar = 5; //foo / k won't be 5
cout << "bar : " << bar << " foo : " << foo << " k : " << k << endl;
auto& ref = foo;
ref = 5; // foo / k will be 5
cout << "bar : " << bar << " foo : " << foo << " k : " << k;
return 0;
}
As others said, they'll generate the same code. The asterisk is line noise (and makes it harder to switch from raw pointers to smart pointers if, for example, &foo is ever replaced by get_foo()). If you want to be explicit, then by all means, be explicit; but when you're using type inference, just let the compiler do its job. Lack of asterisks does not imply that an object isn't a pointer.
It doesn't matter as far as the interpretation of the C++ code goes; you can write whatever you want. However, there is a question of style and readability: Generally, you should not hide pointer, reference and CV qualifiers, and perhaps even smart pointers, in type aliases, since it makes it harder for the reader to understand that that's what's going on. Type aliases should package the semantically relevant type content, whereas qualifiers and modifiers should remain visible. So prefer the following:
using Foo = long_namespace::Foobrigation<other_namespace::Thing>;
using MyFn = const X * (int, int);
std::unique_ptr<Foo> MakeThatThing(MyFn & fn, int x) // or "MyFn * fn"
{
const auto * p = fn(x, -x);
return p ? p->Create() : nullptr;
}
And don't say:
using PFoo = std::unique_ptr<Foo>; // just spell it out
using MyFn = int(&)(int, int); // unnecessary; & is easy to spell
auto p = fn(x, -x); // Don't know that p is a pointer
Note also that reference qualifiers (unlike pointers) genuinely change the type of the variable that's being declared, so they're not optional:
X & f();
auto a = f(); // copy!
auto & b = f(); // b is the same as the return value of f()
Finally, adding explicit const pointer qualifications can help const-correctness. Consider the next example, in which a container contains pointers-to-mutable, but we only require const access. Just auto * would deduce a pointer to mutable, which we can avoid by saying const explicitly:
std::vector<X*> v = /* ... */;
for (const auto * p : v)
{
observe(p->foo()); // no need for a mutable *p
}
Is there any way to pass a constructor as a function?
type foo =
| Foo of int
| Bar of int
let foo x = Foo x
let bar = fun x -> Bar x
Is there any shorthand for the functions foo and bar? I want to pass a constructor as a function, but it seems unwieldy to write fun x -> Bar x.
camlspotter's answer was close enough, but in your case you want to use Variantslib and add with variants at the end of your type definition:
type foo = Foo of int | Bar of int with variants;;
gives you the following:
type foo = Foo of int | Bar of int
val bar : int -> foo = <fun>
val foo : int -> foo = <fun>
module Variants :
sig
val bar : (int -> foo) Variantslib.Variant.t
val foo : (int -> foo) Variantslib.Variant.t
end
Use Fieldslib: https://github.com/janestreet/fieldslib .
Adding with fields postfix at the type definition like:
type foo = | Foo of int | Bar of int with fields
and compile it with Fieldslib's syntax extension. It automatically generates foo and bar for you.
You can now use ppx_variants_conv, like this:
type 'a t =
| A of 'a
| B of char
| C
| D of int * int
[##deriving variants]
struct Foo {};
struct Bar : Foo {};
Foo &foo = Bar; // without ()
I wonder, Is it a legal notation? And if it is legal, could you give some details? Something like, Why it's legal? Or, What is the origin of such a notation?
EDIT: I cannot compile this code. But I met a code like that and wanted to know whether such a notation is allowed (probably just my compiler doesn't support this notation). I'm having some uncertainty since the following notation is quite legal: Foo *pFoo = new Bar;
It should be a compiler error.
g++: error: expected primary-expression before ';' token
Bar is a name of class and it cannot be assigned to reference / variable. Even with putting () it will not compile, unless you make foo a const Foo&.
You cannot assign an class Name to a reference/object. It is neither syntactically valid nor does it make any sense.
You cannot bind a reference to a temporary(rvalue), So following is illegal too:
Foo &foo = Bar();
You can bind a temporary(rvalue) to an const reference, So following is legal:
const Foo &foo = Bar();
The C++ standard specifically allows the 3.
The code as presented is not legal because Bar is the name of a class, not a variable.
The following, however, is:
struct Foo {}
struct Bar : Foo {}
Bar fooBar;
Foo &foo = fooBar; // without ()
It is legal because Bar is a Foo, so you're just giving a different name to your variable fooBar.
Note however that foo, although an alias for fooBar, will interpret the location as a Foo object.
This means the following:
struct Foo { int x; }; //note semicolons after struct declaration
struct Bar : Foo { int y; };
Bar fooBar;
fooBar.y = 2;
fooBar.x = 3;
Foo &foo = fooBar;
int aux;
aux = foo.x; // aux == 3
aux = foo.y; // compile error
You can't assign a value to a reference. So as already mentioned this is not legal regardless of the parentheses.