I have an ugly debugging function for printing a 3 level map, in fact they're dictionaries. I've been trying to convert it so that I can print off an n-level map. This is my attempt so far:
open System.Text
open System.Collections.Generic
let rec PrintMap x =
let PrintVal (v: obj) = match v with
| :? seq<KeyValuePair<_,_>> as vm -> "{ " + PrintMap vm + " }"
| _ -> sprintf "Value: %s" (v.ToString())
let sb = StringBuilder()
for KeyValue(key,value) in x do
sb.AppendLine(sprintf "%s => %s" (key.ToString()) (PrintVal value)) |> ignore
sb.ToString()
type dict3 = Dictionary<string,obj>
type dict2 = Dictionary<string,dict3>
type dict1 = Dictionary<string,dict2>
let k1 = "k1"
let k2 = "k2"
let k3 = "k3"
let v = "foo" :> obj
let dict = dict1()
dict.[k1] <- dict2()
dict.[k1].[k2] <- dict3()
dict.[k1].[k2].[k3] <- v
printf "%s" (PrintMap dict)
I'd rather not switch the nested dictionaries to their F# equivalents (at least for input) as the real thing deals with them.
You can probably deduce from what I'm almost certain is a naive attempt at an Active Pattern, not even mentioning the StringBuilder
, that I'm quite new to F#. It seems my difficulty is telling the difference between a dictionary and 'everything else' when looking at the value, and informing the type inference system that the values aren't the same type as the dictionary in the 'x' parameter.
Any hints?
Thankyou!
Edit
A small elaboration --- sometimes I get just a dict2
or dict3
type instead of the full dict1
so that's one of the reasons I'm trying to make this more generic.
Solution
Thanks to Daniel:
let rec PrintMap x =
let PrintVal (v: obj) = match v with
| :? IDictionary as vd -> "{ " + PrintMap vd + " }"
| _ -> sprintf "%s" (v.ToString())
let sb = StringBuilder()
for key in x.Keys do
sb.AppendLine(sprintf "%s => %s" (key.ToString()) (PrintVal x.[key])) |> ignore
sb.ToString()
The output is pretty ugly, but it certainly works. With the above input dictionary:
k1 => { k2 => { k3 => foo
}
}