I have a rascal syntax containing various type of change operators :
syntax ChangeOperator
= entityOperator: EntityOperation op
| attributeOperator : AttributesOperations op
| relationOperator: RelationOperations op
| databaseOperator: DatabaseOperations op
;
And I try to execute different action depending on the type of the change operator (EntityOperation, AttributeOperation, ...). I loop through my change operator like this :
for ( ChangeOperator op <- operators){
for(EvoQuery evo <- evoQueries){
transform(evo, op);
}
};
And I defined various transform methods :
EvoQuery transform(EvoQuery q, EntityOperation op){ ... }
EvoQuery transform(EvoQuery q, AttributesOperations op) {...}
default EvoQuery transform(EvoQuery q, _) = q;
Unfortunately, the only version of 'transform' that is called is the default one.
How can I adapt the loop or the signature in order to make them match depending on the kind of the alternative ?
It seems that there is a type mismatch between the pattern in the formal parameter and the actual argument in the loop (which is now a ChangeOperator, not some Operation). Changing the call to the transform function to transform(evo, op.op), will likely give the intended result.
Furthermore, the two for loops can be combined into a single one as follows:
for (ChangeOperator op <- operators, EvoQuery evo <- evoQueries) {
transform(evo, op);
};
The first two alternatives of transform fail because the type of the parameter op in the body of the for-loop is neither an EntityOperation nor an AttributusOperations: it's ChangeOperator. In other words: concrete syntax types are not sub-types even if the rule that defines them is only a "chain rule".
To match one level deep in a tree, you can use either concrete matching or abstract matching, like so:
In concrete syntax, we parse a ChangeOperator snippet with a single hole in it, and use that pattern to match against the parse tree that you give as second parameter:
EvoQuery transform(EvoQuery q, (ChangeOperator) `<EntityOperation op>`) { ... }
EvoQuery transform(EvoQuery q, (ChangeOperator) `<AttributesOperations op>`) {...}
In abstract notation, we can use the name label of each alternative syntax rule of ChangeOperator to match the alternative instead. So in this example we use abstract notation to match against concrete parse trees:
EvoQuery transform(EvoQuery q, entityOperator(EntityOperation op)) { ... }
EvoQuery transform(EvoQuery q, attributeOperator(AttributesOperations op)) {...}
PS: there is a bug in this definition:
syntax ChangeOperator
= entityOperator: EntityOperation op
| attributeOperator : AttributesOperations op
| relationOperator: RelationOperations op
| databaseOperator: DatabaseOperations op
;
each op label should be different because they yield different types:
syntax ChangeOperator
= entityOperator: EntityOperation eop
| attributeOperator : AttributesOperations aop
| relationOperator: RelationOperations rop
| databaseOperator: DatabaseOperations dop
;
Related
I'm trying to use Menhir's incremental parsing API and introspection APIs in a generated parser. I want to, say, determine the semantic value associated with a particular LR(1) stack entry; i.e. a token that's been previously consumed by the parser.
Given an abstract parsing checkpoint, encapsulated in Menhir's type 'a env, I can extract a “stack element” from the LR automaton; it looks like this:
type element =
| Element: 'a lr1state * 'a * position * position -> element
The type element describes one entry in the stack of the LR(1) automaton. In a stack element of the form Element (s, v, startp, endp), s is a (non-initial) state and v is a semantic value. The value v is associated with the incoming symbol A of the state s. In other words, the value v was pushed onto the stack just before the state s was entered. Thus, for some type 'a, the state s has type 'a lr1state and the value v has type 'a ...
In order to do anything useful with the value v, one must gain information about the type 'a, by inspection of the state s. So far, the type 'a lr1state is abstract, so there is no way of inspecting s. The inspection API (§9.3) offers further tools for this purpose.
Okay, cool! So I go and dive into the inspection API:
The type 'a terminal is a generalized algebraic data type (GADT). A value of type 'a terminal represents a terminal symbol (without a semantic value). The index 'a is the type of the semantic values associated with this symbol ...
type _ terminal =
| T_A : unit terminal
| T_B : int terminal
The type 'a nonterminal is also a GADT. A value of type 'a nonterminal represents a nonterminal symbol (without a semantic value). The index 'a is the type of the semantic values associated with this symbol ...
type _ nonterminal =
| N_main : thing nonterminal
Piecing these together, I get something like the following (where "command" is one of my grammar's nonterminals, and thus N_command is a string nonterminal):
let current_command (env : 'a env) =
let rec f i =
match Interpreter.get i env with
| None -> None
| Some Interpreter.Element (lr1state, v, _startp, _endp) ->
match Interpreter.incoming_symbol lr1state with
| Interpreter.N Interpreter.N_command -> Some v
| _ -> f (i + 1)
in
f 0
Unfortunately, this is puking up very confusing type-errors for me:
File "src/incremental.ml", line 110, characters 52-53:
Error: This expression has type string but an expression was expected of type
string
This instance of string is ambiguous:
it would escape the scope of its equation
This is a bit above my level! I'm pretty sure I understand why I can't do what I tried to do above; but I don't understand what my alternatives are. In fact, the Menhir manual specifically mentions this complexity:
This function can be used to gain access to the semantic value v in a stack element Element (s, v, _, _). Indeed, by case analysis on the symbol incoming_symbol s, one gains information about the type 'a, hence one obtains the ability to do something useful with the value v.
Okay, but that's what I thought I did, above: case-analysis by match'ing on incoming_symbol s, pulling out the case where v is of a single, specific type: string.
tl;dr: how do I extract the string payload from this GADT, and do something useful with it?
If your error sounds like
This instance of string is ambiguous:
it would escape the scope of its equation
it means that the type checker is not really sure if outside of the pattern matching branch the type of v should be a string, or another type that is equal to string but only inside the branch. You just need to add a type annotation when leaving the branch to remove this ambiguity:
| Interpreter.(N N_command) -> Some (v:string)
I suppose I do not fully understand the concept of keywords in Rascal in relation to pattern matching (as the following notations are in fact supported by Rascal). Say I have defined a datatype Exp and a function demoFun1 (assuming that in this case z binds to y):
data Exp = a(int x, int y = 5) | b(int x);
Exp demoFun1(a(x, y = z)) = b(z);
And then I execute: demoFun1(a(2, y = 3)), Rascal returns:
|stdin:///|(25,4,<1,25>,<1,29>): The called signature: b(value),
does not match the declared signature: Exp = b(int)
(Which is already quite a strange error message, since I cannot say something like int y = ... in the arguments, assuming that this would be the correct syntax). However, if I define another function where instead I assume that the value after the "="-sign is the default value (as is the case in the ADT-definition), and I can simply use the value of y instead:
Exp demoFun2(a(x, y = 3)) = b(y);
And I execute demoFun2(a(1, y=2))
Then Rascal returns:
|stdin:///|(0,19,<1,0>,<1,19>): The called signature: demoFun2(Exp),
does not match the declared signature: Exp demoFun2(Exp); (abstract pattern);
Is pattern matching on keywords not (yet fully) supported, or am I doing something wrong?
Thank you!
First of all, yes, the error message needs improvement. Actually there is another unreported error which comes first. All introduced variables in patterns in function headers in Rascal must have types. The interpreter does not complain about this, and hence downstream there is an unexpected result.
This fixes your problem, annotating the fresh variable z with int:
Exp demoFun2(a(x, y = int z)) = b(z);
Having said that, the following code triggers a similar issue, indicating that indeed something is amiss in the type inferencing during pattern matching keyword parameters:
rascal>if (a(x, y = q) := xxx) q;
value: 3
The type of q should be nothing but int given the declaration of y.
Thanks for the report, see https://github.com/cwi-swat/rascal/issues/843
I'm wondering if it's possible to use an anonymous variable here to match the type of a node. For example from http://tutor.rascal-mpl.org/Rascal/Expressions/Values/Location/Location.html#/Rascal/Patterns/Abstract/TypedLabelled/TypedLabelled.html):
case Exp e:_(_,_): println("And I found an Exp <e>");
which would match both the add and subtract Exp nodes. I've been experimenting a bit with something like this but haven't had any success.
(Apologies, I posted this in the comments section on the website before I saw the link to ask.rascal)
Building on Davy's answer, you could do something like this if you only want to match constructors that take two parameters:
rascal>data D = d1(int n) | d2(int n, int m) | d3(int n,int m);
ok
rascal>D d: str s(_,_) := d2(3,4);
bool: true
rascal>D d: str s(_,_) := d1(3);
bool: false
Normally in a match of this form you would use the constructor name. Using str s instead forces this to be a generic node match, where nodes are given as the node name (a string, here the constructor name) and the node parameters (here, we assume two parameters). This may be useful if there are a large number of these types of matches, but otherwise I would recommend just writing them individually.
case Exp e: println(e); should do it
How can I write a no-op statement in F#?
Specifically, how can I improve the second clause of the following match statement:
match list with
| [] -> printfn "Empty!"
| _ -> ignore 0
Use unit for empty side effect:
match list with
| [] -> printfn "Empty!"
| _ -> ()
The answer from Stringer is, of course, correct. I thought it may be useful to clarify how this works, because "()" insn't really an empty statement or empty side effect...
In F#, every valid piece of code is an expression. Constructs like let and match consist of some keywords, patterns and several sub-expressions. The F# grammar for let and match looks like this:
<expr> ::= let <pattern> = <expr>
<expr>
::= match <expr> with
| <pat> -> <expr>
This means that the body of let or the body of clause of match must be some expression. It can be some function call such as ignore 0 or it can be some value - in your case it must be some expression of type unit, because printfn ".." is also of type unit.
The unit type is a type that has only one value, which is written as () (and it also means empty tuple with no elements). This is, indeed, somewhat similar to void in C# with the exception that void doesn't have any values.
BTW: The following code may look like a sequence of statements, but it is also an expression:
printf "Hello "
printf "world"
The F# compiler implicitly adds ; between the two lines and ; is a sequencing operator, which has the following structure: <expr>; <expr>. It requires that the first expression returns unit and returns the result of the second expression.
This is a bit surprising when you're coming from C# background, but it makes the langauge surprisingly elegant and consise. It doesn't limit you in any way - you can for example write:
if (a < 10 && (printfn "demo"; true)) then // ...
(This example isn't really useful - just a demonstration of the flexibility)
F# keyword 'Some' - what does it mean?
Some is not a keyword. There is an option type however, which is a discriminated union containing two things:
Some which holds a value of some type.
None which represents lack of value.
It's defined as:
type 'a option =
| None
| Some of 'a
It acts kind of like a nullable type, where you want to have an object which can hold a value of some type or have no value at all.
let stringRepresentationOfSomeObject (x : 'a option) =
match x with
| None -> "NONE!"
| Some(t) -> t.ToString()
Can check out Discriminated Unions in F# for more info on DUs in general and the option type (Some, None) in particular. As a previous answer says, Some is just a union-case of the option<'a> type, which is a particularly common/useful example of an algebraic data type.
Some is used to specify an option type, or in other words, a type that may or may not exist.
F# is different from most languages in that control flow is mostly done through pattern matching as opposed to traditional if/else logic.
In traditional if/else logic, you may see something like this:
if (isNull(x)) {
do ...
} else { //x exists
do ...
}
With pattern matching logic, matching we need a similar way to execute certain code if a value is null, or in F# syntax, None
Thus we would have the same code as
match x with
| None -> do ...
| Some x -> do ...