I'm looking for a clean set of ways to manage Test Specific Equality in F# unit tests. 90% of the time, the standard Structural Equality fits the bill and I can leverage it with unquote to express the relation between my result and my expected.
TL;DR "I can't find a clean way to having a custom Equality function for one or two properties in a value which 90% of is well served by Structural Equality, does F# have a way to match an arbitrary record with custom Equality for just one or two of its fields?"
Example of a general technique that works for me
When verifying a function that performs a 1:1 mapping of a datatype to another, I'll often extract matching tuples from both sides of in some cases and compare the input and output sets. For example, I have an operator:-
let (====) x y = (x |> Set.ofSeq) = (y |> Set.ofSeq)
So I can do:
let inputs = ["KeyA",DateTime.Today; "KeyB",DateTime.Today.AddDays(1); "KeyC",DateTime.Today.AddDays(2)]
let trivialFun (a:string,b) = a.ToLower(),b
let expected = inputs |> Seq.map trivialFun
let result = inputs |> MyMagicMapper
test <# expected ==== actual #>
This enables me to Assert that each of my inputs has been mapped to an output, without any superfluous outputs.
The problem
The problem is when I want to have a custom comparison for one or two of the fields.
For example, if my DateTime is being passed through a slightly lossy serialization layer by the SUT, I need a test-specific tolerant DateTime comparison. Or maybe I want to do a case-insensitive verification for a string field
Normally, I'd use Mark Seemann's SemanticComparison library's Likeness<Source,Destination> to define a Test Specific equality, but I've run into some roadblocks:
tuples: F# hides .ItemX on Tuple so I can't define the property via a .With strongly typed field name Expression<T>
record types: TTBOMK these are sealed by F# with no opt-out so SemanticComparison can't proxy them to override Object.Equals
My ideas
All I can think of is to create a generic Resemblance proxy type that I can include in a tuple or record.
Or maybe using pattern matching (Is there a way I can use that to generate an IEqualityComparer and then do a set comparison using that?)
Alternate failing test
I'm also open to using some other function to verify the full mapping (i.e. not abusing F# Set or involving too much third party code. i.e. something to make this pass:
let sut (a:string,b:DateTime) = a.ToLower(),b + TimeSpan.FromTicks(1L)
let inputs = ["KeyA",DateTime.Today; "KeyB",DateTime.Today.AddDays(1.0); "KeyC",DateTime.Today.AddDays(2.0)]
let toResemblance (a,b) = TODO generate Resemblance which will case insensitively compare fst and tolerantly compare snd
let expected = inputs |> List.map toResemblance
let result = inputs |> List.map sut
test <# expected = result #>
Firstly, thanks to all for the inputs. I was largely unaware of SemanticComparer<'T> and it definitely provides a good set of building blocks for building generalized facilities in this space. Nikos' post gives excellent food for thought in the area too. I shouldn't have been surprised Fil exists too - #ptrelford really does have a lib for everything (the FSharpValue point is also v valuable)!
We've thankfully arrived at a conclusion to this. Unfortunately it's not a single all-encompassing tool or technique, but even better, a set of techniques that can be used as necessary in a given context.
Firstly, the issue of ensuring a mapping is complete is really an orthogonal concern. The question refers to an ==== operator:-
let (====) x y = (x |> Set.ofSeq) = (y |> Set.ofSeq)
This is definitely the best default approach - lean on Structural Equality. One thing to note is that, being reliant on F# persistent sets, it requires your type to support : comparison (as opposed to just : equality).
When doing set comparisons off the proven Structural Equality path, a useful technique is to use HashSet<T> with a custom IEqualityComparer:-
[<AutoOpen>]
module UnorderedSeqComparisons =
let seqSetEquals ec x y =
HashSet<_>( x, ec).SetEquals( y)
let (==|==) x y equals =
let funEqualityComparer = {
new IEqualityComparer<_> with
member this.GetHashCode(obj) = 0
member this.Equals(x,y) =
equals x y }
seqSetEquals funEqualityComparer x y
the equals parameter of ==|== is 'a -> 'a -> bool which allows one to use pattern matching to destructure args for the purposes of comparison. This works well if either the input or the result side are naturally already tuples. Example:
sut.Store( inputs)
let results = sut.Read()
let expecteds = seq { for x in inputs -> x.Name,x.ValidUntil }
test <# expecteds ==|== results
<| fun (xN,xD) (yN,yD) ->
xF=yF
&& xD |> equalsWithinASecond <| yD #>
While SemanticComparer<'T> can do a job, it's simply not worth bothering for tuples with when you have the power of pattern matching. e.g. Using SemanticComparer<'T>, the above test can be expressed as:
test <# expecteds ==~== results
<| [ funNamedMemberComparer "Item2" equalsWithinASecond ] #>
using the helper:
[<AutoOpen>]
module MemberComparerHelpers =
let funNamedMemberComparer<'T> name equals = {
new IMemberComparer with
member this.IsSatisfiedBy(request: PropertyInfo) =
request.PropertyType = typedefof<'T>
&& request.Name = name
member this.IsSatisfiedBy(request: FieldInfo) =
request.FieldType = typedefof<'T>
&& request.Name = name
member this.GetHashCode(obj) = 0
member this.Equals(x, y) =
equals (x :?> 'T) (y :?> 'T) }
let valueObjectMemberComparer() = {
new IMemberComparer with
member this.IsSatisfiedBy(request: PropertyInfo) = true
member this.IsSatisfiedBy(request: FieldInfo) = true
member this.GetHashCode(obj) = hash obj
member this.Equals(x, y) =
x.Equals( y) }
let (==~==) x y mcs =
let ec = SemanticComparer<'T>( seq {
yield valueObjectMemberComparer()
yield! mcs } )
seqSetEquals ec x y
All of the above is best understood by reading Nikos Baxevanis' post NOW!
For types or records, the ==|== technique can work (except critically you lose Likeness<'T>s verifying coverage of fields). However the succinctness can make it a valuable tool for certain sorts of tests :-
sut.Save( inputs)
let expected = inputs |> Seq.map (fun x -> Mapped( base + x.ttl, x.Name))
let likeExpected x = expected ==|== x <| (fun x y -> x.Name = y.Name && x.ValidUntil = y.ValidUntil)
verify <# repo.Store( is( likeExpected)) #> once
Related
Here is an example:
type T =
TimeSpan
let x (y: T) =
printfn $"{y}"
let a:TimeSpan = TimeSpan.FromSeconds(3)
let b:T = TimeSpan.FromSeconds(3)
let a' = x a
let b' = x b
In this case, I want to make a type which is identical to TimeSpan but is NOT TimeSpan. I would like the ability to cast between one another, but not be equivalent when it comes to function signatures.
For example, the x function takes a type T, so the line:
let a' = x a
shouldn't compile because it passes a TimeSpan
but the line:
let b' = x b
is passing a type T and should compile.
Is there some simple and elegant way to achieve this? the goal for this is to be able to use TimeSpan, but constrain the options to some specific values.
Right now I'm using an enum that needs to be convert to TimeSpan and then TimeSpans get reconvert to the enum if they exist in the enum. It's rather ugly.
I want to make a type which is identical to TimeSpan but is NOT TimeSpan. I would like the ability to cast between one another, but not be equivalent when it comes to function signatures.
That's not possible in F#, but the usual way to accomplish something like it is with single-case unions, such as:
type T = T of TimeSpan
let x (T y) =
printfn "%A" y // y is the inner TimeSpan value
let a:TimeSpan = TimeSpan.FromSeconds(3.0)
let b:T = TimeSpan.FromSeconds(3.0) |> T
let a' = x a // doesn't compile
let b' = x b
The general issue I think you're dealing with here is called "primitive obsession".
You can either use a single cased DU, or you can use units of measure to do this. UMX specifically supports timespans.
https://github.com/fsprojects/FSharp.UMX
I'm trying to wrap my head around mon-, err, workflows in F# and while I think that I have a pretty solid understanding of the basic "Maybe" workflow, trying to implement a state workflow to generate random numbers has really got me stumped.
My non-completed attempt can be seen here:
let randomInt state =
let random = System.Random(state)
// Generate random number and a new state as well
random.Next(0,1000), random.Next()
type RandomWF (initState) =
member this.Bind(rnd,rest) =
let value, newState = rnd initState
// How to feed "newState" into "rest"??
value |> rest
member this.Return a = a // Should I maybe feed "initState" into the computation here?
RandomWF(0) {
let! a = randomInt
let! b = randomInt
let! c = randomInt
return [a; b; c]
} |> printfn "%A"
Edit: Actually got it to work! Not exactly sure how it works though, so if anyone wants to lay it out in a good answer, it's still up for grabs. Here's my working code:
type RandomWF (initState) =
member this.Bind(rnd,rest) =
fun state ->
let value, nextState = rnd state
rest value nextState
member this.Return a = fun _ -> a
member this.Run x = x initState
There are two things that make it harder to see what your workflow is doing:
You're using a function type for the type of your monad,
Your workflow not only builds up the computation, it also runs it.
I think it's clearer to follow once you see how it would look without those two impediments. Here's the workflow defined using a DU wrapper type:
type Random<'a> =
Comp of (int -> 'a * int)
let run init (Comp f) = f init
type Random<'a> with
member this.Run(state) = fst <| run state this
type RandomBuilder() =
member this.Bind(Comp m, f: 'a -> Random<_>) =
Comp <| fun state ->
let value, nextState = m state
let comp = f value
run nextState comp
member this.Return(a) = Comp (fun s -> a, s)
let random = RandomBuilder()
And here is how you use it:
let randomInt =
Comp <| fun state ->
let rnd = System.Random(state)
rnd.Next(0,1000), rnd.Next()
let rand =
random {
let! a = randomInt
let! b = randomInt
let! c = randomInt
return [a; b; c ]
}
rand.Run(0)
|> printfn "%A"
In this version you separately build up the computation (and store it inside the Random type), and then you run it passing in the initial state. Look at how types on the builder methods are inferred and compare them to what MSDN documentation describes.
Edit: Constructing a builder object once and using the binding as an alias of sorts is mostly convention, but it's well justified in that it makes sense for the builders to be stateless. I can see why having parameterized builders seems like a useful feature, but I can't honestly imagine a convincing use case for it.
The key selling point of monads is the separation of definition and execution of a computation.
In your case - what you want to be able to do is to take a representation of your computation and be able to run it with some state - perhaps 0, perhaps 42. You don't need to know the initial state to define a computation that will use it. By passing in the state to the builder, you end up blurring the line between definition and execution, and this simply makes the workflow less useful.
Compare that with async workflow - when you write an async block, you don't make the code run asynchronously. You only create an Async<'a> object representing a computation that will produce an object of 'a when you run it - but how you do it, is up to you. The builder doesn't need to know.
The msdn page documenting Records (F#) details record expressions for record construction and record patterns for deconstruction, the latter without naming them as such.
Here's an example which uses both techniques for an arithmetic operator:
// Simple two-dimensional generic vector defintion
type 'a UV =
{ U : 'a; V : 'a }
static member inline (+) ({ U = au; V = av }, { U = bu; V = bv }) =
{ U = au + bu; V = av + bv }
This appears unwieldy and not very readable. For deconstruction, there are dot-notation or functions as alternatives. Since the dot-notation operator has a special dispensation in section 8.4.2 Name Resolution and Record Field Labels of the spec (an expression’s type may be inferred from a record label), there's normally no need to annotate. Accessor functions like let u { U = u } = u wouldn't give us any advantages then.
For construction, I think a case can be made for a function as record constructor. Access to the original constructor might even be restricted:
type 'a UV =
internal { U : 'a; V : 'a }
let uv u v = { U = u; V = v }
type 'a UV with
static member inline (+) (a, b) =
uv (a.U + b.U) (a.V + b.V)
Is this an idiomatic thing to do? How to package such functions in modules and handle namespace issues?
Short answer: I don't think there is a general convention here at the moment so it will be a personal decision in the end.
To summarise what you get for free with records in F# is:
Construct: { U = u; V = v } (bracket-notation)
Deconstruct: let u = record.u (dot-notation) and let {U = u} = record (pattern matching)
Update: {record with U = u} (bracket-notation)
But you don't get first class functions for free, if you want you can code them by hand.
The following is what I would personally use as convention:
A static member New with curried arguments for record construction.
For update and deconstruction I would use some kind of Lenses abstraction.
Here's an example of the code I would have to add by hand:
// Somewhere as a top level definition or in a base library
type Lens<'T,'U> = {Get: 'T -> 'U; Set: 'U -> 'T -> 'T } with
member l.Update f a = l.Set (f (l.Get a)) a
type UV<'a> = {U : 'a; V : 'a } with
// add these static members to your records
static member New u v : UV<'a> = {U = u; V = v}
static member u = {Get = (fun (x: UV<'a>) -> x.U); Set = fun t x -> {x with U = t}}
static member v = {Get = (fun (x: UV<'a>) -> x.V); Set = fun t x -> {x with V = t}}
let uvRecord = UV.New 10 20
let u = UV.u.Get uvRecord
let uvRecord1 = UV.u.Set (u+1) uvRecord
let uvRecord2 = UV.u.Update ((+)1) uvRecord
This way I would have first class functions for construction, deconstruction but also for updates plus other very interesting Lenses properties as you can read in this post.
UPDATE (in response to your comments)
Of course they can be defined later, what does it change?
The same applies for the New constructor, it can be defined later but that's actually a good thing.
The accessor functions you defined can also be defined later, indeed any first-class getter, setter or updater value can be defined later.
Anyway the answer to your question is "no, there are no conventions" the rest it's a personal decision, which would be my decision and also many Haskellers are pushing to get some kind of automatic Lenses for Haskell records.
Why would I decide to go this way? Because in terms of lines of code the effort of adding a simple accessor function is almost the same as adding a get-Lens, so for the same price I get more functionality.
If you are not happy with the Lenses discussion please tell me, I can delete it and leave the short answer, or I can delete the whole answer too if it's confusing instead of clarifying.
Or may be I misunderstood your question, for me your question was about which convention is generally used to add first-class constructors, getters and setters values for records.
Composition is not the only advantage of Lenses, you can do many things, keep reading about them, they provide a very interesting abstraction and not only restricted to records.
I'm trying to work through an example of FsCheck right now for a type with discriminated unions in order to establish best practices for our larger project. Right now I am getting null from my generator and I am not sure why. In the following code, DataGen.containerGenerator is null.
namespace Container
open System
open Xunit
open FsCheck
module ContainerLibrary =
type [<Measure>] oz
type Container =
| Cup of Common
| Bowl of Common
and Common =
{ Volume :decimal<oz>
Weight :decimal}
module DataGen =
type Generators =
static member arbVolume =
FsCheck.Gen.choose (1, 16)
|> FsCheck.Gen.map(fun x -> (decimal x / 8.0M) * 1.0M<ContainerLibrary.oz>)
|> FsCheck.Arb.fromGen
FsCheck.Arb.register<Generators>() |> ignore
let bowlGenerator =
FsCheck.Gen.map2 (fun a b -> ContainerLibrary.Bowl( { Volume = a
Weight = b}))
(Generators.arbVolume.Generator)
(FsCheck.Arb.generate<decimal>)
let cupGenerator =
FsCheck.Gen.map2 (fun a b -> ContainerLibrary.Cup( { Volume = a
Weight = b}))
(Generators.arbVolume.Generator)
(FsCheck.Arb.generate<decimal>)
let containerGenerator =
Gen.oneof [bowlGenerator; cupGenerator]
module Tests =
[<Fact;>]
let ``01 : Containers must be no more than 20 oz`` () =
//Is this the best way to get one of something?
let c = FsCheck.Gen.sample 0 1 DataGen.containerGenerator |> Seq.head
Assert.NotNull (c)
It doesn't seem to be null when I run it, even when I get more values. Which version of FsCheck are you using?
[<Fact;>]
let ``01 : Containers must be no more than 20 oz`` () =
//Is this the best way to get one of something?
Gen.sample 0 100 DataGen.containerGenerator |> Seq.iter(fun c -> printf "%A" c; Assert.NotNull (c))
In any case, there are several things to note about what you're doing.
FsCheck uses reflection to register generators; and type of measure type parameters cannot be seen by reflection. So the Arb.register would actually override the decimal generator, for all decimals.
Somehow the FsCheck. qualifications you used confused intellisense no end.
Gen.sample is a reasonable way to test generators but I mostly use it in interactive settings; if you've gone through the trouble of setting up a test I tend to use FsCheck's built in test-case observation capabilities. See "Observing test case distribution" here: https://fsharp.github.io/FsCheck/Properties.html
Using Arb.register in the module init like you're doing is a bit brittle, depending on module initialization rules in F# to register generators. If you're using Xunit, it's much better to use the built-in integration to reduce inevitable frustration in this area.
I've rewritten your example a bit taking some of these things into account:
module DataGen =
open ContainerLibrary
//can't really register this one because of the measure, would override all decimal generatos
let volumeGenerator =
Gen.choose (1, 16)
|> Gen.map(fun x -> (decimal x / 8.0M) * 1.0M<ContainerLibrary.oz>)
let commonGenerator =
Gen.map2 (fun a b -> { Volume = a
Weight = b})
(volumeGenerator)
(Arb.generate<decimal>)
//in case you like applicative style, otherwise completely equivalent
let commonGeneratorAlternative =
(fun a b -> { Volume = a; Weight = b}) <!> volumeGenerator <*> Arb.generate<decimal>
let bowlGenerator = Gen.map Bowl commonGenerator
let cupGenerator = Gen.map Cup commonGenerator
let containerGenerator =
Gen.oneof [bowlGenerator; cupGenerator]
type Generators =
static member Container() = containerGenerator |> Arb.fromGen
module Tests =
open FsCheck.Xunit
open ContainerLibrary
//use PropertyAttribute from FsCheck.Xunit
//use the defined container generator - can also move this to module level
//other ways to parametrize
[<Property(Arbitrary=[|typeof<DataGen.Generators>|])>]
//thanks to PropertyAttribute can now just take container as argument
let ``01 : Containers must be no more than 20 oz`` (container:Container) =
match container with
| Cup common
| Bowl common -> common.Volume <= 20.0M<oz>
|> Prop.collect container //see the generated values in the output
This outputs something like:
Ok, passed 100 tests.
1% Cup {Volume = 2.0M;
Weight = -0.0000221360928858744815609M;}.
1% Cup {Volume = 1.8750M;
Weight = 922337.20325598085121M;}.
etc
I'm trying to wrap my head around functional programming using F#. I'm working my way through the Project Euler problems, and I feel like I am just writing procedural code in F#. For instance, this is my solution to #3.
let Calc() =
let mutable limit = 600851475143L
let mutable factor = 2L // Start with the lowest prime
while factor < limit do
if limit % factor = 0L then
begin
limit <- limit / factor
end
else factor <- factor + 1L
limit
This works just fine, but all I've really done is taken how I would solve this problem in c# and converted it to F# syntax. Looking back over several of my solutions, this is becoming a pattern. I think that I should be able to solve this problem without using mutable, but I'm having trouble not thinking about the problem procedurally.
Why not with recursion?
let Calc() =
let rec calcinner factor limit =
if factor < limit then
if limit % factor = 0L then
calcinner factor (limit/factor)
else
calcinner (factor + 1L) limit
else limit
let limit = 600851475143L
let factor = 2L // Start with the lowest prime
calcinner factor limit
For algorithmic problems (like project Euler), you'll probably want to write most iterations using recursion (as John suggests). However, even mutable imperative code sometimes makes sense if you are using e.g. hashtables or arrays and care about performance.
One area where F# works really well which is (sadly) not really covered by the project Euler exercises is designing data types - so if you're interested in learning F# from another perspective, have a look at Designing with types at F# for Fun and Profit.
In this case, you could also use Seq.unfold to implement the solution (in general, you can often compose solutions to sequence processing problems using Seq functions - though it does not look as elegant here).
let Calc() =
// Start with initial state (600851475143L, 2L) and generate a sequence
// of "limits" by generating new states & returning limit in each step
(600851475143L, 2L)
|> Seq.unfold (fun (limit, factor) ->
// End the sequence when factor is greater than limit
if factor >= limit then None
// Update limit when divisible by factor
elif limit % factor = 0L then
let limit = limit / factor
Some(limit, (limit, factor))
// Update factor
else
Some(limit, (limit, factor + 1L)) )
// Take the last generated limit value
|> Seq.last
In functional programming when I think mutable I think heap and when trying to write code that is more functional, you should use the stack instead of the heap.
So how do you get values on to the stack for use with a function?
Place the value in the function's parameters.
let result01 = List.filter (fun x -> x % 2 = 0) [0;1;2;3;4;5]
here both a function an a list of values are hard coded into the List.filter parameter's.
Bind the value to a name and then reference the name.
let divisibleBy2 = fun x -> x % 2 = 0
let values = [0;1;2;3;4;5]
let result02 = List.filter divisibleBy2 values
here the function parameter for list.filter is bound to divisibleBy2 and the list parameter for list.filter is bound to values.
Create a nameless data structure and pipe it into the function.
let result03 =
[0;1;2;3;4;5]
|> List.filter divisibleBy2
here the list parameter for list.filter is forward piped into the list.filter function.
Pass the result of a function into the function
let result04 =
[ for i in 1 .. 5 -> i]
|> List.filter divisibleBy2
Now that we have all of the data on the stack, how do we process the data using only the stack?
One of the patterns often used with functional programming is to put data into a structure and then process the items one at a time using a recursive function. The structure can be a list, tree, graph, etc. and is usually defined using a discriminated union. Data structures that have one or more self references are typically used with recursive functions.
So here is an example where we take a list and multiply all the values by 2 and put the result back onto the stack as we progress. The variable on the stack holding the new values is accumulator.
let mult2 values =
let rec mult2withAccumulator values accumulator =
match values with
| headValue::tailValues ->
let newValue = headValue * 2
let accumulator = newValue :: accumulator
mult2withAccumulator tailValues accumulator
| [] ->
List.rev accumulator
mult2withAccumulator values []
We use an accumulator for this which being a parameter to a function and not defined mutable is stored on the stack. Also this method is using pattern matching and the list discriminated union. The accumulator holds the new values as we process the items in the input list and then when there are not more items in the list ([]) we just reverse the list to get the new list in the correct order because the new items are concatenated to the head of the accumulator.
To understand the data structure (discriminated union) for a list you need to see it, so here it is
type list =
| Item of 'a * List
| Empty
Notice how the end of the definition of an item is List referring back to itself, and that a list can ben an empty list, which is when used with pattern match is [].
A quick example of how list are built is
empty list - []
list with one int value - 1::[]
list with two int values - 1::2::[]
list with three int values - 1::2::3::[]
Here is the same function with all of the types defined.
let mult2 (values : int list) =
let rec mult2withAccumulator (values : int list) (accumulator : int list) =
match (values : int list) with
| (headValue : int)::(tailValues : int list) ->
let (newValue : int) = headValue * 2
let (accumulator : int list) =
(((newValue : int) :: (accumulator : int list)) : int list)
mult2withAccumulator tailValues accumulator
| [] ->
((List.rev accumulator) : int list)
mult2withAccumulator values []
So putting values onto the stack and using self referencing discriminated unions with pattern matching will help to solve a lot of problems with functional programming.