Ada derived types and primitive operation - ada

I have the following Ada Code.
type U i s tagged private ;
type W i s new U with private ;
type X i s new W with private ;
procedure m1 (P1 : U; P2 : in out U; P3 : Integer ) ;
procedure m2 (P1 : Float ; P2 : in out U) ;
procedure m2 (P1 : Float ; P2 : Boolean ; P3 : in out W) ;
Not I dont understand what happens excatly with this operations in the derived types.
I think the 3 procedures are primitive operations.
But what is the signature of the procedures in the derived types.
Could it be this
procedure m1 (P1 : W; P2 : in out U; P3 : Integer ) ;
procedure m2 (P1 : Float ; P2 : in out W) ;
procedure m2 (P1 : Float ; P2 : Boolean ; P3 : in out X) ;
Or what would the signature looks like of these 3 procedures in derived types?

When a type T has a primitive subprogram, and you say "type T2 is new T" or "type T2 is new T with ...", a new subprogram is implicitly declared. In the new subprogram, if any parameter type is T or access T, it's replaced by T2 or access T2; and if it's a function whose return type is T or access T, the return type is replaced similarly.
If there were no private types or extensions involved, the new subprogram would be implicitly declared right after the derived type. E.g.:
type U is tagged null record ;
procedure m1 (P1 : U; P2 : in out U; P3 : Integer ) ;
procedure m2 (P1 : Float ; P2 : in out U) ;
type W is new U with null record ;
-- procedure m1 (P1 : W; P2 : in out W; P3 : Integer ) ; --implicitly declared
-- procedure m2 (P1 : Float ; P2 : in out W) ; --implicitly declared
procedure m2 (P1 : Float ; P2 : Boolean ; P3 : in out W);
-- this last is a *new* procedure. It doesn't override the other m2 because
-- it has a new Boolean parameter. Instead, it's an example of *overloading*.
-- So now W has three primitive operations, two that were inherited and one that
-- is brand new.
type X is new W with null record ;
-- procedure m1 (P1 : X; P2 : in out X; P3 : Integer ) ; --implicitly declared
-- procedure m2 (P1 : Float ; P2 : in out X) ; --implicitly declared
-- procedure m2 (P1 : Float ; P2 : Boolean ; P3 : in out X); --implicitly declared
-- All three of W's primitive operations, including the implicitly declared ones,
-- are inherited for X.
The with private doesn't change things much, except that it changes the point where the implicit subprograms are declared. I believe they're declared after the full type definition, which would be in the private part of your package. That means that they aren't visible except in places in your program that can see the private part of your package. (However, they might still be called by a dispatching operation.)
EDIT: For a with private case, the visibility of the inherited subprograms is dictated by RM 7.3.1(7):
For a private_extension_declaration, each inherited subprogram is declared immediately after the private_extension_declaration if the corresponding declaration from the ancestor is visible at that place. Otherwise, the inherited subprogram is not declared for the private extension, though it might be for the full type.
Thus:
package P is
type U is tagged private;
procedure M1 (P1 : U; P2 : in out U; P3 : Integer);
procedure M2 (P1 : Float ; P2 : in out U);
type W is new U with private;
--procedure M1 (P1 : W; P2 : in out W; P3 : Integer); -- implicitly declared
--procedure M2 (P1 : Float ; P2 : in out W); -- implicitly declared
private
type U is ... -- full type definition
type W is new U with ... -- full type definition
end P;
The declarations of M1 and M2 are visible at the point where W is first declared; thus they're inherited at that point. And since that point is in the public part of P, they can be referenced by any package that says with P. But:
package P is
type U is tagged private;
type W is new U with private;
procedure M1 (P1 : U; P2 : in out U; P3 : Integer);
procedure M2 (P1 : Float ; P2 : in out U);
private
type U is ... -- full type definition
type W is new U with ... -- full type definition
--procedure M1 (P1 : W; P2 : in out W; P3 : Integer); -- implicitly declared
--procedure M2 (P1 : Float ; P2 : in out W); -- implicitly declared
end P;
The declarations of M1 and M2 are not visible at the point where W is first declared, since they haven't been seen yet. Thus they're not inherited at that point. But the implicit declarations are inherited later, when the full type is seen. However, those implicit declarations are in the private part of P; therefore, they can be called directly (i.e. not via dispatching) only in parts of the program that can see the private part of P, i.e. P's body and at appropriate places in child packages of P.

Related

Lex && Yacc compiler homework

