I want to write a parser in F# and because of reasons I have to use Antlr. This means I have to define a Visitor class for every AST node I want to parse. Now I have the problem that there are some rules with cyclic dependencies like:
boolExpr : boolTerm 'or' boolTerm ;
boolTerm : boolAtom 'and' boolAtom ;
boolAtom : '(' boolExpr ')'
| ... ;
which means I need 3 visitor classes that have the same cyclic dependency and I want to have each of them in their own file
//BoolExprVisitor.fs
let boolExprVisitor = { new BaseVisitor<AST.BoolExpr>() with
override __.VisitBoolExpr(context: BoolExprContext) =
context.boolTerm() |> mapAccept boolTermVisitor |> AST.BoolExpr
}
//BoolTermVisitor.fs
let boolTermVisitor = { new BaseVisitor<AST.BoolTerm>() with
override __.VisitBoolTerm(context: BoolTermContext) =
context.boolAtom() |> mapAccept boolAtomVisitor |> AST.BoolTerm
}
//BoolAtomVisitor.fs
let boolAtomVisitor = { new BaseVisitor<AST.BoolAtom>() with
override __.VisitBoolAtom(context: BoolAtomContext) =
context.boolExpr() |> accept boolExprVisitor |> AST.BoolAtom
}
But F# doesn't like these cyclic dependencies. How can I make F# accept them or restructure my visitors to not need cyclid dependencies?
For anyone coming across this problem in the future:
As rmunn said, the fact that I wanted the classes in different files was simply not good design. Also I did not need different AST nodes for BoolTerm, BoolAtom and BoolExpr as they could all be described as the same node BoolExpr.
My solution was to merge all of the boolean expression visitors into the same class (and merge all files for expression visitors into a single file):
//AST.fs
type BoolExpr =
| BoolConjunctionExpr of BoolOp * BoolExpr list
| ...
//ExpressionVisitors.fs
let boolExprVisitor = { new BaseVisitor<AST.BoolExpr>() with
override this.VisitBoolExpr(context: BoolExprContext) =
context.boolTerm() |> mapAccept this |> AST.BoolConjunctionExpr AST.Or
override this.VisitBoolTerm(context: BoolTermContext) =
context.boolAtom() |> mapAccept this |> AST.BoolConjunctionExpr AST.And
override this.VisitBoolAtom(context: BoolAtomContext) =
context.boolExpr() |> accept this
}
I think if you don't want to create the visitor instances at the same time using and you have to resort to mutable variables. Create a mutable variable for one of the visitors with the value as unchecked default of its type. Then when you have the actual instance assign it to the variable.
//BoolExprVisitor.fs
module BoolExprVisitor =
let mutable boolTermVisitor = Unchecked.defaultof<BaseVisitor<AST.BoolTerm>>
let boolExprVisitor = { new BaseVisitor<AST.BoolExpr>() with
override __.VisitBoolExpr(context: BoolExprContext) =
context.boolTerm() |> mapAccept boolTermVisitor |> AST.BoolExpr
}
//BoolAtomVisitor.fs
module BoolAtomVisitor =
open BoolExprVisitor
let boolAtomVisitor = { new BaseVisitor<AST.BoolAtom>() with
override __.VisitBoolAtom(context: BoolAtomContext) =
context.boolExpr() |> accept boolExprVisitor |> AST.BoolAtom
}
//BoolTermVisitor.fs
module BoolTermVisitor
open BoolAtomVisitor
let boolTermVisitor = { new BaseVisitor<AST.BoolTerm>() with
override __.VisitBoolTerm(context: BoolTermContext) =
context.boolAtom() |> mapAccept boolAtomVisitor |> AST.BoolTerm
}
BoolExprVisitor.boolTermVisitor <- boolTermVisitor
Note that this is essentially the same thing as using createParserForwardedToRef in FParsec.
Related
I'm using union types similar to enums on my dapper objects:
type Confidence =
| Low
| Medium
| High
type Goal = {
Confidence: Confidence
...
}
I've created a custom type handler in order to make it work:
type UnionHandler<'T>() =
inherit SqlMapper.TypeHandler<'T>()
override __.SetValue(param, value) =
param.Value <- value.ToString()
()
override x.Parse(value: obj) =
Union.parse <| string value
let registerTypeHandlers() =
SqlMapper.AddTypeHandler (UnionHandler<Confidence>())
This works fine, but it would be even nicer if I didn't have to register a new one for each new union type.
Is it possible to make the type handler generic in such a way that it can handle all union types with only one registration?
This can be done with Reflection:
let internal addUnionTypeHandlers() =
let assembly = Assembly.GetExecutingAssembly()
let unionHandlerType =
assembly.GetTypes()
|> Seq.filter(fun t -> t.Name.Contains("UnionHandler") && t.IsGenericTypeDefinition)
|> Seq.head
assembly.GetTypes()
|> Seq.filter(fun t -> not t.IsGenericType && FSharpType.IsUnion(t, BindingFlags.Default))
|> Seq.iter(fun t ->
let ctor = unionHandlerType
.MakeGenericType(t)
.GetConstructor(Array.empty)
.Invoke(Array.empty)
(typeof<SqlMapper>.GetMethods()
|> Seq.filter(fun methodInfo ->
if methodInfo.Name = "AddTypeHandler" && methodInfo.IsGenericMethodDefinition then
let gp = methodInfo.GetParameters()
not <| isNull gp && gp.Length = 1 && gp.[0].ParameterType.Name.Contains("TypeHandler")
else false)
|> Seq.head)
.MakeGenericMethod(t)
.Invoke(null, [| ctor |]) |> ignore
)
Note:
It would have been much simpler if Dapper have had the signature of AddTypeHandler in a form ITypeHandler -> unit. But it accepts TypeHandler and in addition has overloaded version. So we need GMD for method AddTypeHandler and instantiate it with method MakeGenericMethod and then call this method with parameter which we obtains from GetConstructor ... Invoke
Playing further with reflection you can decide to mark some discriminated unions with some attribute to ignore adding the mapping. You can extend code to analyse if type has attribute. Also you can do manipulations on module basis I assume using FSharpType.IsModule
I want to sort items of a class and collect them in Collection-Classes that beside a List-Member also contain further information that are necessary for the sorting process.
The following example is a a very simplified example for my problem. Although it doesn't make sense, I hope it still can help to understand my Question.
type ItemType = Odd|Even //realworld: more than two types possible
type Item(number) =
member this.number = number
member this.Type = if (this.number % 2) = 0 then Even else Odd
type NumberTypeCollection(numberType:ItemType , ?items:List<Item>) =
member this.ItemType = numberType
member val items:List<Item> = defaultArg items List.empty<Item> with get,set
member this.append(item:Item) = this.items <- item::this.items
let addToCollection (collections:List<NumberTypeCollection>) (item:Item) =
let possibleItem =
collections
|> Seq.where (fun c -> c.ItemType = item.Type) //in my realworld code, several groups may be returned
|> Seq.tryFind(fun _ -> true)
match possibleItem with
|Some(f) -> f.append item
collections
|None -> NumberTypeCollection(item.Type, [item]) :: collections
let rec findTypes (collections:List<NumberTypeCollection>) (items:List<Item>) =
match items with
| [] -> collections
| h::t -> let newCollections = ( h|> addToCollection collections)
findTypes newCollections t
let items = [Item(1);Item(2);Item(3);Item(4)]
let finalCollections = findTypes List.empty<NumberTypeCollection> items
I'm unsatisfied with the addToCollection method, since it requires the items in NumberTypeCollection to be mutual. Maybe there are further issues.
What can be a proper functional solution to solve this issue?
Edit: I'm sorry. May code was too simplified. Here is a little more complex example that should hopefully illustrate why I chose the mutual class-member (although this could still be the wrong decision):
open System
type Origin = Afrika|Asia|Australia|Europa|NorthAmerika|SouthAmerica
type Person(income, taxrate, origin:Origin) =
member this.income = income
member this.taxrate = taxrate
member this.origin = origin
type PersonGroup(origin:Origin , ?persons:List<Person>) =
member this.origin = origin
member val persons:List<Person> = defaultArg persons List.empty<Person> with get,set
member this.append(person:Person) = this.persons <- person::this.persons
//just some calculations to group people into some subgroups
let isInGroup (person:Person) (personGroup:PersonGroup) =
let avgIncome =
personGroup.persons
|> Seq.map (fun p -> float(p.income * p.taxrate) / 100.0)
|> Seq.average
Math.Abs ( (avgIncome / float person.income) - 1.0 ) < 0.5
let addToGroup (personGroups:List<PersonGroup>) (person:Person) =
let possibleItem =
personGroups
|> Seq.where (fun p -> p.origin = person.origin)
|> Seq.where (isInGroup person)
|> Seq.tryFind(fun _ -> true)
match possibleItem with
|Some(f) -> f.append person
personGroups
|None -> PersonGroup(person.origin, [person]) :: personGroups
let rec findPersonGroups (persons:List<Person>) (personGroups:List<PersonGroup>) =
match persons with
| [] -> personGroups
| h::t -> let newGroup = ( h|> addToGroup personGroups)
findPersonGroups t newGroup
let persons = [Person(1000,20, Afrika);Person(1300,22,Afrika);Person(500,21,Afrika);Person(400,20,Afrika)]
let c = findPersonGroups persons List.empty<PersonGroup>
What I may need to emphasize: There can be several different groups with the same origin.
Tomas' solution using groupby is the optimal approach if you want to generate your collections only once, it's a simple and concise.
If you want to be able to add/remove items in a functional, referentially transparent style for this type of problem, I suggest you move away from seq and start using Map.
You have a setup which is fundamentally dictionary-like. You have a unique key and a value. The functional F# equivalent to a dictionary is a Map, it is an immutable data structure based on an AVL tree. You can insert, remove and search in O(log n) time. When you append/remove from the Map, the old Map is maintained and you receive a new Map.
Here is your code expressed in this style
type ItemType =
|Odd
|Even
type Item (number) =
member this.Number = number
member this.Type = if (this.Number % 2) = 0 then Even else Odd
type NumTypeCollection = {Items : Map<ItemType, Item list>}
/// Functions on NumTypeCollection
module NumberTypeCollection =
/// Create empty collection
let empty = {Items = Map.empty}
/// Append one item to the collection
let append (item : Item) numTypeCollection =
let key = item.Type
match Map.containsKey key numTypeCollection.Items with
|true ->
let value = numTypeCollection.Items |> Map.find key
let newItems =
numTypeCollection.Items
|> Map.remove key
|> Map.add key (item :: value) // append item
{Items = newItems }
|false -> {Items = numTypeCollection.Items |> Map.add key [item]}
/// Append a list of items to the collections
let appendList (item : Item list) numTypeCollection =
item |> List.fold (fun acc it -> append it acc) numTypeCollection
Then call it using:
let items = [Item(1);Item(2);Item(3);Item(4)]
let finalCollections = NumberTypeCollection.appendList items (NumberTypeCollection.empty)
If I understand your problem correctly, you're trying to group the items by their type. The easiest way to do that is to use the standard library function Seq.groupBy. The following should implement the same logic as your code:
items
|> Seq.groupBy (fun item -> item.Type)
|> Seq.map (fun (key, values) ->
NumberTypeCollection(key, List.ofSeq values))
Maybe there are further issues.
Probably. It's difficult to tell, since it's hard to detect the purpose of the OP code... still:
Why do you even need an Item class? Instead, you could simply have a itemType function:
let itemType i = if i % 2 = 0 then Even else Odd
This function is referentially transparent, which means that you can replace it with its value if you wish. That makes it as good as a property getter method, but now you've already saved yourself from introducing a new type.
Why define a NumberTypeCollection class? Why not a simple record?
type NumberTypeList = { ItemType : ItemType; Numbers : int list }
You can implement addToCollection like something like this:
let addToCollection collections i =
let candidate =
collections
|> Seq.filter (fun c -> c.ItemType = (itemType i))
|> Seq.tryHead
match candidate with
| Some x ->
let x' = { x with Numbers = i :: x.Numbers }
collections |> Seq.filter ((<>) x) |> Seq.append [x']
| None ->
collections |> Seq.append [{ ItemType = (itemType i); Numbers = [i] }]
Being immutable, it doesn't mutate the input collections, but instead returns a new sequence of NumberTypeList.
Also notice the use of Seq.tryHead instead of Seq.tryFind(fun _ -> true).
Still, if you're attempting to group items, then Tomas' suggestion of using Seq.groupBy is more appropriate.
I'm trying to create some kind of interface, but i cannot find how to use custom attributes in F# as MSDN only shows usage of CLR attributes. This is what i want to achieve:
open System
type Command (name : string) =
inherit Attribute()
member this.Name = name
[<Command("something")>]
let doSomething () =
Console.Write("I'm doing something")
[<Command("somethingElse")>]
let doSomethingElse () =
Console.Write("I'm doing something else")
[<EntryPoint>]
let main args =
let command = Console.ReadLine()
// find function where Command.Name = command and call it
Console.Read()
0
To extend on your answer, a more generic approach would be to get all the types and then filter the functions that have the attribute you're looking for (as your approach would break down once your application grows and no longer has everything "packed" into the Program class):
let getCommands () =
let types = Assembly.GetExecutingAssembly().GetTypes()
let commands =
types
|> Array.collect (fun typ -> typ.GetMethods())
|> Array.choose (fun mi ->
mi.CustomAttributes
|> Seq.tryFind (fun attr -> attr.AttributeType = typeof<Command>)
|> Option.map (fun attr -> attr, mi))
let commandsMap =
commands
|> Seq.map (fun (attr, mi) ->
let name =
let arg = attr.ConstructorArguments.[0]
unbox<string> arg.Value
name, mi)
|> Map.ofSeq
commandsMap
This gets all the functions from all the types in the executing assembly, then filters out everything that doesn't have command attribute. Then it builds a map where the key is the attribute argument and the value is the MethodInfo of the function.
Ok, found it.
Reflection.Assembly.GetExecutingAssembly().GetType("Program").GetMethods()
Program typename is not viable in code so it cannot be used in typeof<Program>, but this type exists and can be taken from assembly.
I continue to work on a printer for F# quoted expressions, it doesn't have to be perfect, but I'd like to see what is possible. The active patterns in Microsoft.FSharp.Quotations.Patterns and Microsoft.FSharp.Quotations.DerivedPatterns used for decomposing quoted expressions will typically provide MemberInfo instances when appropriate, these can be used to obtain the name of a property, function, etc. and their "declaring" type, such as a module or static class. The problem is, I only know how to obtain the CompiledName from these instances but I'd like the F# name. For example,
> <# List.mapi (fun i j -> i+j) [1;2;3] #> |> (function Call(_,mi,_) -> mi.DeclaringType.Name, mi.Name);;
val it : string * string = ("ListModule", "MapIndexed")
How can this match be rewritten to return ("List", "mapi")? Is it possible?
FYI, here is my final polished solution from Stringer Bell and pblasucci's help:
let moduleSourceName (declaringType:Type) =
FSharpEntity.FromType(declaringType).DisplayName
let methodSourceName (mi:MemberInfo) =
mi.GetCustomAttributes(true)
|> Array.tryPick
(function
| :? CompilationSourceNameAttribute as csna -> Some(csna)
| _ -> None)
|> (function | Some(csna) -> csna.SourceName | None -> mi.Name)
//usage:
let sourceNames =
<# List.mapi (fun i j -> i+j) [1;2;3] #>
|> (function Call(_,mi,_) -> mi.DeclaringType |> moduleSourceName, mi |> methodSourceName);
You can use F# powerpack for that purpose:
open Microsoft.FSharp.Metadata
...
| Call(_, mi, _) ->
let ty = Microsoft.FSharp.Metadata.FSharpEntity.FromType(mi.DeclaringType)
let name = ty.DisplayName // name is List
However, I don't think if it's possible to retrieve function name with powerpack.
Edit:
As hinted by pblasucci, you can use CompilationSourceName attribute for retrieving source name:
let infos = mi.DeclaringType.GetMember(mi.Name)
let att = infos.[0].GetCustomAttributes(true)
let fName =
(att.[1] :?> CompilationSourceNameAttribute).SourceName // fName is mapi
...or, how do I filter a sequence of classes by the interfaces they implement?
Let's say I have a sequence of objects that inherit from Foo, a seq<#Foo>. In other words, my sequence will contain one or more of four different subclasses of Foo.
Each subclass implements a different independent interface that shares nothing with the interfaces implemented by the other subclasses.
Now I need to filter this sequence down to only the items that implement a particular interface.
The C# version is simple:
void MergeFoosIntoList<T>(IEnumerable<Foo> allFoos, IList<T> dest)
where T : class
{
foreach (var foo in allFoos)
{
var castFoo = foo as T;
if (castFoo != null)
{
dest.Add(castFoo);
}
}
}
I could use LINQ from F#:
let mergeFoosIntoList (foos:seq<#Foo>) (dest:IList<'a>) =
System.Linq.Enumerable.OfType<'a>(foos)
|> Seq.iter dest.Add
However, I feel like there should be a more idiomatic way to accomplish it. I thought this would work...
let mergeFoosIntoList (foos:seq<#Foo>) (dest:IList<'a>) =
foos
|> Seq.choose (function | :? 'a as x -> Some(x) | _ -> None)
|> Seq.iter dest.Add
However, the complier complains about :? 'a - telling me:
This runtime coercion or type test from type 'b to 'a involves an indeterminate type based on information prior to this program point. Runtime type tests are not allowed on some types. Further type annotations are needed.
I can't figure out what further type annotations to add. There's no relationship between the interface 'a and #Foo except that one or more subclasses of Foo implement that interface. Also, there's no relationship between the different interfaces that can be passed in as 'a except that they are all implemented by subclasses of Foo.
I eagerly anticipate smacking myself in the head as soon as one of you kind people points out the obvious thing I've been missing.
You can do this:
let foos = candidates |> Seq.filter (fun x -> x :? Foo) |> Seq.cast<Foo>
Typically just adding a 'box' is sufficient (e.g. change function to fun x -> match box x with), but let me try it out...
Yeah; basically you cannot sideways cast from one arbitrary generic type to another, but you can upcast to System.Object (via box) and then downcast to anything you like:
type Animal() = class end
type Dog() = inherit Animal()
type Cat() = inherit Animal()
let pets : Animal list =
[Dog(); Cat(); Dog(); Cat(); Dog()]
printfn "%A" pets
open System.Collections.Generic
let mergeIntoList (pets:seq<#Animal>) (dest:IList<'a>) =
pets
|> Seq.choose (fun p -> match box p with
| :? 'a as x -> Some(x) | _ -> None) //'
|> Seq.iter dest.Add
let l = new List<Dog>()
mergeIntoList pets l
l |> Seq.iter (printfn "%A")
From https://gist.github.com/kos59125/3780229
let ofType<'a> (source : System.Collections.IEnumerable) : seq<'a> =
let resultType = typeof<'a>
seq {
for item in source do
match item with
| null -> ()
| _ ->
if resultType.IsAssignableFrom (item.GetType ())
then
yield (downcast item)
}
Another option for those inclined:
Module Seq =
let ofType<'a> (items: _ seq)= items |> Seq.choose(fun i -> match box i with | :? 'a as a -> Some a |_ -> None)
I have an open source library available on nuget, FSharp.Interop.Compose
That Converts most Linq methods into a idomatic F# form. Including OfType
Test Case:
[<Fact>]
let ofType () =
let list = System.Collections.ArrayList()
list.Add(1) |> ignore
list.Add("2") |> ignore
list.Add(3) |> ignore
list.Add("4") |> ignore
list
|> Enumerable.ofType<int>
|> Seq.toList |> should equal [1;3]