Explicit var type in OCaml - ocaml

If I have a type t
type t = C of string;;
And want to explicitly define a type of the variable to be type t:
let b : t = C 'MyString';;
Can I do it in OCaml?

You don't need to be explicit
let b = C mystring
let b = C "a string litteral"
You can be explicit, but it dy oesn't add anything
let b : t = C foo
The preferred way in general is to use type inference without annotating types, and only be explicit about the type of the identifiers exported to other modules, through the associated .mli interface file.
In this case, a type annotation doesn't add anything as the C constructor already is a kind of tag/annotation : C something is necessarily of type t, there is no possible confusion.

You can, using either that syntax, or the alternate one:
let b = (C foo : t)
Adding type constraints in this fashion does not usually serve any purpose in a well-formed program, because the type inference algorithm can handle all of it correctly on its own. There are a few exceptions (mostly involving the object-oriented side), but they're quite rare.
Such annotations are mostly useful when a type error happens and you need to understand why a certain expression has a certain type when you expected it to have another, because you can type-annotate intermediate values to have the type error move up through your source code.
Note that there's another way of annotating types, which is to define a signature for your modules. In your example above, your module body would contain:
let b = C foo
And your module signature would contain :
val b : t
This is especially useful when you need assumptions inside the module to be invisible to other modules. For instance, when using polymorphic variants:
let user_type = `Admin
Here, you only want to handle the administrator account, but you need the rest of your code to be aware that other account types exist, so you would write in the signature that:
val user_type : [`Admin|`Member|`Guest]
This type is technically correct, but could not have been guessed by the type inference algorithm.

Related

Is it really necessary to write the type definition in both the sig and struct part of a module to make it non abstract?

This is a minor issue but annoying.
module Example : sig
type t = int
end = struct
type t = int
end
I get that I have to include the type in the signature, otherwise it's abstract and hidden... that's fine. But is it necessary to write it out in the struct as well? In this case it's pretty trivial, but if I have a lot of large records or other complex types it gets annoying. I could just not include a sig at all, but I often want some publicly visible types but also some hidden properties.
As far as I can tell, nothing will compile if the struct doesn't exactly copy the type definition from the signature.. is there any way to tell it "Just copy what's in the signature", rather than actually having to copy and paste? If not... why not?
Well yes and no.
You can just write:
module Example =
struct
type t = int
end
This code will work just as you'd expect.
However, and to our common sadness, there is no way to "import" your type definition from the signature. Copy-paste is your friend.
Side-note: As #G4143 mentioned in the comments, you can type ocamlc -i myfile.ml to print a complete type signature of your module, that can be useful too.

Prevent SML type from becoming eqtype without hiding constructors

In datatype declarations, Standard ML will produce an equality type if all of the type arguments to all of the variants are themselves eqtypes.
I've seen comments in a few places lamenting the inability of users to provide their own definition of equality and construct their own eqtypes and unexpected consequences of the SML rules (e.g. bare refs and arrays are eqtypes, but datatype Foo = Foo of (real ref) is not an eqtype).
Source: http://mlton.org/PolymorphicEquality
one might expect to be able to compare two values of type real t, because pointer comparison on a ref cell would suffice. Unfortunately, the type system can only express that a user-defined datatype admits equality or not.
I'm wondering whether it is possible to block eqtyping. Say, for instance, I am implementing a set as a binary tree (with an unnecessary variant) and I want to pledge away the ability to structurally compare sets with each other.
datatype 'a set = EmptySet | SetLeaf of 'a | SetNode of 'a * 'a set * 'a set;
Say I don't want people to be able to distinguish SetLeaf(5) and SetNode(5, EmptySet, EmptySet) with = since it's an abstraction-breaking operation.
I tried a simple example with datatype on = On | Off just to see if I could demote the type to a non-eqtype using signatures.
(* attempt to hide the "eq"-ness of eqtype *)
signature S = sig
type on
val foo : on
end
(* opaque transcription to kill eqtypeness *)
structure X :> S = struct
datatype on = On | Off
let foo = On
end
It seems that transparent ascription fails to prevent X.on from becoming an eqtype, but opaque ascription does prevent it. However, these solutions are not ideal because they introduce a new module and hide the data constructors. Is there a way to prevent a custom type or type constructor from becoming an eqtype or admitting equality without hiding its data constructors or introducing new modules?
Short answer is no. When a type's definition is visible, it's eq-ness is whatever the definition implies. The only way to prevent it being eq then is to tweak the definition such that it isn't, for example, by adding a dummy constructor with a real parameter.
Btw, small correction: your type foo should be an equality type. If your SML implementation disagrees then it has a bug. A different case is real bar when datatype 'a bar = Bar of 'a ref (which is what the MLton manual discusses). The reason that the first one works but the second doesn't is that ref is magic in SML: it has a form of polymorphic eq-ness that user types cannot have.

Include submodule of a functor application

I have this functor that has a submodule:
module type PT = sig
type t
val to_string: t -> string
end
module A(P:PT) = struct
module SubA = struct
type t = T of P.t | F of float
end
end
And I want to extend it using an include. This even works:
module Aplus(P:PT) = struct
include A(P)
let print x = print_string (P.to_string x)
end
But for some reason it doesn't work for submodules.
module Aplus(P:PT) = struct
include A(P)
let print x = print_string (P.to_string x)
module SubAplus = struct
include A(P).SubA (* Syntax error here *)
end
end
It fails with a Syntax error on the submodule reference after a functor application. That is quite strange, since it looks like the language grammar allows that. Is there any specific reason for disallowing that?
OCaml syntax in a module path, allows you only to reference to module types, type constructors and types:
For referring to type constructors, module types, or class types, the
prefix can also contain simple functor applications (as in the
syntactic class extended-module-path above) in case the defining
module is the result of a functor application.
In other words to access to real values, you need to instantiate your module, and then you can reference any values. See Drup's answer for a complete example.
Easy enough:
module M = F(A)
include M.SubModule
There are various possible reason, but one simple is: if the module resulting of the functor application F(A) is not named, you will not be able to refer to it. If the function introduces type equalities in the context, it will lead to issues (and in error messages in particular ...)
Note that it's possible to do it with types, module types and class types. F(M).M.t is a perfectly valid type expression.
To finish, in your case, you don't need to reapply the functor, you already did earlier, so include SubA will be enough.

