Access DateTime enumerations: Property is not static - f#

I have a sequence of DateTime objects, and I would like to get just the Sundays. .net has the DateTime struct, with a DayOfWeek property. Now, consider the following bit of code:
let sundaysFirstOfMonth = dateRange |> Seq.filter (fun d -> d.DayOfWeek = DateTime.DayOfWeek.Sunday)
This does not compile with a Property 'DayOfWeek' is not static, while this
let sundaysFirstOfMonth = dateRange |> Seq.filter (fun d -> int d.DayOfWeek = 0)
does, as I know that Sunday maps to 0 in the enumeration.
How can I make use of the enumerations without having to cast to int and reference to the int itself?
Thanks!

Found the solution myself. This works:
let sundaysFirstOfMonth = dateRange |> Seq.filter (fun d -> d.DayOfWeek = DayOfWeek.Sunday)
I misunderstood where the enumerations was defined. It is indeed in the System namespace, not in System.DateTime

Related

How to Cast IList<IList<Object>> to list of specific type in F#

I'm having some issues finding out how to cast a string array to a specific type.
Here is my code
type plItem = {
sku: string
name: string
size: string
buy: decimal
sell: decimal
barcode: string
}
// .... ( get values from google sheets )
let values:IList<IList<Object>> = response.Values
let pl = values |> Seq.map ( fun item -> Seq.toArray )
At the end of the code - pl is now an array of strings. I want to make it an aray of the type ( above ) plItem I'm not sure of the easiest way to to this.
If I understand the question correctly, you have a list of list where the outer list represents rows and the nested list represents columns. You want to turn the rows into records and the columns correspond to individual record fields.
There is no automatic way of doing that. You'll just have to extract individual columns and convert them to an appropriate type (either by unboxing the type into a string or by getting the string value and then parsing it). Something like this:
open System
open System.Collections.Generic
type plItem = {
sku: string
name: string
size: string
buy: decimal
sell: decimal
barcode: string
}
let values:IList<IList<Object>> =
[| [| box "12660"; box "Probiotics 14 Strains"; box "60 VCaps";
box "31.46"; box "50.35"; box "9403067126606"; |] :> IList<_>
|] :> IList<_>
let pl = values |> Seq.map (fun row ->
{ sku = unbox row.[0]
name = unbox row.[1]
size = unbox row.[2]
buy = decimal (unbox<string> row.[3])
sell = decimal (unbox<string> row.[4])
barcode = unbox row.[5] })

Extend F# Arrays with lookup for bigint

I would like to extend F# Arrays such that I can use arrays without converting to the finite int. Instead I want to work with bigint directly.
I was able to add a second length method to the array type as follows:
type 'T ``[]`` with
member this.LengthI: bigint =
bigint this.Length
member this.Item(index: bigint): 'T =
this.[int index]
However the Item method cannot be called with the .[ ] syntax.
Any ideas how this could be achieved? I this possible at all?
I strongly suspect this isn't possible for native arrays. You can verify yourself that you can overload indexed access just fine for other collections.
If you compile the following code:
let myArray = [| "a" |]
let myList = [ "a" ]
let arrayElement = myArray.[11111]
let listElement = myList.[22222]
and inspect the resulting IL, you'll see that while accessing the list element compiles to a regular virtual call, there is a special CIL instruction for accessing a native array element, ldelem.
//000004: let arrayElement = myArray.[11111]
IL_002c: call string[] Fuduoqv1565::get_myArray()
IL_0031: ldc.i4 0x2b67
IL_0036: ldelem [mscorlib]System.String
IL_003b: stsfld string '<StartupCode$51dff40d-e00b-40e4-b9cc-15309089d437>'.$Fuduoqv1565::arrayElement#4
.line 5,5 : 1,33 ''
//000005: let listElement = myList.[22222]
IL_0040: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<string> Fuduoqv1565::get_myList()
IL_0045: ldc.i4 0x56ce
IL_004a: callvirt instance !0 class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<string>::get_Item(int32)
IL_004f: stsfld string '<StartupCode$51dff40d-e00b-40e4-b9cc-15309089d437>'.$Fuduoqv1565::listElement#5
IL_0054: ret
I would guess that the same compiler logic that special-case array access to that single instruction also bypass any overload resolution involving extension methods and the like.
One way to circumvent this is to wrap the array in a custom type, where overloaded indexers will work as you expect. Making the wrapper type a struct should reduce the performance loss in most cases:
type [<Struct>] BigArray<'T>(array : 'T[]) =
member this.LengthI: bigint =
bigint array.Length
member this.Item
with get(index : int) = array.[index]
and set (index : int) value = array.[index] <- value
member this.Item
with get(index : bigint) = array.[int index]
and set (index : bigint) value = array.[int index] <- value
let bigArray = BigArray myArray
let bigArrayElement = bigArray.[0]
let bigArrayElement2 = bigArray.[bigint 0]
Another one is to upcast the array to the base System.Array class, on which you can then define the same overloaded operator. This removes the need to create a wrapper type and duplicate all members of 'T[], as you can just upcast/downcast the same array object as necessary. However, since the base class is untyped, you will lose type safety and have to box/unbox the elements when using the indexed access, which is quite ugly:
type System.Array with
member this.Item
with get (index : int) = (this :?> 'T[]).[index]
and set (index : int) (value : 'T) = (this :?> 'T[]).[index] <- value
member this.Item
with get(index : bigint) : 'T = (this :?> 'T[]).[int index]
and set(index : bigint) (value : 'T) = (this :?> 'T[]).[int index] <- value
let untypedArray = myArray :> System.Array
let untypedArrayElement = box untypedArray.[0] :?> string
let untypedArrayElement2 = box untypedArray.[bigint 0] :?> string

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

