Firstly, obtain a schema and parse:
type desc = JsonProvider< """[{"name": "", "age": 1}]""", InferTypesFromValues=true >
let json = """[{"name": "Kitten", "age": 322}]"""
let typedJson = desc.Parse(json)
Now we can access typedJson.[0] .Age and .Name properties, however, I'd like to pattern match on them at compile-time to get an error if the schema is changed.
Since those properties are erased and we cannot obtain them at run-time:
let ``returns false``() =
typedJson.[0].GetType()
.FindMembers(MemberTypes.All, BindingFlags.Public ||| BindingFlags.Instance,
MemberFilter(fun _ _ -> true), null)
|> Array.exists (fun m -> m.ToString().Contains("Age"))
...I've made a runtime-check version using active patterns:
let (|Name|Age|) k =
let toID = NameUtils.uniqueGenerator NameUtils.nicePascalName
let idk = toID k
match idk with
| _ when idk.Equals("Age") -> Age
| _ when idk.Equals("Name") -> Name
| ex_val -> failwith (sprintf "\"%s\" shouldn't even compile!" ex_val)
typedJson.[0].JsonValue.Properties()
|> Array.map (fun (k, v) ->
match k with
| Age -> v.AsInteger().ToString() // ...
| Name -> v.AsString()) // ...
|> Array.iter (printfn "%A")
In theory, if FSharp.Data wasn't OS I wouldn't be able to implement toID. Generally, the whole approach seems wrong and redoing the work.
I know that discriminated unions can't be generated using type providers, but maybe there's a better way to do all this checking at compile-time?
As far as I know it cannot be possible to find out if "Json schema has changed" at compile-time using the given TP.
That's why:
JsonProvider<sample> is exactly what kicks in at compile-time providing a type for manipulating Json contents at run-time. This provided erased type has couple of run-time static methods common for any sample and type Root
extending IJsonDocument with few instance properties including ones based on compile-time provided sample (in your case - properties Name and Age).There is exactly one very relaxed implicit
Json "schema" behind JsonProvider-provided type, no another such entity to compare with for change at compile-time;
at run-time only provided type desc with its static methods and its Root type with correspondent instance methods
are at your service for manipulating arbitrary Json contents. All this jazz is pretty much agnostic with regard to
"Json schema", in your given case as long as run-time Json contents represent an array its elements may be pretty much any.
For example,
type desc = JsonProvider<"""[{"name": "", "age": 1}]"""> // # compile-time
let ``kinda "typed" json`` = desc.Parse("""[]""") // # run-time
let ``another kinda "typed" json`` =
desc.Parse("""[{"contents":"whatever", "text":"blah-blah-blah"},[{"extra":42}]]""")
both will be happily parsed at run-time as "typed Json" conforming to "schema" derived by TP from the given sample, although apparently Name and Age are missing and exceptions will be raised if accessed.
It is doable building another Json TP that relies upon a formal Json schema.
It may consume reference to the given schema from a schema repository upon type creation and allow manipulating elements
of the parsed Json payload only via provided accessors derived from the schema at compile-time.
In this case change of the
referred schema may break compilation if provided accessors being used in the code are incompatible with the change.
Such arrangement accompanied by run-time Json payload validator or validating parser may provide reliable enterprise-quality
Json schema change management.
JsonProvider TP from Fsharp.Data lacks such Json schema handling abilities, so payload validations are to be done in run-time only.
Quoting your comments which explain a little better what you are trying to achieve:
Thank you! But what I'm trying to achieve is to get a compiler error
if I add a new field e.g. Color to the json schema and then ignore it
while later processing. In case of unions it would be instant FS0025.
and:
yes, I must process all fields, so I can't rely on _. I want it so
when the schema changes, my F# program won't compile without adding
necessary handling functionality(and not just ignoring new field or
crashing at runtime).
The simplest solution for your purpose is to construct a "test" object.
The provided type comes with two constructors: one takes a JSonValue and parses it - effectively the same as JsonValue.Parse - while the other requires every field to be filled in.
That's the one that interests us.
We're also going to invoke it using named parameters, so that we'll be safe not only if fields are added or removed, but also if they are renamed or changed.
type desc = JsonProvider< """[{"name": "SomeName", "age": 1}]""", InferTypesFromValues=true >
let TestObjectPleaseIgnore = new desc.Root (name = "Kitten", age = 322)
// compiles
(Note that I changed the value of name in the sample to "SomeName", because "" was being inferred as a generic JsonValue.)
Now if more fields suddenly appear in the sample used by the type provider, the constructor will become incomplete and fail to compile.
type desc = JsonProvider< """[{"name": "SomeName", "age": 1, "color" : "Red"}]""", InferTypesFromValues=true >
let TestObjectPleaseIgnore = new desc.Root (name = "Kitten", age = 322)
// compilation error: The member or object constructor 'Root' taking 1 arguments are not accessible from this code location. All accessible versions of method 'Root' take 1 arguments.
Obviously, the error refers to the 1-argument constructor because that's the one it tried to fit, but you'll see that now the provided type has a 3-parameter constructor replacing the 2-parameter one.
If you use InferTypesFromValues=false, you get a strong type back:
type desc = JsonProvider< """[{"name": "", "age": 1}]""", InferTypesFromValues=false >
You can use the desc type to define active patterns over the properties you care about:
let (|Name|_|) target (candidate : desc.Root) =
if candidate.Name = target then Some target else None
let (|Age|_|) target (candidate : desc.Root) =
if candidate.Age = target then Some target else None
These active patterns can be used like this:
let json = """[{"name": "Kitten", "age": 322}]"""
let typedJson = desc.Parse(json)
match typedJson.[0] with
| Name "Kitten" n -> printfn "Name is %s" n
| Age 322m a -> printfn "Age is %M" a
| _ -> printfn "Nothing matched"
Given the typedJson value here, that match is going to print out "Name is Kitten".
<tldr>
Build some parser to handle your issues. http://www.quanttec.com/fparsec/
</tldr>
So...
You want something that can read something and do something with it. Without knowing apriori what any of those somethings is.
Good luck with that one.
You do not want type provider to do this for you. Type providers are made with the full purpose of being "at compile time this is what I saw, and thats what I will use".
With that said:
You want some other type of parser, where you are able to check the "schema" (some definition of what you know is going to come or you saw last time vs. what actually came). In effect some dynamic parser getting the data to some dynamic structure, with dynamic types.
And mind you, dynamic is not static. F# has static types and a lot is based on that. And type providers more so. Fighting that will make your head ache. It is of course possible, and it might even be possible by fighting the type providers to actually work with such an approach, but then again its not really a type provider nor its purpose.
Related
I have written several helper functions in F# that enable me to deal with the dynamic nature of Excel over the COM/PIA interface. However when I go to use these functions in an Excel-DNA UDF they do not work as expected as Excel-DNA is pre-processing the values in the array from excel.
e.g. null is turned into ExcelDna.Integration.ExcelEmpty
This interferes with my own validation code that was anticipating a null. I am able to work around this by adding an additional case to my pattern matching:
let (|XlEmpty|_|) (x: obj) =
match x with
| null -> Some XlEmpty
| :? ExcelDna.Integration.ExcelEmpty -> Some XlEmpty
| _ -> None
However it feels like a waste to convert and then convert again. Is there a way to tell Excel-DNA not to do additional processing of the range values in a UDF and supply them equivalent to the COM/PIA interface? i.e. Range.Value XlRangeValueDataType.xlRangeValueDefault
EDIT:
I declare my arguments as obj like this:
[<ExcelFunction(Description = "Validates a Test Table Row")>]
let isTestRow (headings: obj) (row: obj) =
let validator = TestTable.validator
let headingsList = TestTable.testHeadings
validateRow validator headingsList headings row
I have done some more digging and #Jim Foye's suggested question also confirms this. For UDF's, Excel-DNA works over the C API rather than COM and therefore has to do its own marshaling. The possible values are shown in this file:
https://github.com/Excel-DNA/ExcelDna/blob/2aa1bd9afaf76084c1d59e2330584edddb888eb1/Distribution/Reference.txt
The reason to use ExcelEmpty (the user supplied an empty cell) is that for a UDF, the argument can also be ExcelMissing (the user supplied no argument) which might both be reasonably null and there is a need to disambiguate.
I will adjust my pattern matching to be compatible with both the COM marshaling and the ExcelDNA marshaling.
this is a basic question but i could not find the simple answer reading the tutorial
suppose i have this simple frame
type Person =
{ Name:string; Age:int; Countries:string list; }
let peopleRecds =
[ { Name = "Joe"; Age = 51; Countries = [ "UK"; "US"; "UK"] }
{ Name = "Tomas"; Age = 28; Countries = [ "CZ"; "UK"; "US"; "CZ" ] }
{ Name = "Eve"; Age = 2; Countries = [ "FR" ] }
{ Name = "Suzanne"; Age = 15; Countries = [ "US" ] } ]
// Turn the list of records into data frame
let peopleList = Frame.ofRecords peopleRecds
// Use the 'Name' column as a key (of type string)
let people = peopleList |> Frame.indexRowsString "Name"
How do i access the value the row for Joe ? (as a record, tuple or whatever format)
i tried this
getRow "Joe" people;;
Stopped due to error System.Exception: Operation could not be
completed due to earlier error Value restriction. The value 'it' has
been inferred to have generic type
val it : Series Either define 'it' as a simple data term, make it a function with explicit arguments or, if you do
not intend for it to be generic, add a type annotation. at 3,0
EDIT: thanks for the answer, still i would like to know why my syntax is incorrect because i think i respected the signature
val it :
('a -> Frame<'a,'b> -> Series<'b,'c>) when 'a : equality and 'b : equality
I'll answer the second half of your question, why you got a "value restriction" error. If you search for [f#] value restriction on Stack Overflow you'll find lots of answers, which may or may not confuse you. But the really short version is: F# is built on top of the .Net framework, and .Net imposes certain limitations. Specifically, functions are allowed to be generic, but values cannot be generic. So you can do this:
let f<'TData> (a:'TData) = printfn "%A" a
but you cannot do this:
let (a:'TData) = Unchecked.defaultof<'TData>
The function definition is fine, because the underlying .Net framework knows how to handle generic functions. But you're not allowed to have generic values in .Net; any value must be a specific type.
(Note: I wrote the <'TData> in the f definition explicitly, but I didn't have to: I could have just written let f (a:'TData) = printfn "%A" a and the genericness of f would have still been understood. I could even have just written let f a = printfn "%A" a, and it would have done the same thing).
Now let's look at the error you got: "the value "it" has been inferred to have generic type val it : Series<string,obj>". If you look at the function signature of getRow that you posted, it looks like this:
('a -> Frame<'a,'b> -> Series<'b,'c>)
When you called it as getRow "Joe" people, the F# compiler was able to infer that the type 'a was string (because the parameter "Joe" is a string). And because the second argument people is a Frame<string,string>, the F# compiler was able to infer that the type 'b was also string. But the result of that function call is a Series<'b,'c>, and so far the F# compiler doesn't know anything about what 'c will be. And since you ran getRow "Joe" people at the F# interactive REPL, it tried to store the result of what you typed as the value of the name it (the F# interactive REPL always provides the value of the previous expression as it) -- but since the only type it knew so far was Series<string,'c>, F# couldn't figure out what specific type to assign to the value it. I know from looking at your code that the type 'c was the Person record, but the F# compiler couldn't know that from just that one call to getRow, because of how the getRow function is typed.
There are two ways you could have solved this value restriction error:
One way to solve this would have been to pipe the result of getRow into another function, which would have allowed the F# compiler to infer the specific type of its result. Unfortunately, since I don't know Deedle that well, I can't give you a good example here. Maybe someone else will come up with one and comment on this answer, and I'll edit it in. It would look like:
getRow "Joe" people |> (some Deedle function)
But I don't know which Deedle function to use in my example: it would have to be a function that takes a Series and does some specific calculation with it, in a way that would allow F# to infer that this is a Series<string,Person>. Sorry this isn't a great example, but I'll leave it in anyway in case it helps.
The second way you could have solved the error would have been to specify the type of the value you were getting. In F#, you do that with the : (type) syntax, e.g.:
getRow "Joe" people : Series<string,Person>
Or, since the F# compiler has enough information to infer the string part of that type, you could also have written:
getRow "Joe" people : Series<_,Person>
When you write _ in a type signature, you're telling the F# compiler "You figure out what type this is". This only works when the F# compiler has enough information to infer that type correctly, but it's often a handy shorthand when type signatures would be large and unwieldy.
Both of these approaches would have solved your immediate problem, gotten rid of the "value restriction" error, and allowed you to continue working.
I hope this answer helps you. If it hopelessly confuses you instead, let me know and I'll see if I can explain whatever has you confused.
EDIT: In the comments, Soldalma asks whether the F# compiler (which is a one-pass compiler that works top to bottom and left to right) can infer the type from a forward pipe. The answer is yes, because the expression isn't finished yet. As long as an expression isn't finished, F#'s type inference (which is based on the Hindley-Milner type system*) is fine with carrying around a set of not-yet-resolved types. And if the types are resolved before the expression is complete, then the expression can resolve to a specific value (or a specific function). If the types are not yet resolved when the expression is complete, then it has to resolve to a generic value or function. And generic functions are allowed in .Net, but not generic values, hence the "value restriction" error.
To see this in practice, let's look at some example code. Copy and paste the following code into an F# editor that lets you hover over a variable (or function) name to see its type. I recommend VS Code with the Ionide-fsharp extension since it's cross-platform, but Visual Studio will work just as well.
open System.Collections.Generic
let mkDict (key:'K) = new Dictionary<'K,'V>() // Legal
let getValueOrDefault (key:'a) (defaultVal:'b) (dict:Dictionary<'a,'b>) =
match dict.TryGetValue key with
| true,v -> v
| false,_ -> defaultVal
let d = mkDict "foo" // Error: value restriction
let bar = mkDict "foo" |> getValueOrDefault "foo" "bar" // Legal: type string
let five = mkDict "foo" |> getValueOrDefault "foo" 5 // Legal: type int
Go ahead and hover your cursor over each function and variable name to see its type, or else hit Alt+Enter to send each function or variable declaration to F# Interactive. (And once you've seen that the let d line gives a "value restriction" error, comment it out so the rest of the code will compile).
What's happening here is a good demonstration of how this all works. The mkDict function has two unresolved types, 'K and 'V, so it has to be generic. But that's fine, because .Net has no problem with generic functions. (mkDict isn't actually very useful, since it actually "throws away" the data of its argument and does nothing to it. But it's supposed to be a trivial example, so just ignore the fact that it's kind of useless.) Likewise, getValueOrDefault has two unresolved types, 'a and 'b, so it's also a generic function.
However, let d = mkDict "foo" is not legal. Here, the generic type 'K has been resolved to be the specific type string, but 'V has not yet been resolved by the time the expression is complete so d would have to be generic (it would look like d<'V> in explicitly-generic syntax). But d is not a function (since it has no parameters), it's the name of a value, and .Net doesn't allow generic values.
But in the next two lines, the expression is not complete by the time the compiler has parsed mkDict "foo", so it doesn't yet have to "lock in" the unknown types. It can quite happily carry the unresolved type 'V into the next part of the expression. And there, the getValueOrDefault function has two specific types, string and string in the first line, and string and int in the second line. Because its 'b type corresponds to the 'V type from mkDict, therefore F# can resolve 'V in both lines. And so bar has type string, and five has type int.
* Scott Wlaschin says that it should "more accurately ... be called "Damas-Milner's Algorithm W" ". Since I haven't studied it in detail myself, I'll take his word for it -- but if you're interested in learning more, the Wikipedia link I provided is probably a halfway decent starting point.
I'll be very short, promoting my comment to an answer.
You need to use syntax reverse to the one you have tried:
people.Rows.["Joe"]
I have a function that will create a select where clause, but right now everything has to be a string.
I would like to look at the variable passed in and determine what type it is and then treat it properly.
For example, numeric values don't have single quotes around them, option type will either be null or have some value and boolean will actually be zero or one.
member self.BuildSelectWhereQuery (oldUser:'a) = //'
let properties = List.zip oldUser.ToSqlValuesList sqlColumnList
let init = false, new StringBuilder()
let anyChange, (formatted:StringBuilder) =
properties |> Seq.fold (fun (anyChange, sb) (oldVal, name) ->
match(anyChange) with
| true -> true, sb.AppendFormat(" AND {0} = '{1}'", name, oldVal)
| _ -> true, sb.AppendFormat("{0} = '{1}'", name, oldVal)
) init
formatted.ToString()
Here is one entity:
type CityType() =
inherit BaseType()
let mutable name = ""
let mutable stateId = 0
member this.Name with get() = name and set restnameval=name <- restnameval
member this.StateId with get() = stateId and set stateidval=stateId <- stateidval
override this.ToSqlValuesList = [this.Name; this.StateId.ToString()]
So, if name was some other value besides a string, or stateId can be optional, then I have two changes to make:
How do I modify ToSqlValuesList to
have the variable so I can tell the
variable type?
How do I change my select function
to handle this?
I am thinking that I need a new function does the processing, but what is the best FP way to do this, rather than using something like typeof?
You can use a type test pattern in a match. Would this meet your needs?
let f (x : obj) =
match x with
| :? int -> "int"
| :? string -> "string"
| :? bool -> "bool"
| _ -> "who knows?"
I think that one clear functional approach would be to define a data type that represents the various (more complicated situations) that you need to handle. You mentioned that a value may be optional and that you need to distinguish numeric and textual values (for the encoding to SQL).
You could define a discriminated union (if there are other cases that you'd like to handle, the definition may be a bit more complicated):
type SqlValue =
| Missing
| Numeric of string
| Textual of string
Note that the Textual case also carries string, because I assume that the client who produces the value takes care of converting it to string - this is only information for your SQL query generator (so that it knows whether it needs to add quotes).
Your ToSqlValuesList member would return a list of values string & SqlValue, so for example, a sample product could be represented using the following list:
columns = [ "Name"; "Price"; "Description" ]
values = [ Textual("Tea"); Numeric(10); Missing ]
In the code that generates the SQL query, you'd use pattern matching to handle all the different cases (most importantly, encode string to avoid SQL injection in case the value is Textual :-)).
EDIT You'd need to implement the conversion from the specific data types to the SqlValue representation in every client. However, this can be simplified by writing a utility type (using the fact that members can be overloaded):
type SqlValue with
static member From(a:int) = Numeric(a.ToString())
static member From(a:int option) =
match a with None -> Missing | Some(n) -> SqlValue.From(n)
// ... similarly for other types
In the implementation of ToSqlValuesList, you would write SqlValue.From(description) and it would deal with the details autoamtically.
A more sophisticated approach would be to annotate public members of the types representing your data entities with .NET attributes and use Reflection to extract the values (and their types) at runtime. This is more advanced, but quite elegant (there is a nice exmaple of this technique in Don Syme's Expert F# book)
So, by a hilarious series of events, I downloaded the FParsec source and tried to build it. Unfortunately, it's not compatible with the new 1.9.9.9. I fixed the easy problems, but there are a couple of discriminated unions that still don't work.
Specifically, Don Syme's post explains that discriminated unions containing items of type obj or -> don't automatically get equality or comparison constraints, since objects don't support comparison and functions don't support equality either. (It's not clear whether the automatically generated equality/comparison was buggy before, but the code won't even compile now that they're no longer generated.)
Here are some examples of the problematic DUs:
type PrecedenceParserOp<'a,'u'> =
| PrefixOp of string * Parser<unit,'u> * int * bool * ('a -> 'a)
| others ...
type ErrorMessage =
| ...
| OtherError of obj
| ...
Here are the offending uses:
member t.RemoveOperator (op: PrecedenceParserOp<'a, 'u>) =
// some code ...
if top.OriginalOp <> op then false // requires equality constraint
// etc etc ...
or, for the comparison constraint
let rec printMessages (pos: Pos) (msgs: ErrorMessage list) ind =
// other code ...
for msg in Set.ofList msgs do // iterate over ordered unique messages
// etc etc ...
As far I can tell, Don's solution of tagging each instance with a unique int is the Right Way to implement a custom equality/comparison constraint (or a maybe a unique int tuple so that individual branches of the DU can be ordered). But this is inconvenient for the user of the DU. Now, construction of the DU requires calling a function to get the next stamp.
Is there some way to hide the tag-getting and present the same constructors to users of the library? That is, to change the implementation without changing the interface? This is especially important because it appears (from what I understand of the code) that PrecedenceParserOp is a public type.
What source did you download for FParsec? I grabbed the latest from the FParsec BitBucket repository, and I didn't have to make any changes at all to the FParsec source to get it to compile in VS 2010 RC.
Edit: I take that back. I did get build errors from the InterpLexYacc and InterpFParsec sample projects, but the core FParsec and FParsecCS projects build just fine.
One thing you could do is add [<CustomEquality>] and [<CustomComparison>] attributes and define your own .Equals override and IComparable implementation. Of course, this would require you to handle the obj and _ -> _ components yourself in an appropriate way, which may or may not be possible. If you can control what's being passed into the OtherError constructor, you ought to be able to make this work for the ErrorMessage type by downcasting the obj to a type which is itself structurally comparable. However, the PrecendenceParserOp case is a bit trickier - you might be able to get by with using reference equality on the function components as long as you don't need comparison as well.
Why aren't option types like "int option" compatible with nullable types like "Nullable"?
I assume there is some semantic reason for the difference, but I can't figure what that is.
An option in F# is used when a value may or may not exist. An option has an underlying type and may either hold a value of that type or it may not have a value.
http://msdn.microsoft.com/en-us/library/dd233245%28VS.100%29.aspx
That sure sounds like the Nullable structure.
Because of the runtime representation choice for System.Nullable<'T>.
Nullable tries to represent the absent of values by the null pointer, and present values by pointers to those values.
(new System.Nullable<int>() :> obj) = null
|> printfn "%b" // true
(new System.Nullable<int>(1) :> obj).GetType().Name
|> printfn "%s" // Int32
Now consider strings. Unfortunately, strings are nullable. So this is valid:
null : string
But now a null runtime value is ambiguous - it can refer to either the absence of a value or a presence of a null value. For this reason, .NET does not allow constructing a System.Nullable<string>.
Contrast this with:
(Some (null : string) :> obj).GetType().Name
|> printfn "%s" // Option`1
That being said, one can define a bijection:
let optionOfNullable (a : System.Nullable<'T>) =
if a.HasValue then
Some a.Value
else
None
let nullableOfOption = function
| None -> new System.Nullable<_>()
| Some x -> new System.Nullable<_>(x)
If you observe the types, these functions constrain 'T to be a structure and have a zero-argument constructor. So perhaps F# compiler could expose .NET functions receiving/returning Nullable<'T> by substituting it for an Option<'T where 'T : struct and 'T : (new : unit -> 'T)>, and inserting the conversion functions where necessary..
The two have different semantics. Just to name one, Nullable is an idempotent data constructor that only works on value types, whereas option is a normal generic type. So you can't have a
Nullable<Nullable<int>>
but you can have an
option<option<int>>
Generally, though there are some overlapping scenarios, there are also things you can do with one but not the other.
Key difference is that must test the option type to see if it has a value. See this question for a good description of its semantics: How does the option type work in F#
Again, this is from my limited understanding, but the problem probably lies in how each gets rendered in the IL. The "nullable" structure probably gets handled slightly different from the option type.
You will find that the interactions between various .Net languages really boils down to how the IL gets rendered. Mostof the time it works just fine but on occasion, it causes issues. (check out this). Just when you thought it was safe to trust the level of abstraction. :)