What's meaning of this ocaml code segment? - ocaml

I can't understand this ocaml code from ocaml compiler source code:
File: d:\src\ocaml-4.07.0\driver\pparse.ml
50: type 'a ast_kind =
51: | Structure : Parsetree.structure ast_kind
52: | Signature : Parsetree.signature ast_kind
there define a type ast_kind,define the type parameter 'a,but not use it?
I know the common use of type define like this:
type a=
|A of int
|B of int
so the
Structure : Parsetree.structure ast_kind
means what?the type of Structure is Parsetree.structure? or ast_kind?
I read the offical doc:
http://caml.inria.fr/pub/docs/manual-ocaml-312/manual016.html##manual.kwd53
it tell me only in the defination of record can use the ":"
type-representation ::= = constr-decl { | constr-decl }
∣ = { field-decl { ; field-decl } }
field-decl ::= field-name : poly-typexpr
∣ mutable field-name : poly-typexpr
so what's the meaning of this code segment?Thanks!

Starting from :
50: type 'a ast_kind =
51: | Structure : Parsetree.structure ast_kind
52: | Signature : Parsetree.signature ast_kind
This is read as follows :
line 50 : we define a parametrized type ast_kind whose parameter is 'a. The parameter is defined later in the lines 51 & 52.
On line 51 : the 'a parameter type is Parsetree.structure
And similarly for line 52.
Now, more generally, ast_kind is a GADT type (generalized algebraic datatypes), see GADT-manual and another example : Mads-hartmann.
Note that GADT has been introduced in Ocaml 4.00 - so the link you quote regarding documentation is outdated for that particular feature as it refers to Ocaml 3.12. You are currently inspecting the source code of Ocaml 4.07.

Related

How do I compare values for equality by Type Constructor?

Background
I'm a relative newcomer to Reason, and have been pleasantly suprised by how easy it is to compare variants that take parameters:
type t = Header | Int(int) | String(string) | Ints(list(int)) | Strings(list(string)) | Footer;
Comparing different variants is nice and predictable:
/* not equal */
Header == Footer
Int(1) == Footer
Int(1) == Int(2)
/* equal */
Int(1) == Int(1)
This even works for complex types:
/* equal */
Strings(["Hello", "World"]) == Strings(["Hello", "World"])
/* not equal */
Strings(["Hello", "World"]) == Strings(["a", "b"])
Question
Is it possible to compare the Type Constructor only, either through an existing built-in operator/function I've not been able to find, or some other language construct?
let a = String("a");
let b = String("b");
/* not equal */
a == b
/* for sake of argument, I want to consider all `String(_)` equal, but how? */
It is possible by inspecting the internal representation of the values, but I wouldn't recommend doing so as it's rather fragile and I'm not sure what guarantees are made across compiler versions and various back-ends for internals such as these. Instead I'd suggest either writing hand-built functions, or using some ppx to generate the same kind of code you'd write by hand.
But that's no fun, so all that being said, this should do what you want, using the scarcely documented Obj module:
let equal_tag = (a: 'a, b: 'a) => {
let a = Obj.repr(a);
let b = Obj.repr(b);
switch (Obj.is_block(a), Obj.is_block(b)) {
| (true, true) => Obj.tag(a) == Obj.tag(b)
| (false, false) => a == b
| _ => false
};
};
where
equal_tag(Header, Footer) == false;
equal_tag(Header, Int(1)) == false;
equal_tag(String("a"), String("b")) == true;
equal_tag(Int(0), Int(0)) == true;
To understand how this function works you need to understand how OCaml represents values internally. This is described in the section on Representation of OCaml data types in the OCaml manual's chapter on Interfacing C with OCaml (and already here we see indications that this might not hold for the various JavaScript back-ends, for example, although I believe it does for now at least. I've tested this with BuckleScript/rescript, and js_of_ocaml tends to follow internals closer.)
Specifically, this section says the following about the representation of variants:
type t =
| A (* First constant constructor -> integer "Val_int(0)" *)
| B of string (* First non-constant constructor -> block with tag 0 *)
| C (* Second constant constructor -> integer "Val_int(1)" *)
| D of bool (* Second non-constant constructor -> block with tag 1 *)
| E of t * t (* Third non-constant constructor -> block with tag 2 *)
That is, constructors without a payload are represented directly as integers, while those with payloads are represented as "block"s with tags. Also note that block and non-block tags are independent, so we can't first extract some "universal" tag value from the values that we then compare. Instead we have to check whether they're both blocks or not, and then compare their tags.
Finally, note that while this function will accept values of any type, it is written only with variants in mind. Comparing values of other types is likely to yield unexpected results. That's another good reason to not use this.

