I have a question about default "=" (equals) operator in F#. It allows to compare user-defined union types. The question is: what's the complexity of it? For example, let's consider following type:
type Tree<'a> =
| Nil
| Leaf of 'a
| Node of Tree<'a> * Tree<'a>
and following trees:
let a : Tree<int> = Node (Node (Node (Leaf 1, Leaf 2), Node (Leaf 3, Node (Leaf 4, Leaf 5))), Node (Leaf 6, Nil))
let b : Tree<int> = Node (Node (Node (Leaf 1, Leaf 2), Node (Leaf 3, Node (Leaf 4, Leaf 5))), Node (Leaf 6, Nil))
let c : Tree<int> = Node (Node (Node (Leaf 1, Leaf 2), Nil), Node (Node (Leaf 3, Node (Leaf 4, Leaf 5)), Leaf 6))
It is obvious that this code:
printfn "a = b: %b" (a = b)
printfn "a = c: %b" (a = c)
printfn "a = a: %b" (a = a)
produces this output:
a = b: true
a = c: false
a = a: true
I expect that the "a = b" and "a = c" comparsions takes the linear time. But what about "a = a"? If it is constant what about more complex structures, like that one:
let d : Tree<int> = Node (a, c)
let e : Tree<int> = Node (a, c)
Will it go through whole d and e structure or will it stop at "a = a" and "c = c"?
F# uses structural equality whereas the default Equals implementation in .NET uses reference equality. This means, in the typical case, equality comparisons are O(N) where N is the number of fields in the object graphs being compared.
If you want to ensure a = a is optimized, you can override Equals to check for reference equality first, and fall back on structural equality otherwise. You'll need to annotate your type with [<CustomEquality>].
You can see the rather lengthy implementation of structural equality in the F# source code on github. To follow the call hierarchy start with GenericEqualityObj on line 1412.
EDIT: The original answer was wrong.
The usual implementation of Equals() in .Net works like this:
Compare the two instances by reference. If they both refer to the same object, return true.
Compare the runtime types of the two instances. If they are different, return false.
Compare each of the fields of the type pairwise for equality. If any are not equal, return false, else return true.
For some reason, F# skips the first step, which means the time complexity is always linear.
Since the compiler knows that a and b are the same and some subtrees of c are same as some subtrees of a, and it also knows that they are immutable, it could theoretically make a and b the same object and reuse some of their parts in c. The runtime does something similar with strings, called string interning. But (based on decompiled code) it seems the compiler currently doesn't do this.
Related
I get a IEnumerable of object from using a SqlCommandProvider. Those objects match my rows and columns. Lets called it B. In my program I created a type matching those columns too. Lets call this record A. How can I actually transform/cast/construct a record c of type A based on values from B?
type A = {k: int; c: string}
let a:A = { k = 1; c = "c" }
let b = {| k = 1; c = "c" |} // lets say that this one simulate the sql's object
let c:A = b
printfn "%A" a
printfn "%A" b
printfn "%A" c
Try it online!
I got an error of type mismatch:
error FS0001: This expression was expected to have type 'A' but here has type '{|c : string ; k : int|}'
Full sample code with the provider:
type A = {k: int; c: string}
let toA c =
(A)c // ???
do
use cmd = new SqlCommandProvider<"
SELECT k, c
FROM Examples
" , connectionString>(connectionString)
cmd.Execute() |> Seq.map toA
sql table if it matters:
k
c
0
a
1
b
I read the doc without finding a solution to my problem. Maybe it is a comprehension problem.
A working solution is to construct a record from the object:
let toA c =
{k = c.k; c = c.c }
cmd.Execute()
|> Seq.map toA
How can I access the named fields of a discriminated union's member?
Example:
type Point = | Point of x : int * y : int
let p = Point(3, 1)
// how to access x-value or y-value of p here?
In general, unions with named fields work just like any other union type: You would access the fields via match:
let x, y =
match p with
| Point (x1, y1) -> x1, y1
The F# documentation also mentions a way of matching only some named parameters. In your case, this means you can write:
let xOnly =
match p with
| Point (x = x1) -> x1
If all you have is a single case, see the answer by #p.s.w.g. The code in that answer is general for all discriminated unions. For singleton unions with named fields, you can use the special syntax shown above and write:
let Point(x = myX) = p
This binds the value of field x to myX.
PS as per the comments: Why can you not read out the fields right away, by doing p.x? You can think of a discriminated union as a small object hierarchy (and use it such, see the discriminated union documentation: "You can often use a discriminated union as a simpler alternative to a small object hierarchy"). Consider the following DU:
type Shape = | Circle of r: float | Square of float
You can view Shape as the superclass. Circle and Square are two derived classes, each with a single float property. Each instance of Circle or Square that you create will be upcast to be a Shape.
With that, it becomes clear why you can't read out the fields immediately: you first need to establish which of the derived classes you are looking at, only after the cast to the right subclass you can read out the fields.
This object hierarchy view matches very closely to how DUs are handled internally by F#: If you look at the DU type in reflection, you will see two nested types that have the same name as your union cases:
> typeof<Shape>.GetNestedTypes()
|> Seq.iter (fun t ->
let p = t.GetProperties()
let s =
p
|> Array.map (fun p -> sprintf "%s: %s" p.Name p.PropertyType.Name)
|> String.concat "; "
printfn "Nested type %s: %i Properties %s" t.Name p.Length s
);;
Nested type Tags: 0 Properties
Nested type Circle: 4 Properties r: Double; Tag: Int32; IsCircle: Boolean; IsSquare: Boolean
Nested type Square: 4 Properties Item: Double; Tag: Int32; IsCircle: Boolean; IsSquare: Boolean
The actual data lives in properties of the subclass. For Circle, we used named fields, you see the property r. For Square, we have data in the Item property (or Item1, Item2 if there were multiple arguments). The rest are compiler generated: the numeric Tag field that will be used to quickly distinguish between the subclasses, and two bool properties for subclass checks.
The superclass itself only has compiler-generated properties:
> typeof<Shape>.GetProperties()
|> Seq.iter (fun p -> printfn "Property %s" p.Name);;
Property Tag
Property IsCircle
Property IsSquare
For single-case discriminated unions like your example, you don't need to use a match-with expression. You could just do this:
let (Point (x, y)) = p
printf "%i" x // 3
Or to just get x and ignore y:
let (Point (x, _)) = p
printf "%i" x // 3
F#'s pattern matching is very powerful so it felt natural to write:
match (tuple1, tuple2) with
| ((a, a), (a, a)) -> "all values are the same"
| ((a, b), (a, b)) -> "tuples are the same"
| ((a, b), (a, c)) -> "first values are the same"
// etc
However, the first pattern match gives a compiler error:
'a' is bound twice in this pattern
Is there a cleaner way to do it than the following?
match (tuple1, tuple2) with
| ((a, b), (c, d)) when a = b && b = c && c = d -> "all values are the same"
| ((a, b), (c, d)) when a = c && b = d -> "tuples are the same"
| ((a, b), (c, d)) when a = c -> "first values are the same"
// etc
This is a perfect use case for F#'s "active patterns". You can define a couple of them like this:
let (|Same|_|) (a, b) =
if a = b then Some a else None
let (|FstEqual|_|) ((a, _), (c, _)) =
if a = c then Some a else None
And then clean up your pattern matching with them; note how the first case (where all values are equal) uses the nested Same pattern to check that the first and second elements of the tuple are equal:
match tuple1, tuple2 with
| Same (Same x) ->
"all values are the same"
| Same (x, y) ->
"tuples are the same"
| FstEqual a ->
"first values are the same"
| _ ->
failwith "TODO"
Performance tip: I like to mark simple active patterns like these with inline -- since the logic within the active patterns is simple (just a few IL instructions), it makes sense to inline them and avoid the overhead of a function call.
You can use parameterized active patterns to remedy the issue.
let (|TuplePairPattern|_|) ((p1, p2), (p3, p4)) ((a, b), (c, d)) =
let matched =
[(p1, a); (p2, b); (p3, c); (p4, d)]
|> Seq.groupBy fst
|> Seq.map (snd >> Set.ofSeq)
|> Seq.forall (fun s -> Set.count s = 1)
if matched then Some () else None
Particularly, you should define a pattern in a form of literals (chars, strings, etc).
match tuple1, tuple2 with
| TuplePairPattern(('a', 'a'), ('a', 'a')) -> "all values are the same"
| TuplePairPattern(('a', 'b'), ('a', 'b')) -> "tuples are the same"
| TuplePairPattern(("a", "b"), ("a", "c")) -> "first values are the same"
// etc
I think, the most elegant way can be accomplished by combining two excellent answers provided by #Stephen Swensen and #pad.
The first idea is that the structure (a tuple containing two tuples) can be unpacked once, instead of doing it in every match case.
The second idea is working with sequences of values, all of which must be equal to each other.
Here's the code:
let comparer ((a,b),(c,d)) =
let same = Set.ofSeq >> Set.count >> ((=) 1)
if same[a; b; c; d] then "all values are the same"
elif same[a; c] && same[b; d] then "tuples are the same"
elif same[a; c] then "first values are the same"
else "none of above"
You may change elif's into a match, but does not seem feasible to me.
In practice, I would probably unpack the tuples up-front and then do a series of if / then / else expressions:
let a,b = tuple1
let c,d = tuple2
if a = b && b = c && c = d then "all values are the same"
elif a = c && b = d then "tuples are the same"
elif a = c then "first values are the same"
...
If you find yourself doing this frequently, an active pattern might be warranted (and in the case of 2-tuples, a complete active pattern would be doable and likely preferable - exhaustive matches are "safer" than non-exhaustive matches). Or, perhaps you need a more sophisticated data structure.
I feel silly for even asking this because it seems so trivial but my brain is failing me. If I had the following:
let a, b, c = 1, 1, 1
Is there an eligant way to determine if a, b, and c all hold the same value. Something like:
let result = (a = b = c)
This fails because the expression a = b returns true and the next expression results in true = c and complains that it was expecting int, not bool. The only thing I can think of is:
a = b && a = c && b = c
which won't work when I want to add more variables.
Really what I'm trying to do is this:
let same (x: string * string * string) =
match x with
| (a, a, a) -> true
| _ -> false
I was hoping that I could match all the elements into one element and if they were different it would move on, but it says on the second element in the match that it has already been bound.
To check if every value in a list is the same:
let rec same = function
| x::y::_ when x <> y -> false
| _::xs -> same xs
| [] -> true
Usage
let a, b, c = 1, 1, 1
same [a; b; c] //true
let same (a, b, c) = a = b && b = c
I would try to use the forall function in order to determine if all of the numbers are same.
let list = [a; b; c;];;
List.forall (fun n -> n = a) list;;
val it : bool = true
This solution produces exactly the required syntax. Surprisingly to myself, is fairly fast. Also, is seems to be a good example of using monads, also known as Computation Expressions.
// Generic
let inline mOp1<'a> op sample x = op sample x, sample
let inline mOp2<'a> op1 op2 (b, sample) x = op1 b (op2 sample x), sample
// Implementation for (=) and (&&)
let (==) = mOp1 (=)
let (&=) = mOp2 (&&) (=)
// Use
let ret1 = a == b &= c &= d &= e |> fst
How it works
The approach is a very simplified State monad. The monadic type is a tuple of (bool, 'T). The first component is the boolean value of ongoing calculation, and the second is the sample value to compare with.
(==) would initialize the monad, similar to Delay operator.
(&=) is used for all subsequent comparisons. It is similar to Bind operator.
We don't need Return because fst would serve pretty fine.
mOp1 and mOp2 are abstractions over the logical operations. These allow defining your own operators. Here are examples of or-equal and and-greater-than:
let (|=) = mOp2 (||) (=)
let (.>) = mOp1 (>)
let (&>) = mOp2 (&&) (>)
// Use
let ret2 = a == b |= c |= d |= e |> fst // if any of b,c,d,e equals to a
let ret3 = 5 .> 3 &> 4 |> fst // true: 5>3 && 5>4
let ret4 = 5 .> 3 &> 8 &> 4 |> fst // false
Performance
I really enjoyed the beautiful solution by #ildjarn, but constructing List is quite slow, so my primary goal was performance.
Running a chain of 8 comparisons, 10 million times:
04972ms a=b && a=с && ...
23138ms List-based
12367ms monadic
let standard = (0, 4.5M, 4L)
let tuples = [| ("A", -2, 1.0M, 2L);
("B", -1, 2.0M, 3L);
("C", 0, 3.0M, 4L);
("D", 1, 4.0M, 5L);
("E", 2, 5.0M, 6L) |]
let qualified = tuples
|> Array.sortBy(fun (_, a, b, c) -> (a, -b, c))
|> Array.filter(fun (_, a, b, c) -> (a, b, c) <= standard)
printfn "%A" qualified
I have an array of tuples, and a standard. I want to sort the tuples and pick up those tuples which meet the requirements.
For the tuples, I ignore the first element, and sort the second element and forth element in ordinary way, but also sort the third element in reverse order; and I have a standard tuple, for all the tuples with the second element is at least as big as the standard, and the third element is at most as big as the standard are qualified tuples.
In the above example, the qualified tuple is: = [| ("C", 0, 3.0M, 4L) |]
The conditions are: the second element >= 0 and the third element <= 4.5M and forth element >= 4L
But my code did NOT work!
Let me know how to write a function can do this job!
Thanks and have a nice weekend.
John
I don't think there is any clever way to do what you need using the built in comparison that works on tuples. The main problem is that the comparison treats first element as the most significant, so it decides just using the first few elements (without even considering the rest of the values. Your conditions specify restrictions on all elements. So, the solution from Gustavo is probably the easiest way to go.
However, there are some minor points - firstly, it may be a good idea to perform filtering before sorting, because then your sorting function will need to sort fewer elements:
let qualified =
tuples
|> Array.sortBy (...)
|> Array.filter (...)
If you wanted to represent the condition in some global value that is easy to change, then creating a tuple with 3 values that specify the required minumum/maximum is not enough, because you don't say whether the value is minimum or maximum... However, you could use a tuple of functions that specify the conditions:
let standard = ((fun _ -> true), (<=) 0, (>=) 4.5M, (<=) 4L)
This specifies that all values of first element are OK, values of the second element should be larger than zero ( (<=) 0 stands for a function that takes x and returns 0 <= x) etc. Then you can write:
let conditionsHold (p1, p2, p3, p4) (v1, v2, v3, v4) =
p1 v1 && p2 v2 && p3 v3 && p4 v4
let qualified =
tuples
|> Array.sortBy(fun (_, a, b, c) -> (a, -b, c))
|> Array.filter (conditionsHold standard)
Just change the last line for:
Array.filter(fun (_, a, b, c) -> let (x,y,z) = standard in a >= x && b <= y && c >= z)
Note that the tuple ("D", 1, 4.0M, 5L) also qualifies.
UPDATE:
Tomas is right, it's better to filter first.
Another interesting functional way to solve it could be making the 3-uple an applicative functor.
let pure' x = (x,x,x)
let (<*>) (f,g,h) (x,y,z) = (f x, g y, h z)
let standard = (0, 4.5M, 4L)
let tuples = [| ("A", -2, 1.0M, 2L);
("B", -1, 2.0M, 3L);
("C", 0, 3.0M, 4L);
("D", 1, 4.0M, 5L);
("E", 2, 5.0M, 6L) |]
let qualified = tuples
|> Array.filter(fun (_, a, b, c) -> ((>=),(<=),(>=)) <*> (a,b,c) <*> standard = pure' true)
|> Array.sortBy(fun (_, a, b, c) -> (a, -b, c))