I am trying to rewrite java code using only concrete syntax (no AST). Next code works:
CompilationUnit rewritePackage(CompilationUnit input) =
visit(input) {
case (PackageDeclaration) `package <{Identifier "."}+ N>;` =>
(PackageDeclaration) `package <{Identifier "."}+ N>.<Identifier s>;`
when s:= [Identifier] "othertest"
};
Now I want to create {Identifier "."}+ in order to insert it into result of rewrite:
CompilationUnit rewritePackage(CompilationUnit input) =
visit(input) {
case (PackageDeclaration) `package <{Identifier "."}+ N>;` =>
(PackageDeclaration) `package <{Identifier "."}+ NUpdated>;`
when NUpdated := [{Identifier "."}+] "a1.b2"
};
and it does not work. I also tried with lists, no success.
Is it possible somehow to create {Identifier "."}+? Or to convert list[Identifier] to it? How can I achieve mapper( , toUpperCase) on {Identifier "."}+ ?
Is there a way to insert some str variable directly to concrete syntax?
In docs I found how {Identifier "."}+ can be transformed to list. But is there any other direct operations on {Identifier "."}+.
Would be nice to have pattern match in a form:
[ *Identifier firstIds, (Identifier)someName, *Identifier otherIds ]
First some short answers to make things clearer:
The implementation of the [NonTerminal] "string" notation is unfinished. Currently it only supports named non-terminals, such as [Identifiers] xxx. This is a known TODO and its already tracked as an issue.
There is no short syntax yet for creating concrete lists. You have to construct them manually using loops or recursion. For now the advice is to:
introduce a non-terminal name for the list in the grammar, and
write a helper function to construct the list
To create an {Identifier "."}+ list, use concrete syntax patterns like so:
syntax Identifiers = {Identifier "."}+ elems;
private {Identifier "."}+ insert(Identifier first, {Identifier "."}+ tail)
= (Identifiers) `<Identifier first>.<{Identifier "."} tail>`.elems;
The append function first wraps the list in the Identifiers non-terminal to be able to use the (..).. notation, and then projects out the new nested list using the .elems field. The syntax trees you produce like this are statically correct. Unlike using the [..].. notation which calls a parser dynamically, this (..).. notation calls the parser statically and composes correct trees at run-time.
Or perhaps you want to concatenate two identifier lists:
{Identifier "."}+ append({Identifier "."}+ prefix, {Identifier "."}+ postfix)
= (Identifiers) `<{Identifier "."} prefix>.<{Identifier "."}+ postfix>`.elems;
Sometimes you want to concatenate possibly empty sub-lists, this is allowed and the . separator will be removed automatically:
{Identifier "."}+ append({Identifier "."}+ prefix, {Identifier "."}* postfix)
= (Identifiers) `<{Identifier "."} prefix>.<{Identifier "."}* postfix>`.elems;
So to turn a list[Identifier] into a {Identifier "."} you might write this:
{Identifier "."}+ identifiers([Identifier head]) = (Identifiers) `<Identifier head>`.elems;
{Identifier "."}+ identifiers([Identifier head, Identifier sec, *Identifier tail])
= append(insert(head, identifiers([sec, *tail]);
Agreed that this is kind of clumsy and we should maybe prioritize the much easier concrete list syntax templates syntax. We're also open to suggestions for improvement.
Related
According the F# specification for operator overloading
<# #> op_Quotation
<## ##> op_QuotationUntyped
is given as with many other operators. Unless I'm missing something I don't believe that I can use this for custom types, so why is it listed?
I think you are right that there is no way of actually using those as custom operators. I suspect those are treated as operators in case this was useful, at some point in the future of the language, for some clever new feature.
The documentation really merely explains how the names of the operators get encoded. For non-special operator names, F# encodes those in a systematic way. For the ones listed in the page, it has a special nicer name. Consider this type:
type X() =
static member (<^><>) (a:int,b:int) = a + b
static member (<# #>) (a:int,b:int) = a + b
If you look at the names of those members:
[ for m in typeof<X>.GetMembers() -> m.Name ]
You see that the first operator got compiled as op_LessHatGreaterLessGreater, while the second one as op_Quotation. So this is where the name memntioned in the table comes in - it is probably good this is documented somewhere, but I think you're right, that this is not particularly useful!
I have found this superb JSON library for F#, it's inspired by Elm's Json.Decode and it defines a basic Decoder type like this:
type Decoder<'T> = string -> obj -> Result<'T, DecoderError> (here)
There are functions like Decode.map and I wish I could make it F#+ compatible, so I could use it like:
let customerId = Decode.string |>> CustomerId
(see |>> infix version of generic map)
As far as I can see, to make a 3rd party library use F#+ concepts like Functors, one needs to extend the 3rd party type with static member Map, but the Decoder<'T> is just an abbreviation.
Is there any solution? Did anyone try?
P.S.
My solution so far is a custom binding:
let (<!>) = Decode.map
let customerId: Decoder<CustomerId> = CustomerId <!> Decode.string
let submitId: Decoder<SubmitId> = SubmitId <!> Decode.string
let currency: Decoder<Currency> = Currency <!> Decode.string
// etc…
The problem is that you don't control the code. If you had control over it, a solution would be:
Implement Decoder as a concrete type as opposed to a type alias. A type alias can't have additional members, because it's not really another type. Library authors should use single case discriminated unions, now that you can make them structs with nearly zero overhead.
Add the member Map with the required signature.
Alternatively, if extensions members becomes visible for trait constraints in a future F# version, you would be able just extend the type with the Map function, maybe with some undesired effects as it's a type alias for a function with 2 arguments.
So, I think the best you can do is what you already showed.
As a side note, you might be interested in having a look at Fleece which also provides decoders, but it also goes one step further and provides you codecs which goes in both directions (and you can map and <*> over it).
I love the simplicity of types like
type Code = Code of string
But I would like to put some restrictions on string (in this case - do not allow empty of spaces-only strings). Something like
type nonemptystring = ???
type Code = Code of nonemptystring
How do I define this type in F# idiomatic way? I know I can make it a class with constructor or a restricted module with factory function, but is there an easy way?
A string is essentially a sequence of char values (in Haskell, BTW, String is a type alias for [Char]). A more general question, then, would be if it's possible to statically declare a list as having a given size.
Such a language feature is know as Dependent Types, and F# doesn't have it. The short answer, therefore, is that this is not possible to do in a declarative fashion.
The easiest, and probably also most idiomatic, way, then, would be to define Code as a single-case Discriminated Union:
type Code = Code of string
In the module that defines Code, you'd also define a function that clients can use to create Code values:
let tryCreateCode candidate =
if System.String.IsNullOrWhiteSpace candidate
then None
else Some (Code candidate)
This function contains the run-time logic that prevents clients from creating empty Code values:
> tryCreateCode "foo";;
val it : Code option = Some (Code "foo")
> tryCreateCode "";;
val it : Code option = None
> tryCreateCode " ";;
val it : Code option = None
What prevents a client from creating an invalid Code value, then? For example, wouldn't a client be able to circumvent the tryCreateCode function and simply write Code ""?
This is where signature files come in. You create a signature file (.fsi), and in that declare types and functions like this:
type Code
val tryCreateCode : string -> Code option
Here, the Code type is declared, but its 'constructor' isn't. This means that you can't directly create values of this types. This, for example, doesn't compile:
Code ""
The error given is:
error FS0039: The value, constructor, namespace or type 'Code' is not defined
The only way to create a Code value is to use the tryCreateCode function.
As given here, you can no longer access the underlying string value of Code, unless you also provide a function for that:
let toString (Code x) = x
and declare it in the same .fsi file as above:
val toString : Code -> string
That may look like a lot of work, but is really only six lines of code, and three lines of type declaration (in the .fsi file).
Unfortunately there isn't convenient syntax for declaring a restricted subset of types but I would leverage active patterns to do this. As you rightly say, you can make a type and check it's validity when you construct it:
/// String type which can't be null or whitespace
type FullString (string) =
let string =
match (System.String.IsNullOrWhiteSpace string) with
|true -> invalidArg "string" "string cannot be null or whitespace"
|false -> string
member this.String = string
Now, constructing this type naively may throw runtime exceptions and we don't want that! So let's use active patterns:
let (|FullStr|WhitespaceStr|NullStr|) (str : string) =
match str with
|null -> NullStr
|str when System.String.IsNullOrWhiteSpace str -> WhitespaceStr
|str -> FullStr(FullString(str))
Now we have something that we can use with pattern matching syntax to build our FullStrings. This function is safe at runtime because we only create a FullString if we're in the valid case.
You can use it like this:
let printString str =
match str with
|NullStr -> printfn "The string is null"
|WhitespaceStr -> printfn "The string is whitespace"
|FullStr fstr -> printfn "The string is %s" (fstr.String)
I am trying to do a top-down visit of an Algebraic Data Type. When I find a node of a certain type, I would also like to bind to the nodes of that particular node, for e.g.
data Script=script(list[Stmt] body | ...
data Stmt =exprstmt(Expr expr)| ...
data Expr =assign(Expr left, Expr right) | var(str name)| scalar(Type aType)|... ;
Script myScript=someScript(srcFile);
top-down visit(myScript)
{
case (Expr e:assign(left,right), left:=var(_), right :=scalar(_) )
{
str varName=left.name;
Type myType=right.aType;
}
}
So what I'm trying to do in the case statement is to search for a specific kind of node: i.e. of type assign(var(),scalar()) by doing a couple of pattern matches. My intention is to bind the variables left and right to var() and scalar() respectively at the same time that I find the particular kind of node. I hoped to NOT do a nested 'case' statement in order to retrieve information about the sub-nodes. Maybe that is possible, but I'm not sure.
You can just nest the patterns, like so:
top-down visit(myScript) {
case e:assign(l:var(varName),r:scalar(aType)) :
// do something useful
println("<varName> : <aType>");
}
I believe left and right might be reserved keywords so this is why I used l and r instead.
Or simpler (because you don't need names for the nested patterns:
top-down visit(myScript) {
case assign(var(varName),scalar(aType)) :
// do something useful
println("<varName> : <aType>");
}
I'm getting stymied by the way "dot notation" works with objects and records when trying to program in a point-free functional style (which I think is a great, concise way to use a functional language that curries by default).
Is there an operator or function I'm missing that lets me do something like:
(.) object method instead of object.method?
(From what I was reading about the new ? operator, I think it works like this. Except it requires definition and gets into the whole dynamic binding thing, which I don't think I need.)
In other words, can I apply a method to its object as an argument like I would apply a normal function to its argument?
Short answer: no.
Longer answer: you can of course create let-bound functions in a module that call a method on a given type... For example in the code
let l = [1;2;3]
let h1 = l.Head
let h2 = List.hd l
there is a sense in which "List.hd" is the version of what you want for ".Head on a list". Or locally, you can always do e.g.
let AnotherWay = (fun (l:list<_>) -> l.Head)
let h3 = AnotherWay l
But there is nothing general, since there is no good way to 'name' an arbitrary instance method on a given type; 'AnotherWay' shows a way to "make a function out of the 'Head' property on a 'list<_>' object", but you need such boilerplate for every instance method you want to treat as a first-class function value.
I have suggested creating a language construct to generalize this:
With regards to language design
suggestions, what if
SomeType..Foo optArgs // note *two* dots
meant
fun (x : SomeType) -> x.Foo optArgs
?
In which case you could write
list<_>..Head
as a way to 'functionize' this instance property, but if we ever do anything in that arena in F#, it would be post-VS2010.
If I understand your question correctly, the answer is: no you can't. Dot (.) is not an operator in F#, it is built into the language, so can't be used as function.