The following code creates an array of simple binary trees and attempts to serialize and deserialize it. However, I don't know how to convert the object created by formatter.Deserialize(fso) back to an array of trees. I just get the error "This expression was expected to have type Tree array but here has type obj."
type Tree = | Branch of (string*float)*(Tree*Tree)
| Leaf of float
let trees = [|Branch (("x1", 0.), (Leaf 0., Leaf 1.)); Branch (("x2", 0.), (Leaf 0., Leaf 1.))|]
//Serialize
let filename = "C:/tree.dat"
let fs = new FileStream(filename, FileMode.Create)
let formatter = new BinaryFormatter()
formatter.Serialize(fs, trees)
fs.Close()
//Deserialize
let fso = new FileStream(filename, FileMode.Open)
let (trees2:array<Tree>) = formatter.Deserialize(fso)
fso.Close()
let trees2 = formatter.Deserialize(fso) :?> Tree[]
The result of formatter.Deserialize is obj which doesn't match the type array<Tree>, and so you need a downcast:
...
let trees2 = formatter.Deserialize(fso) :?> array<Tree>
or
let (trees2:array<Tree>) = downcast formatter.Deserialize(fso)
Related
I am trying to use openCL with FSCL on F# but I am obtaining some errors that I don't understand
open FSCL.Compiler
open FSCL.Language
open FSCL.Runtime
open Microsoft.FSharp.Linq.RuntimeHelpers
open System.Runtime.InteropServices
[<StructLayout(LayoutKind.Sequential)>]
type gpu_point2 =
struct
val mutable x: float32
val mutable y: float32
new ( q ,w) = {x=q; y=w}
end
[<ReflectedDefinition>]
let PointSum(a:gpu_point2,b:gpu_point2) =
let sx =(a.x+b.x)
let sy =(a.y+b.y)
gpu_point2(sx,sy)
[<ReflectedDefinition;Kernel>]
let Modgpu(b:float32[], c:float32[],wi:WorkItemInfo) =
let gid = wi.GlobalID(0)
let arp = Array.zeroCreate<gpu_point2> b.Length
let newpoint = gpu_point2(b.[gid],c.[gid])
arp.[gid] <- newpoint
arp
[<ReflectedDefinition;Kernel>]
let ModSum(a:gpu_point2[],b:gpu_point2[],wi:WorkItemInfo) =
let gid = wi.GlobalID(0)
let cadd = Array.zeroCreate<gpu_point2> a.Length
let newsum = PointSum(a.[gid],b.[gid])
cadd.[gid] <- newsum
cadd
[<ReflectedDefinition;Kernel>]
let ModSum2(a:gpu_point2[],b:gpu_point2[],wi:WorkItemInfo) =
let gid = wi.GlobalID(0)
let cadd = Array.zeroCreate<gpu_point2> a.Length
let newsum = gpu_point2(a.[gid].x+b.[gid].x,a.[gid].y+b.[gid].y)
cadd.[gid] <- newsum
cadd
let ws = WorkSize(64L)
let arr_s1= <# Modgpu([|0.f..63.f|],[|63.f..(-1.f)..0.f|],ws)#>.Run()
let arr_s2 = <# Modgpu([|63.f..(-1.f)..0.f|],[|0.f..63.f|],ws)#>.Run()
With this code when I try to use ModSum as
let rsum = <# ModSum(arr_s1,arr_s2,ws)#>.Run()
doesn't work, but instead when I use ModSum2 works perfectly
let rsum = <# ModSum2(arr_s1,arr_s2,ws)#>.Run()
The error I obtain the first time I run it is
FSCL.Compiler.CompilerException: Unrecognized construct in kernel body NewObject (gpu_point2, sx, sy)
and if I re-run the fsi console says
System.NullReferenceException: Object reference not set to an instance of an object.
The only thing I know is that the error doesn't comes from the use of another function since I can define a dot product function that works.
[<ReflectedDefinition>]
let PointProd(a:gpu_point2,b:gpu_point2) =
let f = (a.x*b.x)
let s = (a.y*b.y)
f+s
Thus, I guess the problem comes from the return type of PointSum, but is there a way to create such a function to sum two points and return the point type? And Why is not working?
Edit/Update:
Also with a record happens the same if I define the type as :
[<StructLayout(LayoutKind.Sequential)>]
type gpu_point_2 = {x:float32; y:float32}
If I try to create a function that directly sums two gpu_point_2 on a function works, but if I call a second function it raises the same error as using a struct.
Try to add [<ReflectedDefinition>] on the constructor of gpu_point2:
[<StructLayout(LayoutKind.Sequential)>]
type gpu_point2 =
struct
val mutable x: float32
val mutable y: float32
[<ReflectedDefinition>] new (q, w) = {x=q; y=w}
end
Normally each code that is called from the device need this attribute, constructors included.
What is the best way to create an instance of System.Type representing an F# record or union at runtime? That is, I am looking for an equivalent of FSharpType.MakeTupleType for records and unions.
Just to clarify, I am not interested in creating an instance (i.e. FSharpValue.MakeRecord or FSharpValue.MakeUnion).
I am not aware of an equivalent to FSharpType.MakeTupleType for records and unions in the F# library.
One way to create record or union type like structures at runtime is to use Reflection.Emit. A record type is analogous to a sealed class and a union type is an abstract base class with sealed classes for each case.
For example the following function generates a minimal F# record type:
open System
open System.Reflection
open System.Reflection.Emit
let MakeRecord(typeName:string, fields:(string * Type)[]) =
let name = "GeneratedAssembly"
let domain = AppDomain.CurrentDomain
let assembly = domain.DefineDynamicAssembly(AssemblyName(name), AssemblyBuilderAccess.RunAndSave)
let name = "GeneratedModule"
let dm = assembly.DefineDynamicModule(name, name+".dll")
let attributes = TypeAttributes.Public ||| TypeAttributes.Class ||| TypeAttributes.Sealed
let typeBuilder = dm.DefineType(typeName, attributes)
let con = typeof<CompilationMappingAttribute>.GetConstructor([|typeof<SourceConstructFlags>|])
let customBuilder = CustomAttributeBuilder(con, [|SourceConstructFlags.RecordType|])
typeBuilder.SetCustomAttribute(customBuilder)
let makeField name t =
let attributes = FieldAttributes.Assembly
let fieldBuilder = typeBuilder.DefineField(name+"#", t, attributes)
let attributes = PropertyAttributes.None
let propertyBuilder = typeBuilder.DefineProperty(name, attributes, t, [||])
let customBuilder = CustomAttributeBuilder(con, [|SourceConstructFlags.Field|])
propertyBuilder.SetCustomAttribute(customBuilder)
let attributes = MethodAttributes.Public ||| MethodAttributes.HideBySig ||| MethodAttributes.SpecialName
let methodBuilder = typeBuilder.DefineMethod("get_"+name, attributes, t, [||])
let il = methodBuilder.GetILGenerator()
il.Emit(OpCodes.Ldarg_0)
il.Emit(OpCodes.Ldfld, fieldBuilder)
il.Emit(OpCodes.Ret)
propertyBuilder.SetGetMethod(methodBuilder)
fieldBuilder
let types = fields |> Array.map snd
let cb = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, types)
let il = cb.GetILGenerator()
il.Emit(OpCodes.Ldarg_0)
il.Emit(OpCodes.Call, typeof<obj>.GetConstructor(Type.EmptyTypes))
fields |> Array.iteri (fun i (name, t) ->
let paramName = name.Substring(0,1).ToLower()+name.Substring(1)
let param = cb.DefineParameter(i+1, ParameterAttributes.In, paramName)
let fieldBuilder = makeField name t
il.Emit(OpCodes.Ldarg_0)
il.Emit(OpCodes.Ldarg, param.Position)
il.Emit(OpCodes.Stfld, fieldBuilder)
)
il.Emit(OpCodes.Ret)
let t = typeBuilder.CreateType()
assembly.Save("GeneratedModule.dll")
t
let r = MakeRecord("MyRecord", [|"Alpha",typeof<int>;"Beta",typeof<string>|])
Note the expected interfaces for a Record type may also need to be generated, i.e. implementations of IEquatable, IStructuralEquatable, IComparable and IStructuralComparable are missing.
Update
Extension methods MakeTupleType and MakeUnionType based on the code sample above are now available in the open source Fil (F# to IL Compiler) project (alpha).
In the following example code, I filter a list of strings on a regular expression, knowing that there can only be a single entry that will match that string. I then use the same match string to get 2 grouped values out of the single remaining value.
let input = ["aaaa bbbb";"aaabbbb";"cccc$$$$";"dddddda";" "]
let ValuesOfAB (input: string list) =
let matchString = "(?<a>\w+)\s(?<b>\w+)"
let value = input |> List.filter (fun line -> Regex.Matches(line, matchString).Count <> 0)
|> List.head
(Regex.Matches(value, matchString).[0].Groups.["a"].Value, Regex.Matches(value, matchString).[0].Groups.["b"].Value)
let a = ValuesOfAB input
Is there a better way where I don't have to use Regex.Matches on the same string again for a second time to get the values I wish to return?
Use List.pick:
let input = ["aaaa bbbb";"aaabbbb";"cccc$$$$";"dddddda";" "]
let valuesOfAB (input: string list) =
let matchString = "(?<a>\w+)\s(?<b>\w+)"
let v = input |> List.pick (fun line -> let m = Regex.Match(line, matchString)
if m.Success then Some m else None)
v.Groups.["a"].Value, v.Groups.["b"].Value
let a = valuesOfAB input
Explanation:
You would like to match the first string in the list and return Match object in order that you don't have to run Regex again. List.pick fits the task quite well.
With each string, you need to match at least once so Regex.Match and Match.Success is enough for the purpose.
I want to swap both references, is there a nice way make such a construct work ?
let mutable sarlast = ref (Array.copy ar)
let mutable sarcurr = ref (Array.copy ar)
... some code ...
sarcurr, sarlast <- sarlast, sarcurr
No, <- is single assignment and tuple is immutable in F#.
You can define an infix function for the purpose (one-liner suggestion by #bytebuster):
let (>-<) x y = let temp = !x in x := !y; y := temp
// Usage
let a = ref [|1|]
let b = ref [|2|]
a >-< b
I'm writing a parser for CSV data, and am trying to determine how to handle records
that are blank ("") or contain character data ("C"). The parser code I have below works great, but forces me to deal with the float conversions later. I'd like to be able to just make my string[][] a float[][], and handle the conversions when I parse the file, but I notice that it blows up with any non-numeric data. Ideally there would be no non-numeric or blank values, but they are unavoidable, and as such, have to be dealt with.
Can someone possibly recommend a concise approach to attempt to convert to Double, and then if it doesn't work, replace with Double.NaN instead? (Without sacrificing much performance if possible). Thank you.
let stringLine = [| "2.0"; "", "C"|]
let stringLine2Float = Array.map float stringLine
//desiredFloatArray = [| 2.0; Double.NaN; Double.NaN |]
type csvData = { mutable RowNames: string[]; mutable ColNames: string[]; mutable Data: string[][] }
let csvParse (fileString: string) =
let colNames = ((fileLines fileString |> Seq.take 1 |> Seq.nth 0).Split(',')).[1..]
let lines = fileLines fileString |> Seq.skip 1 |> Array.ofSeq
let rowNames = Array.init lines.Length string;
let allData : string [][] = Array.zeroCreate rowNames.Length
for i in 0..rowNames.Length - 1 do
let fields = lines.[i].Split(',')
allData.[i] <- fields.[1..]
rowNames.[i] <- fields.[0]
{ RowNames = rowNames; ColNames = colNames; Data = allData }
Use this instead of the built-in float conversion:
let cvt s =
let (ok,f) = System.Double.TryParse(s)
if ok then f else nan