In Scala I can do something like this:
abstract class MyData
case class A() extends MyData
case class B() extends MyData
implicit class HeavyComputationProvider(val data : MyData) {
private def _HeavyComputation() = /* */;
lazy val HeavyComputation = this._HeavyComputation();
}
// Example usage:
val a = A
println a.HeavyComputation // This will calculate
println a.HeavyComputation // This will use the cached value
This has the benefit of caching when re-used, but not calculated when not used.
How do you do provide the lazy HeavyComputation for the following F# type?
type MyData =
| A
| B
type MyData with
member private this.__HeavyComputation = (* *)
// Error: This declaration element is not permitted in an augmentation and this is unavailable
let _HeavyComputation = lazy((* *))
// This will just create a *new* lazy computation each time
member this._HeavyComputation = lazy(this.__HeavyComputation)
// This should lazily compute & cache, transparent to the caller
member this.HeavyComputation = this._HeavyComputation.Force
I think there is no direct equivalent of the Scala approach. Doing this requires keeping some additional state as part of the object (e.g. a lazy value) and F# does not let you add additional state to objects once they are defined.
The closest thing you can do is to write a wrapper type that stores the original MyData value together with the additional lazy computation:
type MyData =
| A
| B
type MyDataWithComputation(data:MyData) =
let _HeavyComputation = lazy(1)
member this.MyData = data
member this.HeavyComputation = _HeavyComputation.Value
And then use it as follows:
let myd = MyDataWithComputation(A)
myd.HeavyComputation
myd.HeavyComputation
Related
I created a custom type which is implementing a Map.
type School = Map<int, string list>
I tried now various ways on how to instatiate that type but it always fails.
With attempt Nr.1 I thought maybe one can 'dot' the class (somehow).
let xyz = School.Map.empty;;
or
let kgse = School.empty;;
//The type 'Map<Key,Value>' does not define the field, constructor or member 'empty'.
Attempt Nr.2 was my hope that f# knows if I create a map which has the same structure of the custom type it assigns it automatically.
let xyz =
- Map.empty.
- Add(2, ["Alex"]);;
val xyz: Map<int,string list> = map [(2, ["Alex"])]
This works but it only returns the general Map class.
Finally, I thought maybe I can cast the type.
let xyz =
- School Map.empty.
- Add(2, ["Alex"]);;
This throw me again an error:
Successive arguments should be separated by spaces or tupled, and arguments involving function or method applications should be parenthesized.
F# have pretty neat feature - types with same name can extend each other. For example System.Collection.Generic have type EqualityComparer with static property Default, which return adequate comparer for given generic type, but it doesn't fit for collections, because they would be compared be reference, instead of by value.
In C# you can't write extensions for static class to call EqualityComparer<T>.ForCollection, but you can with F#:
module EqualityComparer =
let ForCollection<'a> = ...
let def = EqaulityComparer.Default
let mine = EqualityComparer.ForCollection
As you can see, we extended static class with module. This is 2 distinct types with same name and we can use methods and properties from both.
Same happens with Map class and Map module. You've created alias for type which can be instantiated but haven't for helper module. What you need to do is create type abbreviation for module
type School = Map<int, string list>
module School = Map
School.empty
Part of the problem here is that School, as you've defined it, is a type abbreviation, not a distinct type of its own. This means that it is simply another name for Map<int, string list>. That's a good light-weight approach, and still allows you to create your own School.empty value, if you want:
module School =
let empty : School = Map.empty
let xyz = School.empty.Add(2, ["Alex"])
If, on the other hand, you actually want School to be a real type, you should consider defining it as a record or discriminated union instead:
type School =
private MkSchool of Map<int, string list> with
member this.Add(key, values) =
let (MkSchool map) = this
MkSchool (map.Add(key, values))
module School =
let empty = MkSchool Map.empty
let xyz = School.empty.Add(2, ["Alex"])
Add a School type annotation to xyz:
let xyz : School = Map.empty.Add(2, ["Alex"])
Using dotnet fsi:
> type School = Map<int, string list>
-
- let xyz : School = Map.empty.Add(2, ["Alex"]);;
type School = Map<int,string list>
val xyz : School = map [(2, ["Alex"])]
You can also create functions to return School and then use them as follows:
Again, in dotnet fsi:
> let makeSchool s : School = Map.empty.Add s
-
- let addStudent (school: School) student : School = school.Add student
-
- let xyz' = makeSchool (3, ["Betty"])
-
- let newStudent = (4, ["Charles"])
-
- let schoolWithNewStudentAdded = addStudent xyz' newStudent
- ;;
val makeSchool : int * string list -> School
val addStudent : school:School -> int * string list -> School
val xyz' : School = map [(3, ["Betty"])]
val newStudent : int * string list = (4, ["Charles"])
val schoolWithNewStudentAdded : School =
map [(3, ["Betty"]); (4, ["Charles"])]
With this type:
type A =
{
S: string
}
static member private l = Dictionary<string, A>()
static member add s = A.l.[s] <- { S=s }
static member list () = l.Values
if I do:
A.add "hello"
A.add "world"
I'd expect A.list() to return something since the dictionary is static, but it returns an empty list. Why is that?
To clarify what I'm trying to do: I'd like to have the ability to register the objects of type A into a static dictionary that is attached to the type itself as it would make the object repository 'self contained' in the type, in a way.
Your l is not a field, but a property with a getter.
A "property", contrary to appearances, is not a memory cell with some value in it. A "property" is a pair of get+set functions. Just functions, that's all. No memory cell.
So what you made yourself is a property with a getter (without a setter), and all that getter does is create a new Dictionary and return it.
This means, every time you access A.l, you get yourself a new, fresh dictionary. Because l is a function, not a memory cell.
Now, in order to make a memory cell (aka "field"), one would ordinarily use static member val, like so:
static member val private l = Dictionary<string, A>()
Unfortunately, in this particular case this doesn't work, because static fields are not permitted on F# records and unions. They work fine on actual classes, but not on F# types.
So instead what I would recommend is to put those functions in a module rather than making them static methods:
type A = { S: string }
module A =
let private l = Dictionary<string, A>()
let add s = l.[s] <- { S=s }
let list () = l.Values
(and just in general: try to use fewer classes and more modules and functions; they're more idiomatic in F# and lead to fewer problems in general)
Now this works as expected:
> A.add "hello";;
val it : unit = ()
> A.add "world";;
val it : unit = ()
> A.list();;
val it : Dictionary`2.ValueCollection<string,A> =
seq [{ S = "hello" }; { S = "world" }]
I want to create a cacheline sized struct wrapping a mutable, volatile int64 in F#. I’ve tried various struct definitions including the one below, but can't get anything to compile.
[<Struct; StructLayout(LayoutKind.Explicit, Size = 64)>]
type MyStruct1 (initVal:int64) =
[<VolatileField>]
let mutable value = initVal
member x.Value
with get () = value
and set(valIn) = value <- valIn
which gives this error: "Structs cannot contain value definitions because the default constructor for structs will not execute these bindings.
consider adding additional arguments to the primary constructor for the type". I can't see what additional arguements I could add to the primary constructor above.
Any ideas?
The struct definition could be
[<Struct; StructLayout(LayoutKind.Explicit, Size = 64)>]
type MyStruct =
[<FieldOffset(0)>]
val mutable value : int64
new(initVal:int64) = { value = initVal }
member x.Value
with get() = x.value
and set(valIn) = x.value <- valIn
but then, [<VolatileField>] is not allowed on val bindings and structs can't contain let bindings.
TL;DR: AFAIK this is impossible in F#
As pointed out by #V.B. you could use Interlocked which gives a superset of volatiles guarantees (stronger guarantees ≈ more overhead). It might then be better to privateize value to prevent (accidental) writes circumventing the barrier:
[<Struct; StructLayout(LayoutKind.Explicit, Size = 64)>]
type MyStruct =
[<FieldOffset(0)>]
val mutable private value : int64
new(initVal:int64) = { value = initVal }
member public x.Value
with get() = Interlocked.Read(&x.value)
and set(valIn) = Interlocked.Exchange(&x.value, valIn) |> ignore
Interlocked gives similar guarantees as volatile, see this question.
open System.Threading
[<Struct; StructLayout(LayoutKind.Explicit, Size = 64)>]
type MyStruct =
[<FieldOffset(0)>]
val mutable value : int64
new(initVal:int64) = { value = initVal }
member x.Value
with get() = Interlocked.Read(&(x.value))
and set(valIn) = Interlocked.Exchange(&(x.value),valIn) |> ignore
F# has many different ways to define variables/members in types. When should I use let, member val and member this. in F#, and what is the difference between them? How about static and mutable members?
The answer from #meziantou already gives a nice overview of the options (and how they behave differently), so let me just give a brief summary, or list of recommendations:
Use let or let mutable if you want to define a local value that is visible only within the type (essentially a private field or a private function). Inside a module at top-level, these are publicly accessible and evaluated once. let mutable at module level creates a single writable field with no backing value.
You can use val to create an auto-property, it is short for member val Foo = .. with get. From F# this is seen as a field, but it's internally implemented as a get-property with a backing field to prevent mutation.
You can use val mutable to define a public field, but I wouldn't recommend this unless you actually need a public field (e.g. some .NET library may require types with this structure).
Using member x.Foo = ... is the best way to expose (read-only) state from a type. Most F# types are immutable, so this is perhaps the most common public member. It is short for a get-only instance property.
Using member x.Foo with get() = .. and set(value) ... is useful when you need to create a get/set property with your own custom code in the gettor and settor. This is sometimes useful when you're creating a mutable object.
Using member val Foo = ... with get, set is basically the same thing as auto-implemented properties in C#. This is useful if you need a mutable property with a getter and setter that just reads/writes a mutable backing field.
Using static let on a type creates a static (class-level) read-only field, which internally creates a property with a backing field. Use static mutable let ... for a read/write static field without a backing field.
Using static val mutable private creates a static read/write auto-property with a backing field, it cannot be public.
I found out easier to just decompile what's happening, so:
type Region() =
let mutable t = 0.0f
member val Width = 0.0f
member x.Height = 0.0f
member val Left = 0.0f with get,set
member x.Top with get() = 0.0f and set(value) = t <- value
is actually the following:
public class Region
{
internal float t;
internal float Width#;
internal float Left#;
public float Width
{
get
{
return this.Width#;
}
}
public float Height
{
get
{
return 0f;
}
}
public float Left
{
get
{
return this.Left#;
}
set
{
this.Left# = value;
}
}
public float Top
{
get
{
return 0f;
}
set
{
this.t = value;
}
}
public Region() : this()
{
this.t = 0f;
this.Width# = 0f;
this.Left# = 0f;
}
}
This sample explains the difference between syntaxes:
type MyClass() =
let random = new System.Random()
[<DefaultValue>] val mutable field : int
member val AutoProperty = random.Next() with get, set
member this.ExplicitProperty = random.Next()
let c = new MyClass()
// c.random is not accessible
c.field <- 42 // 'field' is accessible
// An automatic property is only evaluated upon initialization, and not every time the property is accessed
printfn "AutoProperty = %d" c.AutoProperty // x
printfn "AutoProperty = %d" c.AutoProperty // Still x
// The value of the explicit property is evaluated each time
printfn "ExplicitProperty = %d" c.ExplicitProperty // y
printfn "ExplicitProperty = %d" c.ExplicitProperty // The value is re-evaluated so you'll get a different value
Here is what am I trying to do :
and [<AbstractClass>] Figure() =
let mutable name : string = ""
let mutable color : ColorType = WHITE
abstract member Name : string
member F.Color
with get() = color
and set v = color <- v
abstract member motion : Dashboard -> SPosition -> ColorType -> list<SPosition * CellDashboard * bool>;
override F.ToString() = name
and CellDashboard(addingFigure : Nullable<Figure>) as C =
let mutable attacked : bool = false;
let mutable cleaned : bool = false;
let mutable _CellState : Nullable<Figure> = Nullable<Figure>(addingFigure);
the trouble is :
Error 1 A generic construct requires that the type 'Figure' be non-abstract
why ? And how can I avoid this error ?
The Nullable<T> type can only be used for .NET value types. The error message essentially means that the compiler cannot check whether the constraint holds or not (because the type is abstract).
If you want to represent missing value in F#, it is better to use option<T> instead.
If you're writing code that will be used from C#, then it is better to avoid exposing F#-specific types (like option<T>) and you can mark the type with AllowNullLiteral, which makes it possible to pass null as a value of the type (but null is evil, so this shouldn't be done unless necessary!)