I am struggling to get memoization to work when the memoized function is an abstract function which is overridden/defined within a subclass rather than the parent class.
When the memoized function is defined in the parent class, it works fine.
When I define the signature of the memoized function in the parent class, and then override it in the subclass, I can't figure out the appropriate syntax.
open System
let Memoize f =
let dict = Dictionary<_, _>()
fun c ->
let exists, value = dict.TryGetValue c
match exists with
| true -> value
| _ ->
let value = f c
dict.Add(c, value)
value
[<AbstractClass>]
type ParentClass() as this =
let someparam = DateTime(2022,1,1)
let SlowNumber100InParentClass(t) =
System.Threading.Thread.Sleep(1000)
100.0
member val MemoParentClassSlow100 = Memoize SlowNumber100InParentClass
member this.MultiplyBy2A = (this.MemoParentClassSlow100 someparam) * 2.0
abstract MemoSubClassSlow100: DateTime->float
member this.MultiplyBy2B = (this.MemoSubClassSlow100 someparam) * 2.0
type MyClass() as this =
inherit ParentClass()
let SlowNumber100InSubClass(t) =
System.Threading.Thread.Sleep(1000)
100.0
override this.MemoSubClassSlow100(t) = Memoize SlowNumber100InSubClass t // doesn't "memoize"
//override val MemoSubClassSlow100 = Memoize SlowNumber100InSubClass // This feels intuitive to me, but error is "No abstract property was found that corresponds to this override"
// ??? somehow else ???
[<EntryPoint>]
let main args =
let x = new MyClass()
for i in 1..10 do
Console.WriteLine(x.MultiplyBy2A) // this is fast
for i in 1..10 do
Console.WriteLine(x.MultiplyBy2B) // this is slow
0
You're very close. Just use member val in the subclass to hold the memoized function, since that member doesn't override anything in the parent class:
type MyClass() =
inherit ParentClass()
let SlowNumber100InSubClass(t) =
System.Threading.Thread.Sleep(1000)
100.0
member val MemoSubClassSlow100_ = Memoize SlowNumber100InSubClass
override this.MemoSubClassSlow100(t) = this.MemoSubClassSlow100_ t
Personally, I think let is usually preferable to member val, though:
let memoSubClassSlow100 = Memoize SlowNumber100InSubClass
override _.MemoSubClassSlow100(t) = memoSubClassSlow100 t
Related
I am struggling to make Memoization work in F# when the function I want to Memoize is a member of a class.
The Dictionary appears to be cleared every time - and so nothing is actually memoized, the result is always recomputed. The same code but with the key functions outside of a calls of a class works just fine.
open System
module TestMemo
open System
open System.IO
open System.Collections.Generic
let Memoize f =
let dict = Dictionary<_, _>()
fun c ->
let exists, value = dict.TryGetValue c
match exists with
| true -> value
| _ ->
let value = f c
dict.Add(c, value)
value
type MyClass() as this =
let rec AddToOne(x) = if x <= 1 then 1 else x + AddToOne(x-1)
let rec AddToOneSkip(x) = if x <= 1 then 1 else x + AddToOneSkip(x-2)
member this.MemoAddToOne = Memoize AddToOne
member this.MemoAddToOneSkip = Memoize AddToOneSkip
[<EntryPoint>]
let main args =
let x = new MyClass()
for i in 1..100000 do
Console.WriteLine(x.MemoAddToOneSkip(i))
for i in 1..100000 do
Console.WriteLine(x.MemoAddToOne(i))
0
When you write this:
member this.MemoAddToOne = Memoize AddToOne
That's not a "value", but a property. A property in .NET is a pair of functions (get + set), but there are also read-only properties, which have only "get". And that's what you created here. They're basically functions in disguise.
So every time somebody accesses x.MemoAddToOne, they're basically calling a function, so every time the body is executed anew, thus making a new call to Memoize every time.
To avoid this, create the memoizers once and then return them from the property getter:
let memoAddToOne = Memoize AddToOne
member this.MemoAddToOne = memoAddToOne
Or use a shortcut for the same thing:
member val MemoAddToOne = Memoize AddToOne
What's the best way to persist/save the results of memoization so it can be loaded later?
There's this standard code snippet in F# for implementing memoization:
let memoize f =
let dict = Dictionary<_, _>();
fun c ->
let exist, value = dict.TryGetValue c
match exist with
| true -> value
| _ ->
let value = f c
dict.Add(c, value)
value
let mySlowFunc x=
// something very slow
0
let myFastFunc = memoize mySlowFunc
After calling myFastFunc many times, I will have a dictionary full of results for mySlowFunc for various x's. I want to persist these results so ideally I can do something like:
let saveMemoziationResults myFastFunc "results.file" = ... // saves the dict to a file
let loadMemoziationResults "results.file" // loads the dict from a file
I can't figure out a way to "access" that dict in order to save it.
You could move dict creation to the caller, like
let memoizeBase dict =
let memoize f = …
memoize
And using it like
let dict = new…
let memoize = memoizeBase dict
// use memoize and save/load dict when needed
I have a dictionary (formatters) declared in the following code that will have items added to it inside of multiple HttpModules. Once those are loaded it will not be written to again. What would be the best way to expose this so it can be accessed from any .NET language? I know this seems lame and looks like I should just have them implement ToString() however part of the application requires strings to be in a certain format and I don't want clients having to implement ToString() in a way that is specific to my application.
module MappingFormatters
open System
open System.Collections.Generic
let formatters = new Dictionary<Type, obj -> string>();
let format item =
let toDateTime (d:DateTime) =
let mutable date = d;
if (date.Kind) <> System.DateTimeKind.Utc then
date <- date.ToUniversalTime()
date.ToString("yyyy-MM-ddTHH:mm:00Z")
let stripControlCharacters (str:string) =
let isControl c = not (Char.IsControl(c))
System.String( isControl |> Array.filter <| str.ToCharArray())
let defaultFormat (item:obj) =
match item with
| :? string as str-> stripControlCharacters(str)
| :? DateTime as dte -> toDateTime(dte)
| _ -> item.ToString()
let key = item.GetType();
if formatters.ContainsKey(key) then
formatters.Item(key) item
else
defaultFormat item
If the question is just one about language interoperability, then I think you should just change the type from
Dictionary<Type, obj -> string>
to
Dictionary<Type, Func<obj, string> >
and then you should be in good shape.
After researching. I have decided to create a type called MappingFormatters to hold the method for adding the formatter. The client does not need to call it, but my f# code will. I believe this will let me use the common f# conventions while exposing a way for other .net languages to inter-operate with the least confusion.
module File1
open System
let mutable formatters = Map.empty<string, obj -> string>
let format (item:obj) =
let dateToString (d:DateTime) =
let mutable date = d;
if (date.Kind) <> System.DateTimeKind.Utc then
date <- date.ToUniversalTime()
date.ToString("yyyy-MM-ddTHH:mm:00Z")
let stripCtrlChars (str:string) =
let isControl c = not (Char.IsControl(c))
System.String( isControl |> Array.filter <| str.ToCharArray())
let key = item.GetType().AssemblyQualifiedName
if Map.containsKey key formatters then
Map.find key formatters item
else
match item with
| :? DateTime as d -> dateToString d
| _ -> stripCtrlChars (item.ToString())
let add (typ:Type) (formatter:obj -> string) =
let contains = Map.containsKey
let key = typ.AssemblyQualifiedName
if not (formatters |> contains key) then
formatters <- Map.add key formatter formatters
type MappingFormatters() = class
let addLock = new obj()
member a.Add (``type``:Type, formatter:Func<obj,string>) =
lock addLock (fun () ->
add ``type`` (fun x -> formatter.Invoke(x))
)
end
I am trying to create an expression tree containing a function call to a F# function on a certain module. However, I am missing something because the System.Linq.Expressions.Expression.Call() helper function cant find the function I'm supplying.
The Call() call gives an InvalidOperationException: "No method 'myFunction' on type 'TestReflection.Functions' is compatible with the supplied arguments."
If anyone can give me a hint on what I am doing wrong it would be very helpful.
See the code below:
namespace TestReflection
open System.Linq.Expressions
module Functions =
let myFunction (x: float) =
x*x
let assem = System.Reflection.Assembly.GetExecutingAssembly()
let modul = assem.GetType("TestReflection.Functions")
let mi = modul.GetMethod("myFunction")
let pi = mi.GetParameters()
let argTypes =
Array.map
(fun (x: System.Reflection.ParameterInfo) -> x.ParameterType) pi
let parArray =
[| (Expression.Parameter(typeof<float>, "a") :> Expression); |]
let ce = Expression.Call(modul, mi.Name, argTypes, parArray)
let del = (Expression.Lambda<System.Func<float, float>>(ce)).Compile()
printf "%A" (Functions.del.Invoke(3.5))
Regards,
Rickard
The third argument to Expression.Call is an array of generic type parameters - your method is not generic, so that should be null. You'll also need to pass your "a" argument to Expression.Lambda:
let a = Expression.Parameter(typeof<float>, "a")
let parArray = [| (a :> Expression); |]
let ce = Expression.Call(modul, mi.Name, null, parArray)
let del = (Expression.Lambda<System.Func<float, float>>(ce, a)).Compile()
I'm trying to figure out how to instantiate a case class object with reflection. Is there any support for this? The closest I've come is looking at scala.reflect.Invocation, but this seems more for executing methods that are a part of an object.
case class MyClass(id:Long, name:String)
def instantiate[T](className:String)(args:Any*) : T = { //your code here }
Is close to the API I'm looking for.
Any help would be appreciated.
scala> case class Foo(id:Long, name:String)
defined class Foo
scala> val constructor = classOf[Foo].getConstructors()(0)
constructor: java.lang.reflect.Constructor[_] = public Foo(long,java.lang.String)
scala> val args = Array[AnyRef](new java.lang.Integer(1), "Foobar")
args: Array[AnyRef] = Array(1, Foobar)
scala> val instance = constructor.newInstance(args:_*).asInstanceOf[Foo]
instance: Foo = Foo(1,Foobar)
scala> instance.id
res12: Long = 1
scala> instance.name
res13: String = Foobar
scala> instance.getClass
res14: java.lang.Class[_] = class Foo
Currently there is not much reflection support in Scala. But you can fall back to th Java Reflection API. But there are some obstacles:
You have to create a Array[AnyRef] and box your "primitive types" in the wrapper classes (java.lang.Integer, java.lang.Character, java.lang.Double, ...)
newInstance(Object ... args) gets an varargs array of Object, so you should give the type inferer a hint with :_*
newInstance(...) returns an Object so you have to cast it back with asInstanceOf[T]
The closest I could get to your instantiate function is this:
def instantiate(clazz: java.lang.Class[_])(args:AnyRef*): AnyRef = {
val constructor = clazz.getConstructors()(0)
return constructor.newInstance(args:_*).asInstanceOf[AnyRef]
}
val instance = instantiate(classOf[MyClass])(new java.lang.Integer(42), "foo")
println(instance) // prints: MyClass(42,foo)
println(instance.getClass) // prints: class MyClass
You cannot get the get class from a generic type. Java erases it (type erasure).
Edit: 20 September 2012
Three years on, the instantiate method can be improved to return a properly typed object.
def instantiate[T](clazz: java.lang.Class[T])(args:AnyRef*): T = {
val constructor = clazz.getConstructors()(0)
return constructor.newInstance(args:_*).asInstanceOf[T]
}
See http://www.nabble.com/How-do-I-get-the-class-of-a-Generic--td20873455.html
See answers to Scala: How do I dynamically instantiate an object and invoke a method using reflection? as well, especially regarding type erasure.
This is what I've ended up with so far, I'd like to not have to deal directly with AnyRef if possible. So if anyone knows a way to get around that I'd appreciate the help.
case class MyClass(id:Long,name:String)
def instantiate[T](classArgs: List[AnyRef])(implicit m : Manifest[T]) : T ={
val constructor = m.erasure.getConstructors()(0)
constructor.newInstance(classArgs:_*).asInstanceOf[T]
}
val list = List[AnyRef](new java.lang.Long(1),"a name")
val result = instantiate[MyClass](list)
println(result.id)