OCaml polymorphism example other than template function?

I am trying to understand for myself, which form of polymorhism does OCaml language have.
I was provided by an example
let id x = x
Isn't this example equivalent to C++ template function
template<class A> A id(A x) { return x; }
If so then my question is: are there any other forms of polymorphism in OCaml? This notion is called "generic algorithm" in the world of imperative languages, not "polymorphism".
There are basically three language features that are sometimes called polymorphism:
Parametric polymorphism (i.e. "generics")
Subtype polymorphism, this is the ability of a subtype of a type to offer a more specific version of an operation than the supertype, i.e. the ability to override methods (and the ability of the the runtime system to call the correct implementation of a method based on the runtime type of an object). In OO languages this is often simply referred to as "polymorphism".
So-called ad-hoc polymorphism, i.e. the ability to overload functions/methods.
As you already discovered, OCaml has parametric polymorphism. It also has subtype polymorphism. It does not have ad-hoc polymorphism.
Since in your title you've asked for examples, here's an example of subtype polymorphism in OCaml:
class c = object
method m x = x+1
end
class d = object
inherit c
method m x = x+2
end
let main =
let o:c = new d in
print_int (o#m 2)
This will print 4.
This kind of polymorphism is called generic programming but the theoretical concept behind it is called parametric polymorphism.
The two examples you provided indeed show parametric polymorphism but OCaml is supported by a strong inferring type checker instead that the one provided by C++ (which is a solution more pragmatic and with more caveats) so the real difference is that in C++ the code is duplicated for every type you use it in your code while in OCaml it is resolved by type checker by verifying that a substitution of implicit type variables through unification does exist.
Everything can be polymorphic in OCaml just because nothing is usually annotated with types so in practice if something can be used as an argument to any function then it is implicitly allowed.
You can for example have type variables to define polymorphic methods:
let swap ((x : 'a), (y : 'b)) : 'b * 'a = (y, x)
so that this will work whatever type 'a o 'b is.
Another powerful polymorphic feature of OCaml are functors (which are not the common C++ functors) but are modules parametrized by other modules. The concept sounds scarier that it is but they indeed represent an higher order of polymorphic behavior for OCaml code.

Explain ML type inference to a C++ programmer

How does ML perform the type inference in the following function definition:
let add a b = a + b
Is it like C++ templates where no type-checking is performed until the point of template instantiation after which if the type supports the necessary operations, the function works or else a compilation error is thrown ?
i.e. for example, the following function template
template <typename NumType>
NumType add(NumType a, NumType b) {
return a + b;
}
will work for
add<int>(23, 11);
but won't work for
add<ostream>(cout, fout);
Is what I am guessing is correct or ML type inference works differently?
PS: Sorry for my poor English; it's not my native language.
I suggest you have a look at this article: What is Hindley-Milner? (and why is it cool)
Here is the simplest example they use to explain type inference (it's not ML, but the idea is the same):
def foo(s: String) = s.length
// note: no explicit types
def bar(x, y) = foo(x) + y
Just looking at the definition of bar, we can easily see that its type must be (String, Int)=>Int. That's type inference in a nutshell. Read the whole article for more information and examples.
I'm not a C++ expert, but I think templates are something else that is closer to genericity/parametricity, which is something different.
I think trying to relate ML type inference to almost anything in C++ is more likely to lead to confusion than understanding. C++ just doesn't have anything that's much like type inference at all.
The only part of C++ that doesn't making typing explicit is templates, but (for the most part) they support generic programming. A C++ function template like you've given might apply equally to an unbounded set of types -- just for example, the code you have uses NumType as the template parameter, but would work with strings. A single program could instantiate your add to add two strings in one place, and two numbers in another place.
ML type inference isn't for generic programming. In C or C++, you explicitly define the type of a parameter, and then the compiler checks that everything you try to do with that parameter is allowed by that type. ML reverses that: it looks at the things you do with the parameter, and figures out what the type has to be for you to be able to do those things. If you've tried to do things that contradict each other, it'll tell you there is no type that can satisfy the constraints.
This would be pretty close to impossible in C or C++, largely because of all the implicit type conversions that are allowed. Just for example, if I have something like a + b in ML, it can immediately conclude that a and b must be ints -- but in C or C++, they could be almost any combination of integer or pointer or floating point types (with the constraint that they can't both be pointers) or used defined types that overload operator+ (e.g., std::string). In ML, finding types can be exponential in the worst case, but is almost always pretty fast. In C++, I'd estimate it being exponential much more often, and in a lot of cases would probably be under-constrained, so a given function could have any of a number of different signatures.
ML uses Hindley-Milner type inference. In this simple case all it has to do is look at the body of the function and see that it uses + with the arguments and returns that. Thus it can infer that the arguments must be the type of arguments that + accepts (i.e. ints) and the function returns the type that + returns (also int). Thus the inferred type of add is int -> int -> int.
Note that in SML (but not CAML) + is also defined for other types than int, but it will still infer int when there are multiple possibilities (i.e. the add function you defined can not be used to add two floats).
F# and ML are somewhat similar with regards to type inference, so you might find
Overview of type inference in F#
helpful.