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
Related
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
assuming we have the next function object:
class foo{
private:
int counter;
public:
foo(int counter): counter(counter){}
foo& operator=(const foo& ){...}
bool operator() (int variable){....}
}
int main(){
foo f(4);
foo x(5);
x = f(4);
return 0;
}
how does the compiler knows how to respond to:
x = f(5)?
I've been searching for a while on the web and in Stack and haven't found exact answer, if its a repost , tell me and i'll delete the question.
It depends on whether the "(5)" is being used to construct an object or called on an already-existing object:
foo f(5); // calls the constructor
f(5); // calls operator()
I added a simple method called eval to explain it:
class foo {
private:
int counter;
public:
foo(int counter): counter(counter) {}
bool operator() (int variable) {
return variable < counter;
}
bool eval(int variable) {
return variable < counter;
}
};
foo is a class not a method.
an instance of foo can be used like a method.
calling foo(5) will create an instance of foo where the counter = 5.
eval is a member function of foo. (for now this will do the same as the () operator)
You can call eval like this:
foo f = foo(5); // create an instance of `foo`
f.eval(3); // returns true -> 3 < 5
f.eval(0); // returns false -> 6 < 5
You can also use the () operator:
foo f = foo(5); // create an instance of `foo`
f(3); // returns true -> 3 < 5
f(0); // returns false -> 6 < 5
NOTE:
You can also write (but don't do it):
foo f = foo(5); // create an instance of `foo`
f.operator()(3); // returns true -> 3 < 5
f.operator()(0); // returns false -> 6 < 5
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.