Extracting the values from an IGroupedObservable - f#

Reactive.Linq's GroupBy leaves you with an IObservable<IGroupedObservable<'TKey, 'TValue>>. How do you get the values from the IGroupedObservable? The key is accessible by x.Key, so I suppose the values could be projected by some transformation of sorts.
This is roughly what I want to do:
open System.Reactive.Linq
let doStuffWithEvenNumbers i = i*10
let doStuffWithOddNumbers i = i*3
let numbers = Observable.Range(0, 10)
let groups = numbers.GroupBy(fun i -> i % 2 = 0)
let subscription1 = groups.Where(fun i -> i.Key).Subscribe(doStuffWithEvenNumbers)
let subscription2 = groups.Where(fun i -> not i.Key).Subscribe(doStuffWithOddNumbers)
Of course, the two let subscriptionX = lines won't compile, since I need to get from IGroupedObservable<bool, int> to int.

IGroupedObservable<'TKey, 'TValue> extends IObservable<'TValue>, that's how you get to the values. In your case you can do that in many ways:
// you can use SelectMany to 'flatten' the observable
groups.Where(fun i -> i.Key).SelectMany(fun o -> o :> IObservable<int>).Subscribe(doStuffWithEvenNumbers)
Note that Subscribe call take an Action, whereas in your case you defined the method as a Func. You need to remove its returned value for the call to work.

Related

How to receive a type that extends an interface without losing the original type