Use variant from dependency

I have this code:
cnf.mli
type literal
type clause
type cnf
type l_diff
val l_compare: literal -> literal -> l_diff
cnf.ml (partial)
type l_diff = Same | Negation | Different
checker.ml (partial)
open Cnf
type solution = (literal * bool) list
let rec solve_literal sol l =
match sol with
| [] -> false
| (hl, b)::rs when (l_compare l hl) = Same -> b
| (hl, b)::rs when (l_compare l hl) = Negation -> not b
| _::rs -> solve_literal rs l
This works in utop using:
#mod_use "cnf.ml";;
#use "checker.ml";;
But if I try to compile checker I get the following error:
compile command:
ocamlbuild cnf.cma
ocamlbuild checker.cma
error:
+ /home/user/.opam/4.05.0/bin/ocamlc.opt -c -o checker.cmo checker.ml
File "checker.ml", line 7, characters 42-46:
Error: Unbound constructor Same
Hint: Did you mean Some?
Command exited with code 2.
Compilation unsuccessful after building 6 targets (2 cached) in 00:00:00.
Am I using a variant the wrong way, or using the compiler incorrectly?
Neither, you are using abstract types in signature in the wrong way. When you write in cnf.mli
type l_diff
this declares the type l_diff as an abstract type, in other words a black box whose content is hidden.
Contrarily, when using #mod_use "cnf.ml" the toplevel infers a signature by itself and makes all type declarations transparent:
type literal = …
type clause = …
type cnf = …
type l_diff = Same | Negation | Different
val l_compare: literal -> literal -> l_diff
(If you want to see the full inferred signature ocamlbuild cnf.inferred.mli should work.)
With this signature, the constructor of l_diff are visible and it becomes possible to construct directly or pattern match values of type l_diff.
More generally, your signature cnf.mli is far too restrictive:
With this signature, the only way to create a value of type l_diff is to call l_compare. However it would be then impossible to observe the content of the type. Similarly, with the interface cnf.mli that you provided, it is impossible to create a value of type literal.

Code compiling on OCaml 3.11 but not on 4.01

I have the following code that compiles fine in OCaml 3.11:
module type T =
sig
type test
val create : int -> test (* line 44 *)
...
end
...
type test = (string, clause list) Hashtbl.t
let create = Hashtbl.create (* line 332 *)
But when I try to compile it with OCaml 4.01, it gives me the following error:
Error: Signature mismatch:
...
Values do not match:
val create : ?random:bool -> int -> ('a, 'b) Hashtbl.t
is not included in
val create : int -> theory
File "test1.ml", line 44, characters 2-28: Expected declaration
File "test1.ml", line 332, characters 6-12: Actual declaration
make[1]: *** [test1.cmo] Error 2
make: *** [byte-code] Error 2
What changed in OCaml 4 so that it now can't compile it? I am sure it has a very easy explanation but I am still learning the inner workings of OCaml types.
The type of the function has changed --of course! Since the addition is of an optional argument, it will affect anyone who is aliasing the function (which will carry over the type, inc. the optional parameter). You will have to eta-expand the arguments of the create function to fix this issue, as in...
let create i = Hashtbl.create i
In fact it should be noted that you only need to eta-expand one argument to remove the optional arguments from the inferred type signature as in...
let create ?random1 ?random2 x y z = Hashtbl.create (x+y+z);;
(* ?random1:'a -> ?random2:'b -> int -> int -> int -> ('c, 'd) Hashtbl.t *)
let create7 = create 7;;
(* create7 : int -> int -> ('_a, '_b) Hashtbl.t *)

