Modifying RX Computational Expression Builder to hold previous values - f#

I'm using a slightly modified version of the RX builder presented here:
http://mnajder.blogspot.com/2011/09/when-reactive-framework-meets-f-30.html
Rather than taking IObservable<'T> directly my computational expression has a type of:
type MyType<'a,'b> = MyType of (IObservable<'a> -> IObservable<'b>)
let extract (MyType t) = t
Combinators then take on the form:
let where (f: 'b -> bool) (m:MyType<_,'b>) = MyType(fun input -> (extract m input).Where(f))
Within the expression itself, I often need to reference back to previous values that have been fed into the stream. In order to do so, I've defined a MyType which maintains a rolling immutable list of the n most recent values.
let history n =
MyType(fun input ->
Observable.Create(fun (o:IObserver<_>) ->
let buffer = new History<_>(n)
o.OnNext(HistoryReadOnly(buffer))
input.Subscribe(buffer.Push, o.OnError, o.OnCompleted)
)
)
With this, I can now do something like:
let f = obs {
let! history = history 20
// Run some other types, and possibly do something with history
}
I am finding that I am using this history quite frequently, ideally I would want to have this embedded directly into IObservable<'a>. Obviously I can't do that. So my question is, what is a reasonable way to introduce this concept of history that I have here. Should I be extending IObservable<'T> (not sure how to do that), wrapping the IObservable<'T>?
I appreciate any suggestions.
Edit: Added full example code.
open System
open System.Collections.Generic
open System.Reactive.Subjects
open System.Reactive.Linq
// Container function
type MyType<'a,'b> = MyType of (IObservable<'a> -> IObservable<'b>)
let extract (MyType t) = t
// Mini Builder
let internal mbind (myTypeB:MyType<'a,'b>) (f:'b -> MyType<'a,'c>) =
MyType(fun input ->
let obsB = extract myTypeB input
let myTypeC= fun resB -> extract (f resB) input
obsB.SelectMany(myTypeC)
)
type MyTypeBuilder() =
member x.Bind (m,f) = mbind m f
member x.Combine (a,b) = MyType(fun input -> (extract a input).Concat(extract b input))
member x.Yield (r) = MyType(fun input -> Observable.Return(r))
member x.YieldFrom (m:MyType<_,_>) = m
member x.Zero() = MyType(fun input -> Observable.Empty())
member x.Delay(f:unit -> MyType<'a,'b>) = f()
let mtypeBuilder = new MyTypeBuilder()
// Combinators
let simplehistory =
MyType(fun input ->
Observable.Create(fun (o:IObserver<_>) ->
let buffer = new List<_>()
o.OnNext(buffer)
input.Subscribe(buffer.Add, o.OnError, o.OnCompleted)
)
)
let where (f: 'b -> bool) m = MyType(fun input -> (extract m input).Where(f))
let take (n:int) m = MyType(fun input -> (extract m input).Take(n))
let buffer m = MyType(fun input -> (extract m input).Buffer(1))
let stream = MyType(id)
// Example
let myTypeResult (t:MyType<'a,'b>) (input:'a[]) = (extract t (input.ToObservable().Publish().RefCount())).ToArray().Single()
let dat = [|1 .. 20|]
let example = mtypeBuilder {
let! history = simplehistory
let! someEven = stream |> where(fun v -> v % 2 = 0) // Foreach Even
let! firstValAfterPrevMatch = stream |> take 1 // Potentially where a buffer operation would run, all values here are after i.e. we cant get values before last match
let! odd = stream |> where(fun v -> v % 2 = 1) |> take 2 // Take 2 odds that follow it
yield (history.[history.Count - 1], history.[0], someEven,firstValAfterPrevMatch, odd) // Return the last visited item in our stream, the very first item, an even, the first value after the even and an odd
}
let result = myTypeResult example dat
val result : (int * int * int * int * int) [] =
[|(5, 1, 2, 3, 5); (7, 1, 2, 3, 7); (7, 1, 4, 5, 7); (9, 1, 4, 5, 9);
(9, 1, 6, 7, 9); (11, 1, 6, 7, 11); (11, 1, 8, 9, 11); (13, 1, 8, 9, 13);
(13, 1, 10, 11, 13); (15, 1, 10, 11, 15); (15, 1, 12, 13, 15);
(17, 1, 12, 13, 17); (17, 1, 14, 15, 17); (19, 1, 14, 15, 19);
(19, 1, 16, 17, 19)|]

Using the standard Rx workflow builder, you can create a function history that handles your example use case:
let history (io:IObservable<_>) =
io.Scan(new List<_>(), (fun l t -> l.Add t; l)).Distinct()
let io = new Subject<int>()
let newio = rx { let! history = history io
let! even = io.Where(fun v -> v % 2 = 0)
let! next = io.Take 1
let! odd = io.Where(fun v -> v % 2 = 1).Take 2
yield (history.Last(), history.[0], even, next, odd) }
newio.Subscribe(printfn "%O") |> ignore
for i = 1 to 20 do
io.OnNext i
Extending that to provide history length limits should be trivial. Was there a specific reason you need to define your own type/builder, or was doing that just a means to attain something like this?
Here's an example with combinators. You just have to define the observable outside the rx block. You could get history to work differently with immutable histories rather than a persistent list, so whatever fits your needs.
let history (io:IObservable<_>) =
io.Scan(new List<_>(), (fun l t -> l.Add t; l))
let newest (hist:'a List) = hist.Last()
let extract (ioHist:'a List IObservable) = ioHist.Select newest
let take (i:int) (ioHist: 'a List IObservable) = ioHist.Take i
let where (f: 'a -> bool) (ioHist: 'a List IObservable) = ioHist.Where(fun hist -> f(newest hist))
let io = new Subject<int>()
let history1 = history io
let newio =
rx { let! hist = history1.Distinct()
let! even = extract (history1 |> where (fun v -> v % 2 = 0))
let! next = extract (history1 |> take 1)
let! odd = extract (history1 |> where (fun v -> v % 2 = 1) |> take 2)
yield (hist.Last(), hist.[0], even, next, odd) }

You can use Observable.Buffer to do this already.
Sorry for the C# my F# hat is not thinking today.
IObservable<int> source = ...
IOBservable<IList<int>> buffered = source.Buffer(5,1)
will create you a stream of lists.
Or try to use buffer in LINQ which is more like F# query expressions
Console.WriteLine ("START");
var source = new List<int> () { 1, 2, 3, 4, 5 }.ToObservable ();
// LINQ C#'s Monad sugar
var r =
from buffer in source.Buffer (3, 1)
from x in buffer
from y in buffer
select new { x,y};
r.Subscribe (o=>Console.WriteLine (o.x + " " + o.y));
Console.WriteLine ("END");
Note from in LINQ is exactly/almost the same as let! in an f# query expression. The result is below. Also note how I am using buffer later in the expression just like you could in an f# query expression.
START
1 1
1 2
1 3
2 1
2 2
2 3
3 1
3 2
3 3
2 2
2 3
2 4
3 2
3 3
3 4
4 2
4 3
4 4
3 3
3 4
3 5
4 3
4 4
4 5
5 3
5 4
5 5
4 4
4 5
5 4
5 5
5 5
END

Sorry, my F# is extremely rusty, but perhaps you are looking for the Scan operator. It will push values to an accumulator as the source produces them and then you can use this accumulator to produce the next value for your projection.
Here (in C#, apologies) we take a sequence of [0..10] which produces these value 100ms apart, and we return a running Sum.
var source = Observable.Interval(TimeSpan.FromMilliseconds(100))
.Take(10);
source.Scan(
new List<long>(), //Seed value
(acc, value)=> //Accumulator function
{
acc.Add(value);
return acc;
}
)
.Select(accumate=>accumate.Sum())
which produces the values [0,1,3,6,10,15,21,28,36,45] 100ms apart.
I would think with this tool you can manage your History of values (by adding them to a history/accumulator) and then using this History in the Select to project the value that is appropriate.

Related

Decorate an F# sequence with (simple) computed state for each element

I have a solution to this, and several working-but-unsatisfactory solutions, but it took a lot of work and seems unnecessarily complex.
Am I missing something in F#?
The Problem
I have a sequence of numbers
let nums = seq { 9; 12; 4; 17; 9; 7; 13; }
I want to decorate each number with an "index", so the result is
seq [(9, 0); (12, 1); (4, 2); (17, 3); ...]
Looks simple!
In practice the input can be very large and of indeterminate size. In my application, it is coming from a REST service.
Further
the operation must support lazy evaluation (because of the REST backend)
must be purely functional, which eliminates the obvious seq { let mutable i = o; for num in nums do .. } solution, ditto for while ... do ...
Lets call the function decorate, of type (seq<'a> -> seq<'a * int>), so it would work as follows:
nums
|> decorate
|> Seq.iter (fun (n,index) -> printfn "%d: %d" index n)
Producing:
0: 9
1: 12
2: 4
...
6: 13
This is a trivial problem with Lists (apart from the lazy evaluation), but tricky with Sequences.
My solution is to use Seq.unfold, as follows:
let decorate numSeq =
(0,numSeq)
|> Seq.unfold
(fun (count,(nums : int seq)) ->
if Seq.isEmpty nums then
None
else
let result = ((Seq.head nums),count)
let remaining = Seq.tail nums
Some( result, (count+1,remaining)))
This meets all requirements, and is the best I've come up with.
Here's the whole solution, with diagnostics to show lazy evaluation:
let nums =
seq {
// With diagnostic
let getN n =
printfn "get: %d" n
n
getN 9;
getN 12;
getN 4;
getN 17;
getN 9;
getN 7;
getN 13
}
let decorate numSeq =
(0,numSeq)
|> Seq.unfold
(fun (count,(nums : int seq)) ->
if Seq.isEmpty nums then
None
else
let result = ((Seq.head nums),count)
let remaining = Seq.tail nums
printfn "unfold: %A" result
Some( result, (count+1,remaining)))
nums
|> Seq.cache
// To prevent re-computation of the sequence.
// Will be necessary for any solution. This solution required only one.
|> decorate
|> Seq.iter (fun (n,index) -> printfn "ITEM %d: %d" index n)
PROBLEM: This took a LOT of work to reach. It looks complex, compared to the (apparently) simple requirement.
QUESTION: Is there a simpler solution?
Discussion of some alternatives.
All work, but are unsatisfactory for the reasons given
// Most likely: Seq.mapFold
// Fails lazy evalation. The final state must be evaluated, even if not used
let decorate numSeq =
numSeq
|> Seq.mapFold
(fun count num ->
let result = (num,count)
printfn "yield: %A" result
(result,(count + 1)))
0
|> fun (nums,finalState) -> nums // And, no, using "_" doesn't fix it!
// 'for' loop, with MUTABLE
// Lazy evaluation works
// Not extensible, as the state 'count' is specific to this problem
let decorate numSeq =
let mutable count = 0
seq {
for num in numSeq do
let result = num,count
printfn "yield: %A" result
yield result;
count <- count+1
}
// 'for' loop, without mutable
// Fails lazy evaluation, and is ugly
let decorate numSeq =
seq {
for index in 0..((Seq.length numSeq) - 1) do
let result = ((Seq.item index numSeq), // Ugly!
index)
printfn "yield: %A" result
yield result
}
// "List" like recursive descent,
// Fails lazy evaluation. Ugly, because we are not meant to use recursion on Sequences
// https://stackoverflow.com/questions/11451727/recursive-functions-for-sequences-in-f
let rec decorate' count (nums : int seq) =
if Seq.isEmpty nums then
Seq.empty
else
let hd = Seq.head nums
let tl = Seq.tail nums
let result = (hd,count)
let tl' = decorate' (count+1) tl
printfn "yield: %A" result
seq { yield result; yield! tl'}
let decorate : (seq<'a> -> seq<'a * int>) = decorate' 0
You can use Seq.mapi to do what you need.
let nums = seq { 9; 12; 4; 17; 9; 7; 13; }
nums |> Seq.mapi (fun i num -> (num, i))
This gives (9, 0); (12, 1); etc...
Seq is "lazy" in the same sense as IEnumerable in C#.
You can read about Seq.mapi here:
https://fsharp.github.io/fsharp-core-docs/reference/fsharp-collections-seqmodule.html#mapi
Read more about the use of map here:
https://fsharpforfunandprofit.com/posts/elevated-world/#map
In addition to the Seq.mapi function mentioned in Sean's answer, F# also has a built-in Seq.indexed function, which decorates a sequence with index. This does not do exactly what you're asking, because the index becomes the first element of the tuple, but depending on your use case, it may do the trick:
> let nums = seq { 9; 12; 4; 17; 9; 7; 13; };;
val nums : seq<int>
> Seq.indexed nums;;
val it : seq<int * int> = seq [(0, 9); (1, 12); (2, 4); (3, 17); ...]
If I was trying to implement this on my own using a more primitive function, it could be done using Seq.scan, which is a bit like fold but produces a lazy sequence of states. The only tricky thing is that you have to construct the initial state and then process the rest of the sequence:
Seq.tail nums
|> Seq.scan (fun (prevIndex, _) v -> (prevIndex+1, v)) (0, Seq.head nums)
This will not work for empty lists, even though the function should logically be able to handle this.
Using for is not bad, or wrong. for and yield in a seq {} is how you write new seq functions, if none of the provided functions in Seq Module is a best-fit. It is neither wrong, or bad to use this special construct. It's the same as C# foreach and yield syntax.
Using a mutable in a limited scope, is also not wrong. Mutables are a bad idea, if they escape the scope. For example, you return a mutable value, from a function.
Its important to put the mutable inside the seq, and not outside. Your version is wrong.
Let's assume this
let xs = decorate [3;6;7;12;9]
for x in xs do
printfn "%A" x
for x in xs do
printfn "%A" x
Now you have two versions of decorate. The first version
let decorate numSeq =
let mutable count = 0
seq {
for num in numSeq do
yield (num,count)
count <- count + 1
}
will print:
(3, 0)
(6, 1)
(7, 2)
(12, 3)
(9, 4)
(3, 5)
(6, 6)
(7, 7)
(12, 8)
(9, 9)
Or in other words. The mutable is shared across all invocation whenever you iterate through the sequence. As a general tip. If you want to return a seq then put all your code into seq. And put the seq {} after the = sign. If you do this instead.
let decorate numSeq = seq {
let mutable count = 0
for num in numSeq do
yield (num,count)
count <- count + 1
}
you get the correct output:
(3, 0)
(6, 1)
(7, 2)
(12, 3)
(9, 4)
(3, 0)
(6, 1)
(7, 2)
(12, 3)
(9, 4)
Forther you explain, that this version is not "extensible". But the version with mapi you select as "correct". Has the same problem, it only provides an index, nothing more.
If you want a more generic version, you always can make a function that expects its values as a function argument. You could for example change the above function to this code.
let decorate2 f (state:'State) (xs:'T seq) = seq {
let mutable state = state
for x in xs do
yield state, x
let newState = f state x
state <- newState
}
Now decorate2 expects a state that you can freely pass, and a function to change the state. With this function you could then write:
decorate2 (fun state _ -> state+1) 0 [3;6;7;12;9]
The function signature is nearly the same as Seq.scan, but still a little bit different. But if you want to create a indexed function, you could use scan like this.
let indexed xs =
Seq.scan (fun (count,_) x -> (count+1,x)) (0,Seq.head xs) (Seq.skip 1 xs)
Just in my opinion. This version is harder rot read, understand, and just fugly compared to decorate or decorate2.
And just a note. There is already a Seq.indexed function in the standard library, that does what you wish.
for x in Seq.indexed [3;6;7;12;9] do
printfn "%A" x
will print
(0, 3)
(1, 6)
(2, 7)
(3, 12)
(4, 9)

F# - Weight (Unit of Measure) Stones-Pounds

I have a csv file containing daily weights as follows:
Date,Name,Weight
11-Sep-2017,Alpha,9-1
13-Sep-2017,Alpha,8-13
15-Sep-2017,Alpha,8-11
Though I can successfully import them using CsvProvider, the weight column defaults to System.DateTime.
// Weight
[<Measure>] type lb
[<Literal>]
let input = "DayWeights.csv"
type Weights = CsvProvider<input, HasHeaders=true>
let data = Weights.GetSample()
for row in data.Rows do
printfn "Output: (%A, %A, %A)" row.Date row.Name row.Weight
Is it possible to create a Unit of Measure (UoM) to define "stlb" with the option to convert to lbs on import and, if so, how?
I don't think you could represent stones-pounds as a single numeric type, and units of measure can only be used on numeric types (although there is some discussion about changing this in future). This is because some of their features only make sense with numeric operations like addition and multiplication. The units themselves are multiplied and divided:
[<Measure>] type lb
2<lb> + 2<lb> // 4<lb>
2<lb> * 2<lb> // 4<lb ^ 2>
2<lb> / 2<lb> // 1
Instead of units of measure, if you want some kind of tag to know that a given value has a type of stones-pounds, you could create a single case discriminated union:
type StonesPounds = StonesPounds of int * int
// StonesPounds -> int<lb>
let convertToLb (StonesPounds (s, p)) = (s * 14 + p) * 1<lb>
StonesPounds (1, 2) |> convertToLb // 16<lb>
The downside of this compared to units of measure is that you have to manually pack and unpack these values in code before you can use the numbers and there is a runtime cost for that too.
I resolved the automatic converting of the input weight column to System.DateTime as follows:
// http://fssnip.net/27
let lazySplit (sep:string) (str:string) =
match sep, str with
| ((null | ""), _) | (_, (null | "")) -> seq [str]
| _ ->
let n, j = str.Length, sep.Length
let rec loop p =
seq {
if p < n then
let i = match str.IndexOf(sep, p) with -1 -> n | i -> i
yield str.Substring(p, i - p)
yield! loop (i + j)
}
loop 0
let weight input =
input
|> (fun x -> lazySplit "/" x |> Seq.take 2 |> String.concat("-"))
let data = Weighings.GetSample()
for row in data.Rows do
let stlbs = weight (string row.Weight)
printfn "Output: (%A, %A, %A)" row.Date row.Name stlbs
// Output: 11-Sep-2017,"Alpha","09-01")
Thanks to one and all for your expert help and guidance.

Finding paths in (DAG) directed acyclic graph given destination

Let's say I have this array:
let reportStructure = [|(2, 1); (3, 2); (4, 2); (5, 3); (6, 4); (7, 3)|]
where the first int in a tuple reports to the second int.
I can map that really easily with
let orgMap = Map.ofArray reporting
From there, I could easily get a list of all the ints that report to 2 with
orgMap
|> Map.filter (fun _ key -> key = 2)
which returns
map [(3, 2); (4, 2)]
What I'd really like to see, however, is the entire structure, from 2 all the way down. For example, I'd like to find a way that could give me the sample output
map [(3, 2); (4, 2); (5, 3); (6, 4); (7, 3)]
if I'm looking for person 2 or
map [(5, 3); (7, 3)]
if I'm interested in person 3.
Can I do this? If so, how? Is there another structure other than a map that would be a better way to make this happen?
Thanks in advance for your help.
Since OCaml is close to F# and trying to find Topological sort in F# was not turning up anything useful I looked for OCaml code.
I found An Introduction to Objective Caml which had a solution to your problem using Depth First Search and used it as the basis for this answer. Also because you are new to F# you can review the document and see how the code is derived. Oddly I took a look at the remainder of the document after posting this and he has a more advanced version of DFS latter in the document.
Your input is an array [| |] but your answer is a list [] so I did most of the work as list.
The answers are not in the same order as you had, but they are in the same format.
let reportStructure = [|(2, 1); (3, 2); (4, 2); (5, 3); (6, 4); (7, 3)|]
//
// 6 -> 4 -> 2
// 5 -> 3 -> 2 -> 1
// 7 -> 3
// val revStructure : tl:('a * 'b) list -> ('b * 'a) list
let revStructure tl = List.map (fun (a,b) -> (b,a)) tl
// val mem : item:'a -> list:'a list -> bool when 'a : equality
let mem item list = List.exists (fun x -> x = item) list
// val successors : n:'a -> edges:('a * 'b) list -> 'b list when 'a : equality
let successors n edges =
let matching (s,_) = s = n
List.map snd (List.filter matching edges)
// val dist : pred:'a -> succs:'b list -> ('a * 'b) list
let dist pred succs = List.map (fun y -> (pred,y)) succs
// val dfsPairs : edges:('a * 'a) list -> start:'a -> ('a * 'a) list when 'a : equality
let dfsPairs edges start =
let rec dfsPairsInner edges visited start result =
match start with
| [] -> List.rev (revStructure result)
| n::nodes ->
if mem n visited then
dfsPairsInner edges visited nodes result
else
let predecessors = dist n (successors n edges)
let result =
match predecessors with
| [] -> result
| _ -> predecessors # result
dfsPairsInner edges (n::visited) ((successors n edges) # nodes) result
dfsPairsInner edges [] [start] []
let revEdges = revStructure (List.ofArray reportStructure)
let result = dfsPairs revEdges 2
// val result : (int * int) list = [(4, 2); (3, 2); (7, 3); (5, 3); (6, 4)]
let result = dfsPairs revEdges 3
// val result : (int * int) list = [(7, 3); (5, 3)]
I assume that you want to get a list of pair of ints with "numbers" that directly or indirectly report to some "root".
Here is an easy but inefficient solution:
let reportStructure = [|(2, 1); (3, 2); (4, 2); (5, 3); (6, 4); (7, 3)|]
let reportStructureSet =
reportStructure |> Set.ofArray
let reportingDirectlyTo root raportsToSet =
raportsToSet
|> Set.filter(fun (_, key) -> key = root)
let addNextGeneration previousIteration raportsToSet =
let numbersLowerInHierarchy = previousIteration |> Set.map fst
raportsToSet |> Set.filter(
// select only those elements from raportsToSet...
fun (num, supervisor) ->
// ...which either are already in previousIteration
(Set.contains (num, supervisor) previousIteration) ||
// ...or are "below" someone from previousIteration
(Set.contains supervisor numbersLowerInHierarchy))
let reportingDirectlyOrIndirectlyTo root raportsToSet =
// applies addNextGeneration until is "stabilizes" on some value
let rec fixPointHelper previousIteration =
let nextIteration = addNextGeneration previousIteration raportsToSet
if nextIteration = previousIteration
then nextIteration
else fixPointHelper nextIteration
// set of numbers directly reporting to root
let reportsDirectly = reportingDirectlyTo root raportsToSet
// start "iteration" using numbers directly reporting to root
fixPointHelper reportsDirectly
let reportingDirectlyOrIndirectlyToList root raportsToSet =
reportingDirectlyOrIndirectlyTo root raportsToSet
|> Set.toList
If you want to implement an efficient solution, you should interpret reportStructureSet as a graph in following way:
ints are vertices
pair of ints are directed edges
Then simply check which edges are reachable from "root" using a DFS.
I like f# puzzles, so I took a stab at this one. I hope that you enjoy.
let orgList = [(2, 1); (3, 2); (4, 2); (5, 3); (6, 4); (7, 3)]
let orgMap =
orgList
|> List.fold (fun acc item ->
let key = snd item
match Map.tryFind key acc with
| Some(value) ->
let map' = Map.remove key acc
Map.add(key) (item::value) map'
| None ->
Map.add(key) (item::[]) acc
) Map.empty<int, (int*int) list>
let findReports supervisor =
let rec findReports' acc collection =
match collection with
| head::tail ->
(findReports' (head::acc) tail)
# match Map.tryFind (fst head) orgMap with
| Some(value) -> (findReports' [] value)
| None -> []
| [] -> acc
findReports' [] (Map.find supervisor orgMap)
findReports 2
|> List.map fst
|> List.distinct
returns
val it : int list = [3; 4; 5; 7; 6]
findReports 2 returns
val it : (int * int) list = [(3, 2); (4, 2); (5, 3); (7, 3); (6, 4)]
I'll break it down to clarify.
let orgList = [ (1, 2); (1, 3); (1, 4); (2, 5); (3, 6); (4, 5); (5, 6); (5, 7) ]
We take your list of tuples and create a functional map of boss to ((report,boss) list). This might be known as an adjacency list, which is used for traversing graphs.
let orgMap =
orgList
|> List.fold (fun acc item ->
let key = snd item
match Map.tryFind key acc with
If there is a list of reports under a boss, add to that list.
| Some(reports) ->
let map' = Map.remove key acc
Map.add(key) (item::reports) map'
Otherwise, add to an empty list and insert into the dictionary.
| None ->
Map.add(key) (item::[]) acc
Start with an empty map as an accumulator.
) Map.empty<int, (int*int) list>
Recurse through the items to find all reports.
let findReports supervisor =
let rec findReports' acc collection =
match collection with
If there is an item, append it to the accumulator. This is BFS. If you switch the expression before and after the concatenate operator (#), it will become DFS.
| head::tail ->
(findReports' (head::acc) tail)
Concatenate the current list to the recursive list of reports to reports.
# match Map.tryFind (fst head) orgMap with
| Some(value) -> (findReports' [] value)
| None -> []
If at the end of the list, return the list.
| [] -> acc
Run the recursive function.
findReports' [] (Map.find supervisor orgMap)
Run the function.
findReports 7
Return only the reports
|> List.map fst
Don't report the report twice.
|> List.distinct

Testcases for NUnit 3 tests in F#

I am trying to set up a test suite for an F# project using NUnit.
It seems that especially when testing things like parsers and type checkers one typically has a list of valid input data and a list of invalid data.
The tests itself are practically identical, so I am looking for a clever way to avoid writing a test function for each and every data item and instead seperate the test function from the data.
Apparently, there seems to be something called test cases for that but I am having a hard time to find comprehensive documentation for the usage of NUnit 3 with F# in general and specifically a best practice example for my scenario.
Any pointers and hints are greately appreaciated!
This is an updated answer for NUnit 3.x since my original answer showed a NUnit 2.x example.
The examples below are not meant to be comprehensive, but enough to get you over the threshold and up an running. The things of note are that the test functions are written using argument list instead of currying. Also there are several ways to generate test data using NUnit 3.x attributes, e.g. Pairwise, but sadly none of the attributes available know how to generate test data for discriminated unions.
Also FSUnit is not needed and I didn't try to make it work as the difference between NUnint 2.x and 3.x are so dramatic that I was happy just to get the following examples working. Maybe in the future I will update this answer.
namespace NUnit3Demo
open NUnit.Framework
module MyTest =
// ----------------------------------------------------------------------
[<Pairwise>]
let pairWiseTest([<Values("a", "b", "c")>] (a : string), [<Values("+", "-")>] (b :string), [<Values("x", "y")>] (c : string))
= printfn "%A %A %A" a b c
// ----------------------------------------------------------------------
let divideCases1 =
[
12, 3, 4
12, 2, 6
12, 4, 3
] |> List.map (fun (q, n, d) -> TestCaseData(q,n,d))
[<TestCaseSource("divideCases1")>]
let caseSourceTest1(q:int, n:int, d:int) =
Assert.AreEqual( q, n / d )
// ----------------------------------------------------------------------
let divideCases2 =
seq {
yield (12, 3, 4)
yield (12, 2, 6)
yield (12, 4, 3)
}
[<TestCaseSource("divideCases2")>]
let caseSourceTest2(q:int, n:int, d:int) =
Assert.AreEqual( q, n / d )
// ----------------------------------------------------------------------
[<TestCase(12,3,4)>]
[<TestCase(12,2,6)>]
[<TestCase(12,4,3)>]
let testCaseTest(q:int, n:int, d:int) =
Assert.AreEqual( q, n / d )
// ----------------------------------------------------------------------
let evenNumbers : int [] = [| 2; 4; 6; 8 |]
[<TestCaseSource("evenNumbers")>]
let caseSourceTest3 (num : int) =
Assert.IsTrue(num % 2 = 0)
Leaving Original Answer since it was noted in other answer by OP.
The following example was written 3 years ago using NUnit 2.x so it is a bit dated but should give you an ideal.
You create an array of the test data, then index into the array to pull out the test values and expected results. The nice thing about this is that you don't wind up writing lots of individual test for a function.
This comes from a project some of us did years ago.
open NUnit.Framework
open FsUnit
let private filterValues : (int list * int list)[] = [|
(
// idx 0
// lib.filter.001
[],
[]
);
(
// idx 1
// lib.filter.002
[-2],
[-2]
);
(
// idx 2
// lib.filter.003
[-1],
[]
);
(
// idx 3
// lib.filter.004
[0],
[0]
);
(
// idx 4
// lib.filter.005
[1],
[]
);
(
// idx 5
// lib.filter.006
[1; 2],
[2]
);
(
// idx 6
// lib.filter.007
[1; 3],
[]
);
(
// idx 7
// lib.filter.008
[2; 3],
[2]
);
(
// idx 8
// lib.filter.009
[1; 2; 3],
[2]
);
(
// idx 9
// lib.filter.010
[2; 3; 4],
[2; 4]
);
|]
[<Test>]
[<TestCase(0, TestName = "lib.filter.01")>]
[<TestCase(1, TestName = "lib.filter.02")>]
[<TestCase(2, TestName = "lib.filter.03")>]
[<TestCase(3, TestName = "lib.filter.04")>]
[<TestCase(4, TestName = "lib.filter.05")>]
[<TestCase(5, TestName = "lib.filter.06")>]
[<TestCase(6, TestName = "lib.filter.07")>]
[<TestCase(7, TestName = "lib.filter.08")>]
[<TestCase(8, TestName = "lib.filter.09")>]
[<TestCase(9, TestName = "lib.filter.10")>]
let ``List filter`` idx =
let (list, _) = filterValues.[idx]
let (_, result) = filterValues.[idx]
List.filter (fun x -> x % 2 = 0) list
|> should equal result
filter (fun x -> x % 2 = 0) list
|> should equal result
IIRC the problem with using NUnit with F# is to remember to use <> in the right location.
In NUnit3 there is TestCaseSource and TestCaseData and for the best practices part I added FsUnit:
namespace NUnit3Demo
open NUnit.Framework
open FsUnit
[<TestFixture>]
module MyTest =
let methodToBeTested s =
if String.length s > 3 then failwith "Something's wrong"
else String.length s
let validData =
[
TestCaseData(" ").Returns(3)
TestCaseData("").Returns(0)
TestCaseData("a").Returns(1)
]
let invalidData =
[
" "
"abcd"
"whatever"
]
let otherInvalidData =
[
"just"
"because"
]
[<TestCaseSource("invalidData");
TestCaseSource("otherInvalidData")>]
let ``More than 3 characters throws`` s =
(fun () -> methodToBeTested s |> ignore)
|> should throw typeof<System.Exception>
[<TestCaseSource("validData")>]
let ``Less than 4 characters returns length`` s =
methodToBeTested s
Note that TestCaseData can take and return arbitrary objects (obviously they should match the test signatures). Also, the data can be written even nicer:
let validData =
[
" ", 3
"", 0
"a", 1
] |> List.map (fun (d, r) -> TestCaseData(d).Returns r)
By the end of the day, I realised I should not have used an array in the first place!
I finally understood how the TestCase mechanism is supposed to work:
it simply passes the annotation's contents as a parameter to a function that now is not unit->unit anymore but (in my case) string->unit. Thus all my data items are now pasted into individual TestCase annotations, and the array is gone. Surely this might look a bit odd, to have TestCase annotations whose contents span many lines of code but the array was not beautiful either, so be it.
Unfortunately, my solution is not universally applicable, e.g. would not work for Guy Coder's code above. The reason is indicated here: https://stackoverflow.com/a/28015585/2289899 where they say:
CLI has a restriction regarding kinds of attribute parameters:
primitive: bool, int, float, etc
enums
strings
type references: System.Type
'kinda objects': boxed (if needed) representation of types from above
one dimensional array of one of types from above (ie. no nested arrays allowed)
So we can conclude at this point that you can not use tuple as an
attribute parameter's type.

Type inference in pattern match over list

I'm stuck with trying to create a function that will do the following:
let p = [1, 2, 4, 2, 1]
let v = 8
then I want to go over the elements in a until I find the index i of the one where all elements up to and including i are greater or equal than v. So in this case it should return 4, because 1+2+4 < 8 and 1+2+4+2 > 8. So there 4th element, value of 2 puts the total over 8.
(some background: I want to do monte carlo, where I have a list of probabilies that add up to 1. Then I pass a random number between 0 and 1 to have it pick one of the possible future states. Simple example here with ints)
What I have so far is this:
let p = [1, 2, 4, 2, 1]
let pick (v:int) (l:int list) =
let rec sub (i:int) (acc:int) (l2:int list) =
match l2 with
| h::t -> if acc+h >= v then i else sub(i+1, acc+h, t)
| _ -> failwith "total list didn't amount to " + v
sub 0 0 l
pick 8 p
But it gives the following error on the bit sub(i+1, acc+h, t):
error FS0001: This expression was expected to have type
int
but here has type
int -> int list -> int
But I'm not passing the function sub itself, I'm calling it complete with arguments and brackets and all, so why doesn't it return int, the result of the function?
How do I make it return the result of the function?
Thanks in advance,
Gert-Jan
you give the 3-tuple (i+1,acc+h,t) where curried function is supposted to be:
| h::t -> if acc+h >= v then i else sub (i+1) (acc+h) t
Try this.
First, p will be understood as [(1, 2, 4, 2, 1);] which is an (int*int*int*int*int) list with only one element. p as an int list should be [1; 2; 4; 2; 1].
Second, sub(i+1, acc+h, t) in line 6 should be called in the curried form, not in the tuple form. The correction is sub (i+1) (acc+h) t.

Resources