How do I iterate over a hashtable in F#?

let dic = Environment.GetEnvironmentVariables()
dic
|> Seq.filter( fun k -> k.Contains("COMNTOOLS"))
fails to compile.
I've tried using Array.filter, Seq.filter, List.filter
I've tried getting just the dic.Keys to iterate over but F# doesn't seem to want me to coerce a KeyCollection into an IEnumerable.
I've tried upcasting the hashtable into an IEnumerable<KeyValuePair<string,string>>
How do I walk the hashtable that is returned from Environment.GetEnvironmentVariables() ?
Since Environment.GetEnvironmentVariables() returns a non-generic IDictionary and it stores key/value pairs in DictionaryEntry, you have to use Seq.cast first:
let dic = Environment.GetEnvironmentVariables()
dic
|> Seq.cast<DictionaryEntry>
|> Seq.filter(fun entry -> entry.Key.ToString().Contains("COMNTOOLS"))
See the relevant docs at https://msdn.microsoft.com/en-us/library/system.collections.idictionary(v=vs.110).aspx. Notice that entry.Key is of type obj, so one has to convert to string before checking string containment.
Instead of using high-order functions, sequence expression might be handy:
let dic = Environment.GetEnvironmentVariables()
seq {
for entry in Seq.cast<DictionaryEntry> dic ->
(string entry.Key), (string entry.Value)
}
|> Seq.filter(fun (k, _) -> k.Contains("COMNTOOLS"))
F# Seq can only operate with System.Collections.Generic.IEnumerable<_>. System.IDictionary returned by Environment.GetEnvironmentVariables is not generic but it implements non-generic System.Collections.IEnumerable and not System.Collections.Generic.IEnumerable<_>. System.Collections.IEnumerable does not contain type information and allows enumeration of the collection of boxed types i.e. instances of System.Object.
Anyway System.IDictionary can be enumerated as collection of System.Collections.DictionaryEntry objects so you can simply call Seq.cast on it. It will give you access to Key and Value properties, yet still boxed as objects, so you should unbox them too.
let dic = System.Environment.GetEnvironmentVariables()
dic
|> Seq.cast<System.Collections.DictionaryEntry>
|> Seq.filter( fun k -> (k.Key :?> string).Contains("COMNTOOLS"))
Alternatively you can use the following function
let asStringPairSeq (d : System.Collections.IDictionary) : seq<string * string> =
Seq.cast<System.Collections.DictionaryEntry> d
|> Seq.map (fun kv -> kv.Key :?> string, kv.Value :?> string)
System.Environment.GetEnvironmentVariables()
|> asStringPairSeq
|> Seq.filter (fun (k,v) -> k.Contains("COMNTOOLS"))

Casting an object to a generic type without supplying the parameters

Say I have a code like this
let a = new List<int>()
let b = a :> obj :?> List<obj>
It throws an exception saying that it can't do it since one is List<int> while I'm trying to make it an List<obj>.
I understand why that's a problem. It can't just magically create an interface for me that replaces all int types with obj, but what CAN I do here?
I have an object and I know that's it's a List of something. How can I access the elements and just not care about their type?
My concrete example doesn't use Lists so I require a general, not a List specific, solution.
In case of lists you can use System.Collections.IList to access elements
open System.Collections
open System.Collections.Generic
let x = List<int>()
let y: IList = downcast (x :> obj)
This approach can also be generalized: make your generic classes implement non-generic interface:
type IT =
abstract Value: obj
type T<'a>(a: 'a) =
member val Value = a;
interface IT with
member this.Value = upcast this.Value
If this is not an option (i.e. because you cannot make changes in classes) you can always resort to reflection
type T<'a>(a: 'a) =
member val Value = a;
type Action =
static member Do(a: T<_>) = printfn "%A" a.Value
let v = T(10)
let mi = typeof<Action>.GetMethod("Do").MakeGenericMethod(v.GetType().GetGenericArguments().[0])
mi.Invoke(null, [|v|])

Resources