Is it possible to generate a parser for a language using the Reverse Polish notation with bison/yacc?

Is it possible to generate a parser for a scripting language that uses the Reverse Polish notation (and a Postscript-like syntax) using bison/yacc?
The parser should be able to parse code similar to the following one:
/fib
{
dup dup 1 eq exch 0 eq or not
{
dup 1 sub fib
exch 2 sub fib
add
} if
} def
Given the short description above and the notes on Wikipedia:
http://en.wikipedia.org/wiki/Stack-oriented_programming_language#PostScript_stacks
A simple bison grammer for the above could be:
%token ADD
%token DUP
%token DEF
%token EQ
%token EXCH
%token IF
%token NOT
%token OR
%token SUB
%token NUMBER
%token IDENTIFIER
%%
program : action_list_opt
action_list_opt : action_list
| /* No Action */
action_list : action
| action_list action
action : param_list_opt operator
param_list_opt : param_list
| /* No Parameters */
param_list : param
| param_list param
param : literal
| name
| action_block
operator : ADD
| DUP
| DEF
| EQ
| EXCH
| IF
| NOT
| OR
| SUB
literal : NUMBER
name : '/' IDENTIFIER
action_block : '{' program '}'
%%
Yes. Assuming you mean one that also uses postscript notation, it means you'd define your expressions something like:
expression: operand operand operator
Rather than the more common infix notation:
expression: operand operator operand
but that hardly qualifies as a big deal. If you mean something else by "Postcript-like", you'll probably have to clarify before a better answer can be given.
Edit: Allowing an arbitrary number of operands and operators is also pretty easy:
operand_list:
| operand_list operand
;
operator_list:
| operator_list operator
;
expression: operand_list operator_list
;
As it stands, this doesn't attempt to enforce the proper number of operators being present for any particular operand -- you'd have to add those checks separately. In a typical case, a postscript notation is executed on a stack machine, so most such checks become simple stack checks.
I should add that although you certainly can write such parsers in something like yacc, languages using postscript notation generally require such minimal parsing that you frequently feed them directly to some sort of virtual machine interpreter that executes them quite directly, with minimal parsing (mostly, the parsing comes down to throwing an error if you attempt to use a name that hasn't been defined).

Ocaml: Error - this expression has type x but is used with type x

This is my error:
Error: This expression has type nfa but is here used with type nfa
What could possibly be happening to cause this? I'm using emacs tuareg, and loading evaluating files one by one. Sometimes this happens, and other times it doesn't.
There's a good description of this in the ocaml tutorial. What's happened is you have shadowed a type definition with a new definition:
type nfa = int
let f (x: nfa) = x
type nfa = int
let g (x: nfa) = x
Restarting the top-level will clear out the old definitions.
Update:
Since OCaml 4.01.0 (released Sept. 2013) the general problem is the same, but the error message adds a number to the type definition, to make evident the types are internally different.
Full example from the old OCaml FAQ in the toplevel:
type counter = Counter of int;; (* define a type *)
type counter = Counter of int
# let x = Counter 1;; (* use the new type *)
val x : counter = Counter 1
type counter = Counter of int;; (* redefine the type, use it *)
type counter = Counter of int
# let incr_counter c = match c with Counter x -> Counter (x + 1);;
val incr_counter : counter -> counter = <fun>
# incr_counter x;; (* now mix old and new defs *)
Error: This expression has type counter/1029
but an expression was expected of type counter/1032
#