Hello(my english isn't very well I hope you will understand) , I have a misson to make a compiler, already made the language in the lex and yacc but i'm pretty stuck, our teacher asked from us to build AST tree from the language and print it with pre-order. he gave us example for the text:
function void foo(int x, y, z; real f) {
if (x>y) {
x = x + f;
}
else {
y = x + y + z;
x = f * 2;
z = f;
}
}
the output of the AST tree with pre-order should be:
(CODE
(FUNCTION
foo
(ARGS
(INT x y z)
(REAL f)
)
(TYPE VOID)
(BODY
(IF-ELSE
(> x y)
(BLOCK
(= x
(+ x f)
)
)
(BLOCK
(= y
(+
(+ x y)
z
)
)
(
(= x
(* f 2)
)
(= z f)
)
)
)
)
my question is how should I build the tree? I mean which token will go to left which will go to right so I can get the same output ?
like
makeTree($1,$2,$3);
node,left,right
Help please :)
Stephen Johnson wrote a technical paper to accompany yacc about 42 years ago. Have you read it, and do you understand it?
If yes, a syntax rule like:
expr : expr '+' expr { $$ = node( '+', $1, $3 ); }
node is effectively creating an abstract syntax tree node; and each reduction performed by yacc is the opportunity to build this tree from the bottom up. That is the most important thing to know about yacc; it builds from the bottom up, and you need to construct your data structures likewise.
When the parse is complete ( for whatever version of complete your grammar yields ), the resultant value ($$) is the root of your syntax tree.
followup
You might want to devise a node data structure something like this:
typedef struct Node Node;
typedef struct NodeList NodeList;
struct NodeList {
int Num;
Node *List;
};
struct Node {
int Type;
union {
unsigned u; unsigned long ul; char *s, ... ;
Variable *var;
Node *Expression;
NodeList *List;
} Operands[3];
};
With this you could devise a node of type '+', which defined 2 Operands, corresponding to the Left and Right sides of the '+' opcode.
You could also have a node of type IF, which had three operands:
a conditional Expression
a List of Nodes to perform if the conditional was true
a List of Nodes to perform if the conditional was false.
You could have a node of type Func, which had three operands:
A Type of return value.
A List of arguments.
A List of Nodes comprising the body of the function
I would give more examples but formatting lists with this UI is as much fun as kicking a whale down a beach.

Imperative OCaml data structure with pointers?

Is such a thing possible?
Hi all,
in my class we were told to implement Binary Search Trees in OCaml, using functional and imperative programming.
We are following an ADT and implementation in Pascal, a procedural language where pointers are used.
This is how the data structure looks like:
# Pascal
type
tKey = integer;
tPos = ^tNode;
tNode = record
key : tKey;
left, right : tPos;
end;
tBST = tPosT;
We were also given some basic BST operations. Here is an example of one, if that could help:
# Pascal
procedure add_key(VAR T : tBST; k:tKey);
var new, parent, child : tBST;
begin
createNode(new);
new^.key := k;
new^.left := nil;
new^.right := nil;
if T=nil then
T := new
else begin
parent := nil;
child := T;
while (child <> nil) and (child^.key <> k) do begin
parent := child;
if k < child^.key then
child := child^.left
else
child := child^.right;
end;
if (child = nil) then
if k < parent^.key then
parent^.left := new
else
parent^.right := new;
{ duplicates are ignored }
end;
end;
This is how my functional (if that makes any sense) data structure looks like:
type key =
Key of int;;
type bst =
Empty
| Node of (key * bst * bst);;
However, I am having big trouble using the imperative facet of OCaml. I have to make it look as similar as possible as the Pascal implementation and I don't know about the possibilities of data structures and pointers in OCaml since I've always programmed using recursive and so on. I was thinking in using multiple "let", if's and else's, but I have no idea how to define my data structure.
Would appreciate enormously input on this.
From what I understand you would have a type like this :
type key = int
type t = Empty | Node of t * key * t
But your add function shouldn't look like this :
let rec add x t =
match t with
| Empty ->
Node (Empty, x, Empty)
| Node (l, v, r) ->
let c = compare x v in
if c = 0 then t
else if c < 0 then Node (add x l, v, r)
else Node (l, v, add x r)
Because this is only functional.
Maybe you could change your type to :
type t = Empty | Node of t ref * key * t ref
And try to adapt the add function to this type.

how to find number of occurrences in ML string list?

I am new to ML, here is my attemp to writing a function that receives:
list of strings L
string str
int counter
the function should return the number of occurrences of str in L
Here is my code:
(*
* return number of occurences of str in L
* count should be initialized to zero.
*)
fun aux_num_of_occur(L: string list) (str:string) (count:int) =
if null L then 0
else if str = hd(L) then
aux_num_of_occur tl(L) str (count+1)
else
aux_num_of_occur tl(L) str count
Those are the errors i got:
Error: case object and rules don't agree [tycon mismatch]
rule domain: string list * string * int
object: ('Z list -> 'Z list) * 'Y * 'X
in expression:
(case (arg,arg,arg)
of (L : string list,str : string,count : int) =>
if null L
then 0
else if <exp> = <exp> then <exp> <exp> else <exp> <exp>)
uncaught exception Error
raised at: ../compiler/TopLevel/interact/evalloop.sml:66.19-66.27
../compiler/TopLevel/interact/evalloop.sml:44.55
../compiler/TopLevel/interact/evalloop.sml:296.17-296.20
My Questions:
What is wrong with the syntax?
it is not clear to me what the error message says: what is a
rule and an object in this case?
how can i return a int by recursively calling a function? is it by passing to it a counter as an argument?
This is a classical mistake: tl(L) and tl L are the same thing -- you don't need parentheses for function application in ML-like languages, you just juxtapose the function and the argument(s).
So aux_num_of_occur tl(L) ... is the same thing as aux_num_of_occur tl L ..., i.e. you are trying to apply aux_num_of_occur to the tl function, not to a list of strings. Now, the tl function has type 'a list -> 'a list and that is what you see in the error message (with 'a being 'Z there).
I ought to say that this style with those null, hd, and tl functions is not very idiomatic in SML -- you could use pattern-mathing instead. It is also more convenient to make aux_num_of_occur local to prevent namespace pollution, prevent incorrect usage (you control the initial value of count). Additionally, this gives you the advantage of not passing str all the time when recursing further.
fun num_of_occur ss str =
let
fun loop [] count = count
| loop (s::ss) count =
if s = str
then loop ss (count + 1)
else loop ss count
in
loop ss 0
end
Notice that num_of_occur has a more general type ''a list -> ''a -> int, where ''a means any type with equality comparison. The compiler will generate a warning
Warning: calling polyEqual
which you can either ignore or add some type annotations to num_of_occur. See here for more detail.

Syntax error in creating a list from a tree in SML

I have the following two datatypes:
datatype leaf = Slist of string list | Real of real | nil;
datatype 'a tree = Empty | Node of leaf * 'a tree * 'a tree * 'a tree;
The code below goes through all trees of length one/two and forms a list of the values in the leafs.
fun list12(Empty:'a tree) = nil
| list12(Node(leaf leaf1, 'a tree a1, 'a tree a2, 'a tree a3)) =
if (not(a1 = Empty) andalso not(a2 = Empty) andalso not(a3 = Empty))
then list12(a1)::list12(a2)::list12(a3)
else leaf1::list12(a1)::list12(a2)::list12(a3);
The issue is, I get syntax errors such as
stdIn:94.59-94.66 Error: syntax error: deleting TYVAR ID
stdIn:94.71-94.78 Error: syntax error: deleting TYVAR ID
stdIn:94.83-94.93 Error: syntax error: deleting TYVAR ID ID
stdIn:94.93-94.97 Error: syntax error: deleting RPAREN RPAREN EQUALOP
stdIn:94.98-94.102 Error: syntax error: deleting IF LPAREN
stdIn:94.109-94.116 Error: syntax error: deleting EQUALOP ID
The code in itself isn't complicated. Base case is if it's empty, returns null.
If it doesn't have three nodes, then I add the value of the leaf and recursively call the function on the nodes. If it does, I just recursively call the function on the nodes without adding the leaf.
It works because it it's empty, it ends that search by adding nil to the list, which does nothing.
I've also tried other cases such as using and instead of andalso, as well as other versions of the code such as
| list12(Node(leaf1, Empty, Empty, Empty)) = nil
| list12(Node(leaf2, a1, Empty, Empty)) = leaf2::list12(a1);
| list12(Node(leaf3, b1, b2, Empty)) = leaf3::list12(b1)::list12(b2);
| list12(Node(leaf4, c1, c2, c3)) = list12(c1)::list12(c2)::list12(c3);
but I've found that the above doesn't match all cases.
Any idea on why the syntax errors are appearing?
Side note, why doesn't 1.0 = 2.0 work, but in the summaries it says it works for reals? It only appears to work for integers, and >, <, and so on don't work either.
Syntax errors:
You can't rebind nil. It's a reserved keyword for the built-in list type (i.e. nil = []).
You don't prefix types like 'a tree t1. You either infer the type (by not specifying it and letting the type-checker guess it), or you annotate it with the proper syntax (t1 : 'a tree).
Assuming we get the syntax errors out of the way, rely a little more on inference by removing the type annotations, and add a little formatting, this is how your code might look like:
datatype leaf = Slist of string list | Real of real | Nil;
datatype 'a tree = Empty | Node of leaf * 'a tree * 'a tree * 'a tree;
fun list12 Empty = []
| list12 (Node(leaf1, a1, a2, a3)) =
if (not(a1 = Empty) andalso not(a2 = Empty) andalso not(a3 = Empty))
then list12(a1)::list12(a2)::list12(a3)
else leaf1::list12(a1)::list12(a2)::list12(a3);
Type errors:
! then list12(a1)::list12(a2)::list12(a3)
! ^^^^^^^^^^
! Type clash: expression of type
! 'a list
! cannot have type
! 'a
! because of circularity
Looking at the type of op:: : 'a * 'a list -> 'a list, and your use of list12(a1)::list12(a2), the type-checker must find some 'a such that 'a = 'a list. That is like finding an x such that x = x + 1. Clearly, whatever list12 returns, you have something of the same kind on each side.
A dirty and inefficient trick is to use the # operator (append) instead. A neater way is to fold across the tree in such a way that the function with which you fold has access to the entire node (like in this StackOverflow post from the other day):
fun para f e Empty = e
| para f e0 (t0 as Node (x, t1, t2, t3)) =
let val e1 = f (e0, t0)
val e2 = para f e1 t1
val e3 = para f e2 t2
val e4 = para f e3 t3
in e4 end
fun isNode (Node _) = true
| isNode Empty = false
fun list12 t =
let fun extract (xs, Empty) = xs
| extract (xs, Node (x, t1, t2, t3)) =
if isNode t1 andalso isNode t2 andalso isNode t3
then x::xs
else xs
in para extract [] t end
You could collapse this into just one function - this way is separating the traversal logic into para and the accumulation logic into list12's helper function.
Comparing reals
Why doesn't 1.0 = 2.0 work, but in the summaries it says it works for reals?
I don't know what summaries you refer to. This question is answered here: Why can't I compare reals in Standard ML? (this answer was originally placed here, but was moved there, since it's a separate question.)

Functors in OCaml

I am having a bit of a problem with a functor (and it's resultant type). Below, I have a Set functor that uses an Ordered type. I actually used the set.ml that comes with OCaml for some guidance, but I seem to be doing everything ahem right. I created an Ordered module with integers and applied it to the Set functor to get the last module on this code sample, IntSet.
The next line fails, when I try to insert an integer. I get the following type error:
Error: This expression has type int but is here used with type
SetInt.elt = Set(OrdInt).elt
Don't get me wrong, the type system is correct here. The top level reports that the type of the SetInt.elt is Set(OrdInt).elt, but when I do the same operations to set up a Set using the one provided by OCaml the 'same' line is, SetInt.elt = OrderedInt.t. Seems like I should be getting SetInt.elt = Ordered.t.
This is so simple, I'm probably just missing some stupid detail! argh!
Please Note: I have simplified the member/insert functions here since this issue has to do with types.
module type Ordered =
sig
type t
val lt : t -> t -> bool
val eq : t -> t -> bool
val leq : t -> t -> bool
end
module type S =
sig
type elt
type t
exception Already_Exists
val empty : t
val insert : elt -> t -> t
val member : elt -> t -> bool
end
module Set (Elt:Ordered) : S =
struct
type elt = Elt.t
type t = Leaf | Node of t * elt * t
exception Already_Exists
let empty = Leaf
let insert e t = t
let member e t = false
end
module OrdInt : Ordered =
struct
type t = int
let lt a b = a < b
let eq a b = a = b
let leq a b = a <= b
end
module IntSet = Set (OrdInt)
(* line that fails *)
let one_elm = IntSet.insert 1 IntSet.empty
You need to change these two lines
module Set (Elt:Ordered) : S =
module OrdInt : Ordered =
to
module Set (Elt:Ordered) : S with type elt = Elt.t =
module OrdInt : Ordered with type t = int =
Without these, the modules will not have signatures that expose the types elt and t as int.
[Edit]:
The set.ml doesn't have the 'with' bit, because there's a sml.mli, which declares the signature for the functor and it does have the 'with'. Also, OrdInt doesn't need 'with' if you don't explicitly specify a signature for it, like this:
module OrdInt =
You can also construct the set by defining the module in place:
module IntSet = Set (struct
type t = int
let lt a b = a < b
let eq a b = a = b
let leq a b = a <= b
end)

Resources