I'm a bit confused by the fact that (apparently) functor's signature in OCaml can be defined in two (seemingly) completely different ways. E.g. in the .mli file I can write:
module type A = sig
type a
end
module type SigA = sig
type t
end
module Make (MA : SigA) :
A with type a := MA.t
module type Make2 = functor (MA : SigA) -> A with type a := MA.t
As far as I understand, in the example above Make and Make2 are entirely identical signature, yet the syntax looks quite radically different.
Am I missing something? Is there any difference?
So is there a reason for two separate syntactic constructs? Historical reasons? IMO it is a bad practice to have two separate syntactic constructs serving the same purpose.
This is syntactic sugar, similar to that for functions (ie, let f x y = ... is shorthand for let f = fun x -> fun y -> ...). The motivation is presumably that in the long form multiple argument functors become quite hard to read:
module type A = sig end
module type B = sig end
module type C = sig end
module Foo (A:A) (B:B) (C:C) = struct
end
module Foo2 = functor (A:A) -> functor (B:B) -> functor (C:C) -> struct
end
Related
Say I just want a template to "generate" a type, from a generic argument, and use the template's invocation in places where a type is expected:
template p[T] = T
var a: p[int]()
(3, 14) Error: expression 'T' is of type 'type int' and has to be
discarded
lol, really ?
I hope I'm just being a newbie and there is indeed a way (hopefully uncontrived) to do that.
Note that it's the same output, with a non generic attempt:
template p(t: typedesc) = t
var a: p(int)
EDIT: reading this insightful answer, I realized the system might feel more patted on the back if we specified the templates's return type; adding : untyped before = t got the previous snippets to build. any explanation ?
template p[T] = T
var a: p[int]()
This is the same as:
template p[T]: void = T
var a: p[int]()
You're telling the compiler that your template returns nothing, this is why it complains.
So you need to specify the return type...
template p[T]: typedesc = T
var a: p[int]()
Then it works fine. This behaviour extends to procedures and methods in Nim, not specifying a return type means that there is no return value.
Compile-time functions mapping from types to types in Nim are usually implemented with typedesc parameters. Compared to generic params, this has the additional benefit of allowing to provide multiple overloads handling different types in different ways:
type
Foo = object
# handler all integer types:
template myTypeMapping(T: typedesc[SomeInteger]): typedesc = string
# specific handling of the Foo type:
template myTypeMapping(T: typedesc[Foo]): typedesc = seq[string]
# all sequence types are not re-mapped:
template myTypeMapping(T: typedesc[seq]): typedesc = T
Please note that you always need to specify that your template has a typedesc return type.
Can I specialize a type in a signature using types before that type and in the signature? Here is an example:
signature A = sig
type t
type s
end
Can I specialize A by the following?
signature B = A where type s = t list
Both SML/NJ and Mlton complain that t is unbound.
No, that indeed cannot be done directly. The reasons are rather technical, it is not easy to ascribe a well-behaved semantics to such an operation in the general case.
The closest you can get is by introducing another auxiliary type:
signature B =
sig
type t'
include A with type t = t' with type s = t' list
end
This is about type definition in OCaml, I find the following syntax puzzling:
type 'a t
What does it mean in plain English?
Since OP has an experience in C++ language, I think the following explanation might be useful. A type declaration of the form:
type 'a t
is close to the C++
template <typename a> class t;
For example, 'a list is a generic list, and 'a is a type of an element. For concise, we use a single ', instead of template <typename _> construct. In the OCaml parlance, we use term "parametric polymorphism", instead of "generic programming". And instead of a word template, we say a type constructor. The latter has an interesting consequence. Like in C++ a template instantiation creates a new instances of types, in OCaml concertizing a type variable of a polymorphic type creates a new type, e.g., int list, float list (c.f., list<int>, float<list>). So, one can view type constructor 'a list as an unary function on a type level, it accepts a type, and creates a type. It is possible to have nary type constructors, e.g., type ('key, 'value) hashtbl is a binary type constructor, that creates a type for a given key and value pair. Moreover, we can see a non parametric types as a nullary type constructors, so int constructs the type int.
P.S. F# language, a descendant of OCaml, allows to write in both forms: int t and t<int>
P.P.S. To prevent a possible confusion, I would like to state, that although templates and parametric types are trying to solve the same problems, they still have a few differences. Templates are typed after the instantiation, parametric types before. So parametric type 'a t is defined for all 'a. If you want to create a type where a type variable is not universally quantified, you can use another mechanism - functors. They are also very close to templates, but they accept a type plus type requirements, a concept in C++ parlance. The concepts are reified in module types in OCaml, and thus a functor is actually a function on a module level, as it accepts a module and produces a module.
This a parametric type declaration.
A type declaration allows you to declare a new datatype:
type my_type = int * string
let x : my_type = (42,"Sorry for the inconvenience")
Sometimes however, you want a type to be parametric, meaning it takes another type as argument:
type 'a container = 'a * string * 'a
let x : int container = (0, "hello", 1)
let y : string container = ("stack", "over", "flow")
Now in that case, there is no equal after your type declaration. The meaning of that depends whether if it is in a module's structure (like, on top of a .ml file) or in a signature (e.g. in a .mli)
If it is in a structure, it declares a type with no value inside. Which is as useful as an empty set (sometimes it is, but not much). However, if it is in a signature, it means "there exists a parametric definition somewhere, but it is not visible from here".
Suppose there are those two files a.ml and a.mli:
(* a.ml *)
type 'a t = Nil | Cons of 'a * 'a t
let empty = Nil
let add x l = Cons (x,l)
(* and so on... *)
(* a.mli *)
type 'a t
val empty : 'a t
val add : 'a -> 'a t -> 'at
(* and so on... *)
If in the rest of your program you want to manipulate the A.t type, you'll be able to do so only through the empty and add and other defined functions, but not through directly using Nil and Cons.
I'm trying to accomplish the following:
module type S = sig
type 'a t
end
module A = struct
type 'a t = 'a list
end
module B = struct
type ('a,'b) t = ('a * 'b) list
end
module Make (P : S) = struct
type 'a t = 'a P.t
end
module Single = struct
include Make (A)
end
module Tuple = struct
include Make (B)
end
Basically, I want to reuse the make functor, except for in Tuple, force the type to be a tuple. Is this possible?
I think the module type S is messing it up, which is giving me the error: They have different arities. Maybe it is possible to get this working using first class modules?
Thanks!
What are you trying to accomplish? If you forget about functors for a second you will see that your module B cannot satisfy the signature S. For example:
module B1 = (B : S)
Will give you the same error. The problem here is that your type t in your singature S only accepts 1 type variable. You cannot apply this signature to a module with type t with 2 type variables.
So I understand using var in C# makes sense because you have anonymous types that are compiler derived. C++ doesn't seem to have this feature (unless I'm wrong), so what is the point of having an auto keyword?
(It is kinda cool that unlike C#, auto does work for member/global variables, which is cool I guess, but doesn't seem enough to justify its existence).
auto has a lot of uses when it comes down to both generic programming and to save the programmer some typing.
For example, consider this. Would you rather type out:
std::unique_ptr<name::long_type::goes_here> g =
std::make_unique<name::long_type::goes_here>(1,2,3,4)
or:
auto g = std::make_unique<name::long_type::goes_here>(1,2,3,4)
Yes, they're both long but we know the return type and specifying it again is a bit cumbersome to type. This also goes for iterators:
for(auto i = vec.begin(); ...)
vs:
for(std::vector<type>::iterator i = vev.begin(); ...)
Its use in generic programming is also to figure out the return type of a function or if you're doing some generic algorithms where you don't know the type.
For example, consider a very basic example.
template<typename T, typename U>
auto add(T t, U u) -> decltype(t + u) {
return t + u;
}
This allows the compiler to figure out the type of the add operation rather than us trying to figure it out ourselves. Note that in C++14 you can omit the trailing return type. Its uses in generic programming don't stop there either. If we wanted to work with any type of container as a wrapper function for algorithms we could use auto to help us with it. For example:
template<class Cont>
void my_sort(Cont&& cont) {
using std::begin;
auto first = begin(std::forward<Cont>(cont));
// work with the iterators here
}
In the future (C++14), auto can be used to make polymorphic lambdas as well such as:
[](auto a) { return a + 4; }
Which can be useful as well.
There are a number of uses for auto in C++
Anonymous function objects, aka closures, aka lambda instances. auto is the only way to store them. Types can also be generated derived off those types, and types on their backs, ad infinitum.
C++ can have quite complex types, such as the type of a non mutating iterator into an unordered map that uses a custom allocator and hashing function. typedef can mitigate this, but the type of a m.begin() having a particular name is not that informative: foo_iterator it = is as meaningful as auto foo_iterator =, and the auto one does not require boilerplate elsewhere.
Return type deduction uses the auto keyword, which is required to do some template functions work without huge amounts of traits boilerplate. Eliminating boilerplate is a common theme: C++s robust type system means that types can carry lots of information, and encoding it at every use can be counterproductive.
In some ducktype template code, the work to deduce the type of a variable is roughly the same as the work to code the variables value, and nearly identical in structure, some times literally: decltype(long expression) x = long expression;. auto eliminates that duplication.
Finally in C++1y, type deduction lambdas use auto to say that an argument is a deduced one. Sort of a light weight template. Talk to extend this to non lambdas is also in skunkworks.
HEre's a real life example where I could not, not use auto
I was trying to do a switch type statement in C++ where the return type is implementation specific and could not be declared easily. So using an 'auto' is probably the right way to resolve the type look up for the map declaration.
auto foo = boost::bind(&VegaFactory::load_commodity_one_leg,this,conn,_1);
std::map<std::string,decltype(foo)> methods;
methods.insert(std::make_pair("FOO",commodityOneLeg));
auto f = methods.find(bar);
// Call f here
C++ does have "anonymous" types - types you cannot refer to by name because the name is not available to you. This was the case even before C++11 and lambdas. Consider the following code:
class foo {
class bar {
public:
void baz() { }
};
public:
static bar func() { return bar(); }
};
foo::func().baz(); // OK, only the name "bar" is private
??? a = foo::func(); // Umm...
auto b = foo::func(); b.baz(); // Hooray!
Even if not actually declared in a private scope, it is often useful for a library to leave some types unspecified in its API - especially when heavily utilizing expression templates or other template metaprogramming where the type names can be arbitrarily long with all the nested template arguments. Even the standard itself does this - for instance, the result type of std::bind is not defined by the specification.
syntactic sugar
I rather say
auto i = mapping.begin();
over
std::map<int, int>::iterator i = mapping.begin();
It is well worth reading Herb Sutter's article Almost Always Auto for some great examples of why it's worth using auto over explicit types. The main advantages are the reduction in typing, and gives additional safety if the underlying types change. One of my favourite examples though is about how it reduces duplication. If you allocate on the stack then you'd use:
MyClass c(param);
However, if you want to create on the heap you need:
MyClass* c=new MyClass(param);
So you've had to duplicate the MyClass, but the RHS already forces the variable to be a MyClass pointer, so you can just use this instead:
auto c=new MyClass(param);
If you want to declare it as a unique_ptr then previously you would need:
unique_ptr<MyClass> c=make_unique<MyClass>(param);
which can be abbreviated to:
auto c=make_unique<MyClass>(param);
In C++, auto keyword provides a way of type deduction mechanism. For example,
auto i = expressions;
auto keyword tells the compiler to determine the type of variable i from the expression on the right side of the assignment operator.
Therefore if the value of expressions is double, then variable i will be double. Or, if the value of expressions is bool, then variable i will be bool.
so, let's learn type inference first which is basically refers to automatic deduction of the data type of an expression in a programming language.
before C++ 11 all the variables in c++ have to explicitly declare but after the release of c++ 11, the compiler itself deduces the type of the variable at runtime.
we can use it for variables and even in the case of function return types.
but, it's suggested to avoid using auto in function return type.