Dynamic Function Call in FSharp - function

Is it possible to take an FSharp function and convert it to a Dynamic function, alternatively is something like this coming to FSharp in the future?
let func (a:int) (b:int) : int =
a + b
let dynamicFunc = FSharpFunc.ToDynamicFunc(func)
let argumentList = [1; 2]
let object = dynamicFunc argumentList
let result = object :?> int
It appears that you currently have to fall back to standard reflection (like this: calling a F# function by name) however, this approach seems very brittle. Mainly because there's no real guarantee it works, and you have to know what's going on under the covers.
Something like this could be used to wrap any function and do things dynamically.
let wrapFun (x:'f) : 'f =
let args = FSharp.Reflection.FSharpType.GetFunctionElements <| x.GetType()
let runner (any:obj list) : obj =
// Do extra things
FSharpFunc.DynamicInvoke x
FSharp.Reflection.FSharpValue.MakeFunction (typeof<'f>, runner) :?> 'f

F# does support the dynamic call operator. But you must implement yours. Here is a sample Implementation taken from http://www.fssnip.net/2U/title/Dynamic-operator-using-Dynamic-Language-Runtime
// Reference C# implementation of dynamic operations
#r "Microsoft.CSharp.dll"
open System
open System.Runtime.CompilerServices
open Microsoft.CSharp.RuntimeBinder
// Simple implementation of ? operator that works for instance
// method calls that take a single argument and return some result
let (?) (inst:obj) name (arg:'T) : 'R =
// TODO: For efficient implementation, consider caching of call sites
// Create dynamic call site for converting result to type 'R
let convertSite =
CallSite<Func<CallSite, Object, 'R>>.Create
(Binder.Convert(CSharpBinderFlags.None, typeof<'R>, null))
// Create call site for performing call to method with the given
// name and a single parameter of type 'T
let callSite =
CallSite<Func<CallSite, Object, 'T, Object>>.Create
(Binder.InvokeMember
( CSharpBinderFlags.None, name, null, null,
[| CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null);
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) |]))
// Run the method call using second call site and then
// convert the result to the specified type using first call site
convertSite.Target.Invoke
(convertSite, callSite.Target.Invoke(callSite, inst, arg))
You'd be able to use it as follows
// Dynamically invoke 'Next' method of 'Random' type
let o = box (new Random())
let a : int = o?Next(10)
As for the params you'd have to pass them as a Tuple something like
target?method(param1, param2) that would mean that the target method processes its argument as a Tuple and as such, some pattern matching may or may not be involved

Related

How do I make a for loop that scans through JSON in F#

Using F# I am trying to scan through a JSON file and compare its arrays against a single array of (randomly generated) numbers. The formatting for the json is:
{"1":[#,#,#,#,#],"2":[#,#,#,#,#],...}
etc for 121 entries. I'm currently trying Json.NET. My problems are:
How can I import a local file with Json.NET?
How would I set about making a simple call of the json key that'd return it's array value that's fit to run it through a for loop?
Here is my code of how far I've gotten:
open System
open System.IO
open Newtonsoft.Json
(*open FSharp.Data
type Provider = JsonProvider<"powernum.json">
let numbers = Provider.Load("powernum.json")
//numbers.``1`` gets me the array but can't scan through all the IDs with an iterating for loop
(*
if numbers.``3`` = [|29;30;41;48;64|] then
printfn "True"
else printfn "False"
*)
(*numbers.JsonValue.Item "1"
let test (a: int) = string a
let testPile =
for i = 1 to 10 do
let goNum = numbers.JsonValue.Item (test i)
Console.Write goNum
Console.WriteLine ""
testPile // This works but is not usable for data comparison with an F# Array
*)
*)
let r = new StreamReader("\PATH\powernum.json")
let (json: string) = r.ReadToEnd();
let conv = JsonConvert.DeserializeObject<> (json)
Console.WriteLine("{0}",conv)//where I'm stuck with Json.NET
[<EntryPoint>]
let main argv =
let rnd = Random()
let numberGen = Set.empty.Add(rnd.Next(1,69)).Add(rnd.Next(1,69)).Add(rnd.Next(1,69)).Add(rnd.Next(1,69)).Add(rnd.Next(1,69)) |>Set.toArray |>Array.sort
Console.ReadKey() |> ignore
0// return an integer exit code
Jsontocsharp.com renders invalid.
I've tried using F# Data but from what I've found it's impossible to make an iterating loop because I have to pull up the "key" with accents encapsulating the number to read it as an int like this numbers.``1``.It doesn't take variables. Tried another method while still using F# Data but it only works as a string that errors when I try to convert it.
For comparison this is the version I prototyped in python:
import random
import json
with open('/PATH/powernum.json') as pnumbers:
data = json.load(pnumbers)
#makes an array with the range of numbers
Valid_numbers =[]
for x in range(69):
Valid_numbers.append(x+1)
generated = []
def pulledNumber():
generated[:]=[]
#adds numbers to the array from 0-4
while len(generated) !=5:
#takes a random number from the range of numbers
generate_number = random.choice(Valid_numbers)
#check if the two arrays have the same values
if generate_number not in generated:
#add to the array if values don't match
generated.append(generate_number)
generated.sort()
return generated
pulledNumber()
for x, y in data.items():
if generated not in y:
print("Id: %s passed" % x)
else:
print("Id: %s failed" % x)
pulledNumber()
break
print (pulledNumber())
f# is a statically typed language - we simply often don't notice because of its excellent type inferencing. But when deserializing from a JSON file, before writing any code, it is useful to determine whether the JSON has a fixed schema, and if so, create or choose an appropriate data model to which the JSON can be mapped automatically.
In your case, your JSON looks like:
{
"1": [29,30,41,48,64],
"2": [29,320,441,548,11]
// Additional items omitted
}
When you have here is a root object with variable property names whose values are always an array of integers. As explained in the Newtonsoft documentation Deserialize a Dictionary, such a JSON object can be deserialized to some IDictionary<string, T> for appropriate value type T. And as explained in Deserialize a Collection a JSON array can be deserialized to a collection of an appropriate item type.
In f# we use Map<'Key,'Value> to represent a dictionary, and lists to represent a materialized list of statically typed values. Thus your JSON corresponds to a
Map<string, int list>
Having determined an appropriate data model, introduce the following function to deserialize JSON from a file:
//https://www.newtonsoft.com/json/help/html/DeserializeWithJsonSerializerFromFile.htm
let jsonFromFile<'T>(fileName : string, settings : JsonSerializerSettings) =
use streamReader = new StreamReader(fileName)
use jsonReader = new JsonTextReader(streamReader)
let serializer = JsonSerializer.CreateDefault(settings)
serializer.Deserialize<'T>(jsonReader)
Now you can deserialize your JSON and filter the values for lists matching some
let fileName = "\PATH\powernum.json"
let requiredValues = [29;30;41;48;64] // Or whatever list of values you are looking for
let map = jsonFromFile<Map<string, int list>>(fileName, null)
let filteredMap =
map |> Map.toSeq
|> Seq.filter (fun (key, value) -> requiredValues = value)
|> Map.ofSeq
// Print results
filteredMap |> Map.iter (fun key value ->
printf "Key = %A has matching list of values = %A\n" key value)
Which prints out
Key = "1" has matching list of values = [29; 30; 41; 48; 64]
Notes:
Always be sure to dispose of disposable resources such as StreamReader after you are done with them. The use keyword ensures this happens automatically when the resource goes out of scope.
If you would prefer to search for an unordered set of values, you can use set instead of list:
let requiredValues = set [64;29;30;41;48] // Or whatever set of values you are looking for
let map = jsonFromFile<Map<string, Set<int>>>(fileName, null)
let filteredMap =
map |> Map.toSeq
|> Seq.filter (fun (key, value) -> requiredValues = value)
|> Map.ofSeq
As explained in Equality and Comparison Constraints in F# by Don Syme, both list and set support structural equality comparisons, which is why requiredValues = value checks that the collections have identical contents.
Demo fiddle #1 here for list and #2 here for set.

convert sqlprovider typed object to json string

I am trying without success to convert the type provided by the sqlprovider to json.
I have a method:
let getAll () =
query {
for c in db.MyDb.Table do
select c
}
then I call it with Newtonsoft.Json as such:
JsonConvert.SerializeObject(getAll ())
What I get is a string with a empty object: [{}]
If I create a type by hand, it works all right. It works as well if I am selecting a primitive type and a single attribute, like c.something.
I guess I am missing something basic (hopefully ;))
This type of usage was referred to in Issue 212. Because the generated SqlEntity type is not something the Json serializer knows about, it won't be able to deal with it directly. One way to get around this is to define record types for the tables (which might not be pleasant for large tables). So for example:
type DataRec' = {
DT:DateTime
ADAY:String
ID:System.Int64
}
let qry = query { for row in table1 do
select row} |> Seq.map (fun x -> x.MapTo<DataRec'>())
JsonConvert.SerializeObject(qry |> Seq.toList)
val it : string =
"[{"DT":"2016-09-27T00:00:00","ADAY":"Tuesday","ID":8},{"DT":"2016-09-26T00:00:00","ADAY":"Monday","ID":9},{"DT":"2016-09-25T00:00:00","ADAY":"Sunday","ID":10},{"DT":"2016-09-24T00:00:00","ADAY":"Saturday","ID":11},{"DT":"2016-09-27T00:00:00","ADAY":"Tuesday","ID":12},{"DT":"2016-09-24T00:00:00","ADAY":"Saturday","ID":13},{"DT":"2016-09-24T00:00:00","ADAY":"Saturday","ID":14},{"DT":"2016-09-23T00:00:00","ADAY":"Friday","ID":15},{"DT":"2016-09-25T00:00:00","ADAY":"Sunday","ID":16},{"DT":"2016-09-26T00:00:00","ADAY":"Monday","ID":17}]"

F#: Saving JSON data

I am new to programming and F# is my first language.
Here are the relevant parts of my code:
let internal saveJsonToFile<'t> (someObject:'t) (filePath: string) =
use fileStream = new FileStream(filePath, FileMode.OpenOrCreate)
(new DataContractJsonSerializer(typeof<'t>)).WriteObject(fileStream, someObject)
let testList = new List<Fighter>()
saveJsonToFile testList<Fighter> #"G:\User\Fighters.json"
I have previously created an F# record of type Fighter.
When I try to run "saveJsonToFile testList #"G:\User\Fighters.json"", "testList" is underscored in red with the error message: "Unexpected type arguments".
What went wrong? What am I missing?
First, your testList is a value, not a function.
Second, it doesn't have a generic argument, everything in its body is concrete.
If you want it to be a function, give it a parameter.
If you want it to be generic, say so in the body.
let testList () = new List<'a>()
saveJsonToFile testList<Fighter>() #"G:\User\Fighters.json"
And finally, the List you're trying to create probably resolves to F#'s own List, which is a module, not a type.
If you meant to create the .NET's System.Collections.Generic.List, then you need to specify the full type name:
let testList () = new System.Collections.Generic.List<'a>()
But if you meant to create an F# native list, use one of its constructors:
let testList () = []

How to use tuples effectively in function?

Swift programming book says,
By returning a tuple with two distinct values, each of a different
type, the function provides more useful information about its outcome
than if it could only return a single value of a single type.
Excerpt From: Apple Inc. “The Swift Programming Language.” iBooks. https://itun.es/gb/jEUH0.l
I searched on internet but couldn't find any examples of it.So I tried myself like example below, but if you've got better please let me know.. Thanks in advance.
var statusCode = 404
var statusMessage = "No Site"
let http404 = ( sCode : statusCode , sMessage : statusMessage)
func responseFromWS (foo : Int, bar : String) -> (param1 : Int, param2 : String)
{
statusCode = foo
statusMessage = bar
let httpProtocol = ( statusCode , statusMessage)
return httpProtocol
}
responseFromWS(500, "Internal Server Error")
In other languages (including objective c) you can return one value only (of any type), but in some cases you might need to return more than one value.
The pattern usually applied in those cases is to pass references to variables to the function for all additional return values - a typical case is a reference to a NSError * variable, which the function either sets to nil if no error occurs, or to an instance of NSError in case of error.
Such problem is elegantly solved in swift using multiple return values packed in a tuple.
The way you are using this features seems correct, but what's wrong is defining the statusCode and statusMessage variables outside the function scope:
func responseFromWS (foo : Int, bar : String) -> (code: Int, message: String)
{
let statusCode: Int = foo
let statusMessage: String = bar
return (code: statusCode, message: statusMessage)
// Note: you can also write as follows, because the parameter names are defined in the function signature
// return (statusCode, statusMessage)
}
You can use the return value in different ways. As a tuple:
let response = responseFromWS(500, "Internal Server Error")
// Using named parameters
println(response.code) // Prints 500
println(response.message) // Prints "Internal Server Error"
// using parameters by index
println(response.0) // Prints 500
println(response.1) // Prints "Internal Server Error"
As individual variables:
let (code, message) = responseFromWS(500, "Internal Server Error")
println(code)
println(message)
As a subset of individual variables (if you need only a subset of the returned values):
// Assign message only, discard code
let (_, message) = responseFromWS(500, "Internal Server Error")
println(message)
In addition to the uses mentioned by #Antonio, I have used them to return "pseudo-structs" where a function calculates several values, but the definition of a new struct type would really not be used anywhere else.
An example: when calculating true bearing and distance on the surface of the earth, one may choose to return some kind of polar coordinate struct, but the reverse azimuth (not a trivial relation in true geodesy) is also calculated as a by product. In implementations in other languages I have done this by defining a struct type to return the three doubles - but this struct type is never used except to call this function! Better to say
let (distance, azimuth, reverseAzimuth) = coordinate(vectorTo: otherCoordinate)
than having your future self look up the definition of and then unpack some obscure struct.

How to JSON serialize math vector type in F#?

I'm trying to serialize "vector" (Microsoft.FSharp.Math) type. And I get that error:
Exception Details: System.Runtime.Serialization.SerializationException: Type 'Microsoft.FSharp.Math.Instances+FloatNumerics#115' with data contract name 'Instances.FloatNumerics_x0040_115:http://schemas.datacontract.org/2004/07/Microsoft.FSharp.Math' is not expected. Add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.
I have tried to put KnownType attribute and some other stuff, but nothing helps!
Could someone know the answer?
This is the code I use:
// [< KnownType( typeof<vector> ) >]
type MyType = vector
let public writeTest =
let aaa = vector [1.1;2.2]
let serializer = new DataContractJsonSerializer( typeof<MyType> )
let writer = new StreamWriter( #"c:\test.txt" )
serializer.WriteObject(writer.BaseStream, aaa)
writer.Close()
I think that F# vector type doesn't provide all the necessary support for JSON serialization (and is quite a complex type internally). Perhaps the best thing to do in your case would be to convert it to an array and serialize the array (which will also definitely generate shorter and more efficient JSON).
The conversion is quite straightforward:
let aaa = vector [1.1;2.2]
let arr = Array.ofSeq aaa // Convert vector to array
// BTW: The 'use' keyword behaves like 'using' in C#
use writer = new StreamWriter( #"c:\test.txt" )
let serializer = new DataContractJsonSerializer()
serializer.WriteObject(writer.BaseStream, aaa)
To convert the array back to vector, you can use Vector.ofSeq (which is a counterpart to Array.ofSeq used in the example above).
You can also use:
let v = vector [1.;3.];
let vArr = v.InternalValues
to get the internal array of the vector. In this way, you don't need to create a temporary array.
Types, RowVector, Matrix also has this method to get the internal arrays.