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")]
Related
I'm learning F# and I am building a quick set of functions which compare two poker hands and determine the winner.
I made this discriminated union to represent categories of poker hands:
type Category =
| HighCard
| OnePair
| TwoPair
| ThreeOfAKind
| Straight
| Flush
| FullHouse
| FourOfAKind
| StraightFlush
I use this code to compare categories to determine if one hand is better than another:
if playerCategory > houseCategory then Win
elif playerCategory < houseCategory then Loss
// ... More code to handle cases within the same category
So, for example, the expression:
let playerCategory = FullHouse
let houseCategory = HighCard
if playerCategory > houseCategory then Win
elif playerCategory < houseCategory then Loss
// ... Other code
Would have the value Win.
However, I don't understand how the < and > operators are able to work here. (Originally I had a function which mapped each case to a numeric value, but I realized it wasn't necessary.) If I rearrange the order of the cases then the logic breaks, so I'm assuming each case is assigned some default value corresponding to its order within the type?
But I would definitely appreciate a bit more insight...
This is described in the specification:
by default, record, union, and struct type definitions called
structural types implicitly include compiler-generated declarations
for structural equality, hashing, and comparison. These implicit
declarations consist of the following for structural equality and
hashing
8.15.4 Behavior of the Generated CompareTo implementations
If T is a union type, invoke Microsoft.FSharp.Core.Operators.compare
first on the index of the union cases for the two values, and then on
each corresponding field pair of x and y for the data carried by the
union case. Return the first non-zero result.
In addition to what Lee said, there's also in the spec
8.5.4 Compiled Form of Union Types for Use from Other CLI Languages
A compiled union type U has:
...
One CLI instance property U.Tag for each case C. This property fetches or computes an integer tag corresponding to the case.
The compiler-generated CompareTo method uses the backing fields of these properties to determine the index as stipulated in 8.15.4. This is evidenced by IlSpy:
int tag = this._tag;
int tag2 = category._tag;
if (tag != tag2)
{
return tag - tag2;
}
if (this.Tag != 0)
{
return 0;
}
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.
Are there any documents or examples out there on how one can extend/add new keywords to query expressions? Is this even possible?
For example, I'd like to add a lead/lag operator.
In addition to the query builder for the Rx Framework mentioned by #pad, there is also a talk by Wonseok Chae from the F# team about Computation Expressions that includes query expressions. I'm not sure if the meeting was recorded, but there are very detailed slides with a cool example on query syntax for generating .NET IL code.
The source code of the standard F# query builder is probably the best resource for finding out what types of operations are supported and how to annotate them with attributes.
The key attributes that you'll probably need are demonstrated by the where clause:
[<CustomOperation("where",MaintainsVariableSpace=true,AllowIntoPattern=true)>]
member Where :
: source:QuerySource<'T,'Q> *
[<ProjectionParameter>] predicate:('T -> bool) -> QuerySource<'T,'Q>
The CustomOperation attribute defines the name of the operation. The (quite important) parameter MaintainsVariableSpace allows you to say that the operation returns the same type of values as it takes as the input. In that case, the variables defined earlier are still available after the operation. For example:
query { for p in db.Products do
let name = p.ProductName
where (p.UnitPrice.Value > 100.0M)
select name }
Here, the variables p and name are still accessible after where because where only filters the input, but it does not transform the values in the list.
Finally, the ProjectionParameter allows you to say that p.UnitValue > 100.0M should actually be turned into a function that takes the context (available variables) and evaluates this expression. If you do not specify this attribute, then the operation just gets the value of the argument as in:
query { for p in .. do
take 10 }
Here, the argument 10 is just a simple expression that cannot use values in p.
Pretty cool feature for the language. Just implemented the reverse to query QuerySource.
Simple example, but just a demonstration.
module QueryExtensions
type ExtendedQueryBuilder() =
inherit Linq.QueryBuilder()
/// Defines an operation 'reverse' that reverses the sequence
[<CustomOperation("reverse", MaintainsVariableSpace = true)>]
member __.Reverse (source : Linq.QuerySource<'T,System.Collections.IEnumerable>) =
let reversed = source.Source |> List.ofSeq |> List.rev
new Linq.QuerySource<'T,System.Collections.IEnumerable>(reversed)
let query = ExtendedQueryBuilder()
And now it being used.
let a = [1 .. 100]
let specialReverse =
query {
for i in a do
select i
reverse
}
Following up my previous question, I'm slowly getting the hang of FParsec (though I do find it particularly hard to grok).
My next newbie F# question is, how do I extract data from the list the parser creates?
For example, I loaded the sample code from the previous question into a module called Parser.fs, and added a very simple unit test in a separate module (with the appropriate references). I'm using XUnit:
open Xunit
[<Fact>]
let Parse_1_ShouldReturnListContaining1 () =
let interim = Parser.parse("1")
Assert.False(List.isEmpty(interim))
let head = interim.Head // I realise that I have only one item in the list this time
Assert.Equal("1", ???)
Interactively, when I execute parse "1" the response is:
val it : Element list = [Number "1"]
and by tweaking the list of valid operators, I can run parse "1+1" to get:
val it : Element list = [Number "1"; Operator "+"; Number "1"]
What do I need to put in place of my ??? in the snippet above? And how do I check that it is a Number, rather than an Operator, etc.?
F# types (including lists) implement structural equality. This means that if you compare two lists that contain some F# types using =, it will return true when the types have the same length and contain elements with the same properties.
Assuming that the Element type is a discriminated union defined in F# (and is not an object type), you should be able to write just:
Assert.Equal(interim, [Number "1"; Operator "+"; Number "1"])
If you wanted to implement the equality yourself, then you could use pattern matching;
let expected = [Number "1"]
match interim, expected with
| Number a, Number b when a = b -> true
| _ -> false
How can a value of type:
type Tree =
| Node of int * Tree list
have a value that references itself generated in a functional way?
The resulting value should be equal to x in the following Python code, for a suitable definition of Tree:
x = Tree()
x.tlist = [x]
Edit: Obviously more explanation is necessary. I am trying to learn F# and functional programming, so I chose to implement the cover tree which I have programmed before in other languages. The relevant thing here is that the points of each level are a subset of those of the level below. The structure conceptually goes to level -infinity.
In imperative languages a node has a list of children which includes itself. I know that this can be done imperatively in F#. And no, it doesn't create an infinite loop given the cover tree algorithm.
Tomas's answer suggests two possible ways to create recursive data structures in F#. A third possibility is to take advantage of the fact that record fields support direct recursion (when used in the same assembly that the record is defined in). For instance, the following code works without any problem:
type 'a lst = Nil | NonEmpty of 'a nelst
and 'a nelst = { head : 'a; tail : 'a lst }
let rec infList = NonEmpty { head = 1; tail = infList }
Using this list type instead of the built-in one, we can make your code work:
type Tree = Node of int * Tree lst
let rec x = Node(1, NonEmpty { head = x; tail = Nil })
You cannot do this directly if the recursive reference is not delayed (e.g. wrapped in a function or lazy value). I think the motivation is that there is no way to create the value with immediate references "at once", so this would be awkward from the theoretical point of view.
However, F# supports recursive values - you can use those if the recursive reference is delayed (the F# compiler will then generate some code that initializes the data structure and fills in the recursive references). The easiest way is to wrap the refernece inside a lazy value (function would work too):
type Tree =
| Node of int * Lazy<Tree list>
// Note you need 'let rec' here!
let rec t = Node(0, lazy [t; t;])
Another option is to write this using mutation. Then you also need to make your data structure mutable. You can for example store ref<Tree> instead of Tree:
type Tree =
| Node of int * ref<Tree> list
// empty node that is used only for initializataion
let empty = Node(0, [])
// create two references that will be mutated after creation
let a, b = ref empty, ref empty
// create a new node
let t = Node(0, [a; b])
// replace empty node with recursive reference
a := t; b := t
As James mentioned, if you're not allowed to do this, you can have some nice properties such as that any program that walks the data structure will terminate (because the data-structrue is limited and cannot be recursive). So, you'll need to be a bit more careful with recursive values :-)