As part of a course in my university, I have to build a simple DSL using XText. Currently I am having a problem with static type checking. Lets suppose I have two types of variables in my language, circle and triangle.
Both have their own set of parameters like e.g. radius or height/width. However, both do have common parameters like x/y (position). Therefore, I have to following xtext code:
//CircleAttributesInit makes sure, that the correct parameter are used
CircleDecl:
'circle' name = ID '(' (attributes += CircleAttributesInit)* ')'
;
//triangleAttributesInit makes sure, that the correct parameter are used
TriangleDecl:
'triangle' name = ID '(' (attributes += triangleAttributesInit)* ')'
;
CircleAccess returns INT:
circle = [CircleDecl] '.' ('radius')
;
TriangleAccess returns INT:
triangle = [TriangleDecl] '.' ('height' | 'width')
;
ObjectDecl:
name = (CircleDecl | TriangleDecl)
;
ObjectAccess returns INT:
objName = [ObjectDecl] '.' ('x' | 'y')
;
In my simple program, I can now type something like:
triangle tri (...)
circle c (...)
tri.height = ...
c.radius = ...
but access on the super type variables like :
tri.x = ....
c.y =....
does not work. The error message is: "Couldn't resolve reference to ObjectDecl 'tri/c'."
This kind of makes sense to me, since I never told xtext, that each TriangleDecl/CircleDecl object is also a ObjectDecl. But how do I do this?
it looks like you mix up some metalevels. as long as the attributes exist only on syntax level you have to take care yourself
Related
I was trying alternative ways to write the below proof from this question and Isabelle 2020's Rings.thy. (In particular, I added the note div_mult_mod_eq[of a b] line to test the use of the note command:
lemma mod_div_decomp:
fixes a b
obtains q r where "q = a div b" and "r = a mod b"
and "a = q * b + r"
proof -
from div_mult_mod_eq have "a = a div b * b + a mod b" by simp
note div_mult_mod_eq[of a b]
moreover have "a div b = a div b" ..
moreover have "a mod b = a mod b" ..
note that ultimately show thesis by blast
qed
However, if I write it in a separate .thy file, there is an error about type unification at the note line:
Type unification failed: Variable 'a::{plus,times} not of sort semiring_modulo
Failed to meet type constraint:
Term: a :: 'a
Type: ??'a
The problem goes way if I enclose the whole proof in a pair of type class class begin ... end as follows:
theory "test"
imports Main
HOL.Rings
begin
...
class semiring_modulo = comm_semiring_1_cancel + divide + modulo +
assumes div_mult_mod_eq: "a div b * b + a mod b = a"
begin
(* ... inserted proof here *)
end
...
end
My questions are:
Is this the correct way to prove a theorem about a type class? i.e. to write a separate class definition in a different file?
Is it always necessary to duplicate type class definitions as I did?
If not, what is the proper way to prove a theorem about a type class outside of its original place of definition?
There are two ways to prove things in type classes (basically sort = typeclass for Isabelle/HOL):
Proving in the context of the typeclass
context semiring_modulo
begin
...
end
(slightly less clean) Add the sort constraints to the type:
lemma mod_div_decomp:
fixes a b :: "'a :: {semiring_modulo}"
obtains q r where "q = a div b" and "r = a mod b"
and "a = q * b + r"
semiring_modulo subsumes plus and times, but you can also type {semiring_modulo,plus,times} to really have all of them.
The documentation of classes contains more examples.
The issue you ran into is related to how Isabelle implements polymorphism. Sorts represent a subset of all types, and we characterize them by a set of intersected classes. By attaching a sort to a variable, we restrict the space of terms with which that variable can be instantiated with. One way of looking at this is an assumption that the variable belongs to a certain sort. In your case, type inference (+) (*) div mod apparently gives you {plus,times}, which is insufficient for div_mult_mod_eq. To restrict the variable further you can make an explicit type annotation as Mathias explained.
Note that the simp in the line above should run into the same problem.
I am trying to make a vector library with a hidden Vector type but i get the following error:
Unexpected start of structured construct in definition. Expected '='
or other token
I am trying to learn how modules work, and i took this example from a book where I copied exactly as given and still got this error.
Screenshot with code
The given errors are :
`error FS0039: The value or constructor 'make' is not defined.
error FS0010: Unexpected start of structured construct in definition. Expected '=' or other token.
`
F# has 2 sintaxis for module
Top level module without the =
module Vector
type Vector = V of float * float
let (~-.) (V(x, y)) = V(-x, -y)
Which acts as a namespace and module declaration in one.
Components can be indented at the same level as the module Vector, like in
the book example. F# interactive doesn't recognize this form, so you need to use the other form:
Sub modules with the =:
module Vector =
type Vector = V of float * float
let (~-.) (V(x, y)) = V(-x, -y)
Which require its components to be indented further inside.
Here is the documentation:
https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/modules
You need to remove the first type Vector then just indent the module:
module Vector =
type Vector = V of float*float
let (~-.) (V(x,y)) = V(-x, -y)
let make (x, y) = V(x, y)
let a = make(1.0, 2.0) // V (1.0, 2.0)
I am wondering whether there is a possibility for antlr parsing rules to create rules that match Strings containing the endtoken. I'll illustrate this by using an sql-example:
CREATE FUNCTION UFHDBTBL.FH_LIEF_SPERR_SK(pidpack INTEGER)
...
BEGIN ATOMIC
DECLARE sperrsk VARCHAR(2000) DEFAULT '';--
DECLARE erster INTEGER DEFAULT 0;--
FOR satz AS
SELECT sk_name1
FROM UFHDBTBL.FH01TM21 psk, UFHDBTBL.FH01T61 lsk
WHERE psk.id_pack = pidpack
DO
IF erster = 1 THEN
SET sperrsk = sperrsk || '<br>';--
END IF ;--
SET sperrsk = sperrsk || LTRIM(RTRIM(satz.sk_name1));--
IF erster = 0 THEN
SET erster = 1;--
END IF ;--
END FOR;--
RETURN sperrsk;--
END;
Currently, I tried the following parsing-rules to match all the stuff between "BEGIN ATOMIC" and "END;":
'BEGIN' ~('END') 'END'
'BEGIN' .+? 'END'
'BEGIN' (~('END')|~(';'))* 'END'
(The last ; is contained in the "create function rule" so don't worry about it)
Notice, that the block contains the tokens "END" and ";". Since I don't want to create a new token "END;" (which causes many other rules to fail), I hope there is some antlr guy around who's able to help me!
You could use something like the following to match everything until END; without creating a new single token to represent it.
'BEGIN'
( ~'END'
| 'END' ~';'
)*
'END' ';'
While writing some code yesterday, I ran into two odd problems, which neither me nor my functional programming oriented friend could figure out. We have looked at it for quite some time, and researched it on the net, but we were not able to find any answers anywhere, so here goes:
The issue is that in this code:
First weird problem:
let outer1 (bs : byte array) =
let rec inner (bs : byte array) (bacc : byte array) (i : int) =
match i with
| bs.Length -> bacc // <--- Error: bs is not recognized. Why?
| _ -> bacc.[i] <- bs.[i]
inner bs bacc (i + 1)
inner bs (Array.zeroCreate bs.Length) 0
The problem here is: FS0039: The namespace or module 'bs' is not defined.
How can this be? bs is in the function signature after all. Moreover, defining a new value with let bsLength = bs.Length works right before the match. But by doing so I see a new oddity:
let outer2 (bs : byte array) =
let rec inner (bs : byte array) (bacc : byte array) (i : int) =
let bsLength = bs.Length
match i with
| bsLength -> bacc
| _ -> bacc.[i] <- bs.[i] // <--- Warning: Rule never matched. Why?
inner bs bacc (i + 1)
inner bs (Array.zeroCreate bs.Length) 0
Here the problem is a warning that says: warning FS0026: This rule will never be matched.
I don't get that at all. i and the length of the array has no relation to each other. If I write an integer (for instance 10) instead of bsLength, the warning disappears.
Both your problems stem from the expectation that pattern matching allows using values and literals interchangeably. No, it does not. Pattern Matching (F#) topic on MSDN gives a good overview of supported pattern types and precedence rules of their application. The major principle simplifying a lengthy description there is: you cannot match a value unless this value is a literal, or identifier (a case value of a discriminated union, an exception label, or an active pattern case).
In your first problem point compiler treats bs.Length not as a property Length of array bs as you expect, but as a literal or identifier Length from non-existing module or namespace bs; as John Palmer pointed in his answer you may achieve the expected behavior by using variable pattern with a guard statement. A sample of legitimate use of the pattern matching expression resembling yours would be:
module bs =
[<Literal>]
let Length = 100
//.............................
let v = 100;
let s = match v with
| bs.Length -> "matched"
| _ -> "not matched";;
val s : string = "matched"
The second problem point is treated by compiler as variable pattern, and bsLength is assigned a value of i instead of values being compared, as you expected; second matching rule does not have chances to kick in.
The match statement doesn't work like you think it does - the correct syntax is
match i with
| t when t = bs.Length
In the second case, you actually create a new variable called bsLength which hides the definition of the earlier bsLength and matches all integers, so you get the rule never matched warning.
I am trying to design an AST for a decision logic table. One of the things I would like to be able to do with the discriminated union that represents my AST is transform parts of it for different reasons. For clarity I will give you an example
Decision Logic Table
# VAR = 10 ;Y;
The above can be read as there is one rule and the condition VAR = 10 enters this rule with a Y entry.
Abstract Syntax Tree Definition (simplified for this example)
type expression =
| Value of double
| Variable of string
| Equality of expression * expression
type entry =
| Entry of string
type entries =
| Entries of entry list
type conditional =
| ConditionEntries of expression * entries
type condition
| Condition of expression * string
type rule =
| Rule of condition list
Rendered (before transform)
ConditionEntries(
Equality(
Variable("VAR"),
Value(10.0)),
Entries(["Y"]))
Rendered (after transform)
Rule(
Condition(
Equality(
Variable("VAR"),
Value(10.0)
),
Entry("Y")
)
)
Now what I would like to do is transform the above tree to expand the rules that are represented in the entries. My thinking was I could use a recursive function and pattern-matching to do this but I am having a little trouble wrapping my head around it right now.
I guess in essence what I am trying to do is whenever I see a ConditionEntries node, I want to emit a new Rule for every string in the Entries list where the Condition is combined with the Entry. Does that make any sense?
Thanks in advance for any advice.
p.s. I haven't quite tried to compile the above example, so please forgive any grammatical errors.
Hmm, based on your AST, which is awfully broken up, here is a tranform function which produces the output from input you desire (though it's not recursive, just uses List.map with some pattern matching. expression is your only recursive type but it doesn't look like you want to process it recursively?):
let ex1 =
ConditionEntries(
Equality(
Variable("VAR"),
Value(10.0)),
Entries([Entry("Y")]))
let ex2 =
ConditionEntries(
Equality(
Variable("VAR"),
Value(10.0)),
Entries([Entry("X");Entry("Y");Entry("Z")]))
let transform ces =
match ces with
| ConditionEntries(x, Entries(entries)) ->
entries
|> List.map (function Entry(entry) -> Condition(x, entry))
//FSI output:
> transform ex1;;
val it : condition list =
[Condition (Equality (Variable "VAR",Value 10.0),"Y")]
> transform ex2;;
val it : condition list =
[Condition (Equality (Variable "VAR",Value 10.0),"X");
Condition (Equality (Variable "VAR",Value 10.0),"Y");
Condition (Equality (Variable "VAR",Value 10.0),"Z")]