I have just started using F# and my brain is broken trying to figure out how to work with its types without having to resort to an OO type of programming.
Here is my situation I basically want to create a method where I provide the type and the Id and it returns to me the object on the database.
So basically this is what I get so far.
let client = MongoClient()
let database = client.GetDatabase("testdb")
let lowerCase (str : string) =
str.ToLower()
let nameOf (classType: Type) =
classType.Name
let nameTypeOf<'a> =
nameOf typeof<'a>
let getCollection<'a> =
let collectionName = nameTypeOf<'a> |> lowerCase
database.GetCollection<'a> collectionName
let dbSelect<'a> id =
let collection = getCollection<'a>
collection.Find(fun(x) -> x.Id = id).First()
So my problem is with the dbSelect, obviously it does not compile since x is generic, basically I wanted to create an interface with the Id and all my objects interface with it.
I do know how to do it using classes and inheritances, but I am avoiding having to use instanced classes outside interop with c# libraries. What would be the best functional way to do it, if there is any.
This is what I was eexpecting to call it with
type IDbObject =
abstract Id: string
type Item =
{
Id: string
Name: string
}
interface IDbObject with
member x.Id = x.Id
let item =
selectDb<Item> "5993592a35ce962b80da1e22"
Any help would be appreciated.
And if anyone want to point out how crappy my code is, any feedback is really appreciated
I don't think the solution here is much different from what you'd have in C#. You can constrain the generic type to use the interface members, getting something roughly like this:
let getCollection<'a when 'a :> IDbObject> () =
let collectionName = nameTypeOf<'a> |> lowerCase
database.GetCollection<'a> collectionName
let dbSelect<'a when 'a :> IDbObject> id =
let collection = getCollection<'a>()
collection.Find(fun (x : 'a) -> x.Id = id).First()
The type of dbSelect should be inferred to be string -> #IDbObject, and be coerced to string -> 'a at the call site.

F# Adding value to map result in KeyNotFoundException

type bytesLookup = Map<byte,int list>
type lookupList = bytesLookup list
let maps:bytesLookup = Map.empty
let printArg arg = printfn(Printf.TextWriterFormat<unit>(arg))
let array1 = [|byte(0x02);byte(0xB1);byte(0xA3);byte(0x02);byte(0x18);byte(0x2F)|]
let InitializeNew(maps:bytesLookup,element,index) =
maps.Add(element,List.empty<int>)(*KeyNotFoundException*)
maps.[element]
let MapArray (arr:byte[],maps:bytesLookup ) =
for i in 0..arr.Length do
match maps.TryFind(arr.[i]) with
| Some(e) -> i::e
| None -> InitializeNew(maps,arr.[i],i)
MapArray(array1,maps);
printArg( maps.Count.ToString())
Exception
System.Collections.Generic.KeyNotFoundException: The given key was not
present in the dictionary. at
Microsoft.FSharp.Collections.MapTreeModule.find[TValue,a](IComparer1
comparer, TValue k, MapTree2 m) at
Microsoft.FSharp.Collections.FSharpMap2.get_Item(TKey key) at
FSI_0012.MapArray(Byte[] arr, FSharpMap2 maps) in Script1.fsx:line 16
at .$FSI_0012.main#() in Script1.fsx:line 20
In the function I'm trying to initialize a new element in the map with a list of int. I also try to push a new int value into the list at the same time.
What am I doing wrong?
F# Map is an immutable data structure, the Add method doesn't modify the existing data structure, it returns a new Map with the additions you've requested.
Observe:
let ex1 =
let maps = Map.empty<byte, int list>
maps.Add(1uy, [1]) // compiler warning here!
maps.[1uy]
Two things about this code:
It throws System.Collections.Generic.KeyNotFoundException when you run it
It gives you a compiler warning that the line maps.Add... should have type unit but actually has type Map<byte,int list>. Don't ignore the warning!
Now try this:
let ex2 =
let maps = Map.empty<byte, int list>
let maps2 = maps.Add(1uy, [1])
maps2.[1uy]
No warning. No exception. Code works as expected, returning the value [1].

index rows by year in F#

i am reading my data as a frame on F# as follows
let myannual = Frame.ReadCsv("data/annual.csv")
My frame consists of time series columns and a year column, and I would like to index my time series by year. I cannot do it as follows
let myyears = [| for i in myannual.GetColumn<float>("yyyy").Values -> float i |]
let myindexedframe = myannual.IndexRows(myyears)
What should I do? Any feedback is appreciated!
The ReadCsv method takes an optional parameter indexCol that can be used to specify the index column - and you also need to provide a type parameter to tell Deedle what is the type of the index:
let myannual = Frame.ReadCsv<int>("data/annual.csv", indexCol="yyy")
Your approach would work too, but you'd need to use IndexRowsWith, which takes a sequence of new indices (and it is better to use int because float is imprecise for years):
let myyears = [| for i in myannual.GetColumn<float>("yyyy").Values -> int i |]
let myindexedframe = myannual.IndexRowsWith(myyears)
The IndexRows method takes just the name of a column (very similar to using the indexCol parameter when calling ReadCsv):
let myindexedframe = myannual.IndexRows<int>("yyyy")

How can I dynamically unbox a value in F#?

I am trying to achieve the automatic/dynamic cast in the fourth line below:
let a = 1 // type: int
let b = box a // type: obj
b.GetType() // System.Int32, so it is perfectly aware what it is!
let c = unbox b // fails....
The following would would work in the final line above BUT would require me to know and explicitly mark ahead-of-time the primitive/value type that I am working with (which I am trying to avoid):
let c1:int = unbox b
let c2 = b :?> int
While b knows at run-time what it is, the compiler doesn't, because it's an obj.
If you know, at compile time, what it is, you can unbox it like this:
let a = 1
let b = box a
b.GetType()
let c = unbox<int> b
c is now an int.
unbox only does anything if the type can be explicitly or implicitly determined at compile time. Here it will implicitly (and wrongly) try to convert the object to a string, as that's how it is used in the subsequent line.
let a = 1
let b = box a
b.GetType()
let c = unbox b
printf "%s" c
This of course gives a runtime error because it is not a string.
There's no way to have unbox convert to "what it actually is under the hood", as there's no definite way of determining this at compile time. There may be another way to do what you're trying to do though, if you can provide more details.
If you're wanting to, say create a generic unboxed list from boxed objects, you can do something like this:
let addToList (l: 'a list) (o: obj) = // type annotations optional
let o' = unbox o // unboxes to generic type 'a
o'::l
let l = [1;2;3]
let b = box 4
let l' = addToList l b // l' is list<int>, not list<obj>
let l2 = [1.;2.;3.]
let b2 = box 4.
let l2' = addToList l2 b2 // l2' is list<float>
// but as above you still have to be careful
let lcrash = addToList l b2 // crash

'mutable' in type definition

Why is disabled types like
type t = A of int | B of string * mutable int
while such types are allowed:
type t = A of int | B of string * int ref
The question is, how would you modify the value of a mutable element of discriminated union case? For ref types, this is quite easy, because ref is a reference cell (a record actually) which contains the mutable value:
match tval with
| B(str, refNum) -> refNum := 4
We extract the reference cell and assign it to a new symbol (or a new variable) refNum. Then we modify the value inside the ref cell, which also modifies tval, because the two references to the cell (from discriminated union case and from refNum variable) are aliased.
On the other hand, when you write let mutable n = 0, you're creating a variable, which can be directly mutated, but there is no cell holding the mutable value - the variable n is directly mutable. This shows the difference:
let mutable a = 10
let mutable b = a
b <- 5 // a = 10, b = 5
let a = ref 10
let b = a
b := 5 // a = 5, b = 5 (because of aliasing!)
So, to answer your question - there is no way to directly refer to the value stored inside the discriminated union case. You can only extract it using pattern matching, but that copies the value to a new variable. This means that there isn't any way you could modify the mutable value.
EDIT
To demonstrate limitations of mutable values in F#, here is one more example - you cannot capture mutable values inside a closure:
let foo() =
let mutable n = 0
(fun () -> n <- n + 1; n) // error FS0407
I think the reason is same as with discriminated union cases (even though it's not as obvious in this case). The compiler needs to copy the variable - it is stored as a local variable and as a field in the generated closure. And when copying, you want to modify the same variable from multiple references, so aliasing semantics is the only reasonable thing to do...
Ref is a type (int ref = ref<int>). Mutable is not a type, it's a keyword that allows you to update a value.
Example:
let (bla:ref<int>) = ref 0 //yup
let (bla:mutable<int>) = 3 //no!

Resources