I have action data that looks like:
type IHasShow =
abstract member show:bool
type ShowHideNotCompletedData = {show:bool}
type ShowHideCompletedData = {show:bool}
[<Pojo>]
type ActionData =
| ShowHideNotCompleted of ShowHideNotCompletedData
| ShowHideCompleted of ShowHideCompletedData
Later I am trying to pass ShowHideNotCompletedData or ShowHideCompletedData to a function, the function only cares for a boolean "show" member but cant figure out how to pass/cast it:
let setShowItem (data:IHasShow) negate item =
if data.show && (negate item.completed) then
{ item with show = true}
else if (negate item.completed) then
{ item with show = false}
else
item
But how to call this function?
let setShowFn = setShowItem (data :> IHasShow) not
Error:
Type constraint mismatch. The type
'ShowHideNotCompletedData'
is not compatible with type
'IHasShow'
Tried
let setShowFn = setShowItem data not
Error:
The type 'ShowHideNotCompletedData' is not compatible with the type 'IHasShow'
Is there a way to this other than copy paste setShowItem taking a ShowHideNotCompletedData and a ShowHideCompleted?
If it helps; the full source code is here: https://github.com/amsterdamharu/riot_redux_fable
The simplest solution was to not pass the data but only the bool:
let setShowItem show negate item =
if (negate item.completed) then//simplified if statement
{ item with show = show}
else
item
//...
| ShowHideCompleted data ->
let setShowFn = setShowItem data.show id
{ state with
showCompleted = data.show
items = state.items
|> Array.map setShowFn}
I do still wonder how to define a generic type and pass that.
In your current solution, your two types ShowHideNotCompletedData and ShowHideCompletedData are records. They have all fields of the interface, but don't explicitly implement them. The solution is to make the interface explicit:
type ShowHideNotCompletedData(show) =
interface IHasShow with
member this.show = show
type ShowHideCompletedData(show) =
interface IHasShow with
member this.show = show
Instantiate as ShowHideNotCompletedData true. For alternative solutions, you may want to consult some of the SO questions about duck typing, for example this
Having said all that: I have a hunch that your data type definition is a little too complicated. #robkuz has posted an answer that does without the interface. Your own suggestion to just pass a bool into the function seems even better in terms of modularity and testability.
I must admit: I dont like interfaces in F# - not in general but I think syntactically they are a total desaster.
So I more often than not use inline functions with type constraints.
Achtung: using this kind of code will probably kill a dozen puppies or sort
First thing get rid of your interface and the implementation of it (which you have forgotten anyways ;-) )
type ShowHideNotCompletedData = {show:bool}
type ShowHideCompletedData = {show:bool}
type ActionData =
| ShowHideNotCompleted of ShowHideNotCompletedData
| ShowHideCompleted of ShowHideCompletedData
Then write that really crazy looking function
let inline show< ^T when ^T : (member show : bool)> (x:^T) =
(^T : (member show : bool)(x))
and apply it
let setShowItem data =
match data with
| ShowHideNotCompleted x -> show x
| ShowHideCompleted x -> show x
Related
Let's consider this code:
type TransactionTypes =
| TransactionType1
| TransactionType2
type Test() =
let mutable lastTransactionType1 = DateTime.MinValue
let mutable lastTransactionType2 = DateTime.MinValue
let getLastTransaction transaction =
match transaction with
| TransactionType1 -> lastTransactionType1
| TransactionType2 -> lastTransactionType2
let updateLastTransaction transaction =
match transaction with
| TransactionType1 -> lastTransactionType1 <- DateTime.UtcNow
| TransactionType2 -> lastTransactionType2 <- DateTime.UtcNow
Now (with the understanding that I'm still learning F#), I would like to clarify a couple things:
Something like:
let a = DateTime.Now
does a permanent binding, so 'a' will always be the same time on subsequent uses.
But, my understanding is that if there is a parameter, like:
let a anyParameter = DateTime.Now
will be re-evaluated every time due to the presence of the parameter. Is that correct?
In the code above, the two let statements (getLastTransaction and updateLastTransaction) are private to the type (Test)
I could also have implemented them as:
member private this.getLastTransaction = ...
member private this.updateLastTransaction = ...
Is there any reason, for private functions to prefer let vs. member private this?
"let mutable" already implies the this. so the fields are accessible by both forms.
So, what is the advantage of one form vs. the other?
When you are working with members, F# inherits a lot of things from the .NET object model. A .NET object can have a couple of different things:
Fields - those are storing a value (just like fields of a record). They can be mutable or immutable.
Methods - those can be invoked with zero or more arguments (like functions)
Properties - those have no arguments (like fields); they can be read or written, but when this happens, some code is invoked. A property is basically a pair of getter and setter methods.
In F#, some of this is less visible. However, let corresponds to a field and member with arguments corresponds to a method. Your tricky case is a member without arguments. For example:
type A() =
member x.Foo = printfn "Hi"; 42
Will Hi be printed only once, or will it be printed each time you access Foo? To answer, it's useful to know that Foo is a property with a getter. The above is actually a syntactic sugar for the full version:
type A() =
member x.Foo
with get() = printfn "Hi"; 42
Now you can see that there is a method behind the Foo property! Each time you access Foo, the compiler will generate a call to the get() method, so Hi will be printed repeatedly.
In addition to Tomas' answer:
let mutable lastTransactionType1 = DateTime.MinValue
is equivalent in C# to:
internal DateTime lastTransactionType1 = DateTime.MinValue;
and
member private this.getLastTransaction ...
is the same IL as far as IL is concerned with
let getLastTransaction ...
In equivalent C#, both are
internal DateTime getLastTransactionMember(TransactionTypes transaction)
{
if (transaction.Tag != 1)
{
return lastTransactionType1;
}
return lastTransactionType2;
}
But for using F# in an idiomatic way, you would want to go with let.
There's also a difference in that member does let you use the methods in bindings before their declaration, which might be useful in some cases (read: hacks)
let getType1 = this.getLastTransactionMember TransactionType1 //this compiles
member private this.getLastTransactionMember transaction =
match transaction with
| TransactionType1 -> lastTransactionType1
| TransactionType2 -> lastTransactionType2
Given a function defined as let get<'T> var1 var2 : 'T option what type signature should the given to a record field that function will be assigned to?
I've tried various permutations of type MyType = {AFunc<'T> : obj -> obj -> 'T option} but but can't find any variant that lets me introduce the type argument.
I can do this type MyType = {AFunc: obj -> obj -> obj option} and that will let me create the record {AFunc = get} but then can't apply the function because the type argument is missing.
There's a bit of ambiguity in your question. Do you want to be able to store get<'t> in a record for one particular 't per record, or do you want to have the record itself store a "generic" function like get<_>?
If the former, then TeaDrivenDev's answer will work.
If the latter, then there's no completely straightforward way to do it with F#'s type system: record fields cannot be generic values.
However, there's a reasonably clean workaround, which is to declare an interface type with a generic method and store an instance of the interface in your record, like this:
type OptionGetter = abstract Get<'t> : obj->obj->'t option
type MyType = { AFunc: OptionGetter }
let get<'t> var1 var2 : 't option = None // your real implementation here
let myRecord = { AFunc = { new OptionGetter with member this.Get v1 v2 = get v1 v2} }
let test : int Option = myRecord.AFunc.Get "test" 23.5
You have to make the record type itself generic; only then will 'T be defined and usable.
type MyType<'T> = { AFunc : obj -> obj -> 'T option }
why in the world does the constructor for a dictionary in F# allow duplicate keys and just overwrites silently?
let ``you just got dict`` = dict [ "hello","goodbye";"hello","world"]
This is very counter-intuitive behavior.
You could shadow the built-in dict function with a version that behaves as you want. You could return the more fitting IReadOnlyDictionary interface while you're at it.
let dict source =
let d = Dictionary<'K, 'V>(HashIdentity.Structural)
source |> Seq.iter d.Add
{
new IReadOnlyDictionary<'K, 'V> with
member x.ContainsKey(key) = d.ContainsKey(key)
member x.TryGetValue(key, value) = d.TryGetValue(key, &value)
member x.Item with get key = d.[key]
member x.Keys = d.Keys :> _
member x.Values = d.Values :> _
interface IReadOnlyCollection<KeyValuePair<'K, 'V>> with
member x.Count = d.Count
interface IEnumerable<KeyValuePair<'K, 'V>> with
member x.GetEnumerator() = d.GetEnumerator() :> _
interface System.Collections.IEnumerable with
member x.GetEnumerator() = d.GetEnumerator() :> _
}
I can't explain the reason for this design - just as I can't explain why Dictionary<TKey, TValue> doesn't take a sequence of KeyValuePairs as input.
However, if you look at the implementation of dict, you'll see that it internally adds each element using the indexer, like this:
foreach (Tuple<TKey, TValue> tuple in keyValuePairs)
{
TValue local = tuple.Item2;
TKey local2 = tuple.Item1;
d[new RuntimeHelpers.StructBox<TKey>(local2)] = local;
}
where d is the Dictionary being created. The indexer silently updates the dictionary entry, so this explains the mechanics of it.
Not an entire answer, I admit, but perhaps a piece of the puzzle.
You aren't going to get a why unless some Microsoft engineer explains it to you why they chose to do it that way. Regardless, it is what it is and works just as the documentation says it should:
https://msdn.microsoft.com/en-us/library/k7z0zy8k(v=vs.110).aspx
Remarks
You can also use the Item property to add new elements by setting the value
of a key that does not exist in the Dictionary<TKey, TValue>; for example,
myCollection[myKey] = myValue (in Visual Basic, myCollection(myKey) =
myValue). However, if the specified key already exists in the
Dictionary<TKey, TValue>, setting the Item property overwrites the old
value. In contrast, the Add method throws an exception if a value with the
specified key already exists.
I need a data structure for the following:
In a device that has memory slots, each of the slots has a set of parameters. These parameters have different types. The list of possible parameters is fixed, so there is no need for generic flexibility à la »Support of arbitrary parameters without change«. Also, for each parameter, the structure of the contents is known. Typical use cases are the retrieval and modification of one specific parameter as well as a transformation of the complete parameter set into a different (but already defined) data structure.
The natural choice of F# data structure would be a sum type like this:
type SomeParameterContentType = { Field1 : string, Field2 : int }
type SomeOtherParameterContentType = { Other1 : bool option, Other2 : double }
type Parameter =
| SomeParameter of SomeParameterContentType
| SomeOtherParameter of SomeOtherParameterContentType
This way I could create a set and store the parameters there with a very nice data structure. The question here is: Given this idea, how would looking for a specific parameter look like? I don't know of any way to specify a predicate for a find-function for sets. It would be possible to define another sum type listing just the Parameter Types without their contents using this as key for a Dictionary but I don't like this idea too much. Using strings instead of the second sum type doesn't make things better as it still would require providing the list of possible parameters twice.
Does anyone have a better idea?
Thx
--Mathias.
Sounds like all you want is a tryFind for a Set:
module Set =
let tryFind p =
Set.toList >> List.tryFind p
Usage:
let mySet = Set.ofList [1;2;3;4;5]
let m = mySet |> Set.tryFind (fun t -> t = 2)
val m : int option = Some 2
Usage with your Types:
let yourSet = Set.ofList [SomeParameter {Field1="hello";Field2=3}]
let mYours = yourSet |> Set.tryFind (fun t -> match t with
|SomeParameter p -> true
|SomeOtherParameter p -> false)
val mYours : Parameter option = Some (SomeParameter {Field1 = "hello";
Field2 = 3;})
For the sample program:
type public MyClass(reasonForLiving:string) =
member x.ReasonForLiving with get() = reasonForLiving
let classFactory () = MyClass("up to you")
let live () =
let instance = classFactory()
if instance = null then raise(System.Exception("null is not living... that's why OO languages die from bugs"))
instance
I get the error "The type 'MyClass' does not have null as a proper value" when I go to use this class as a return value of implicitly typed functions and compare it to null (b/c of compatibility requirements with C# dependency injection I cannot rely on F# option types).
I can easily fix this by changing the null check to:
if instance :> obj = null then
However, I know ("feel") this is completely "wrong". Especially when I consider how MyClass is a reference type that shouldn't need to be boxed (speaking from a C# background).
I've read about "F# Value Restriction" and how it impacts type inference, but I can't seem to gleam how it applies to this scenario.
Q: Is there another way to do this?
Aside #1: I found a simpler method of getting the error...
type public MyClass(reasonForLiving:string) =
member x.ReasonForLiving with get() = reasonForLiving
let nullMyClass : MyClass = null
Aside #2: I did try System.Nullable without thinking... MyClass is a reference type and not a value type (struct) which Nullable<_> requires. So, just reassures me that I REALLY am dealing with a reference type and leaves me wondering why an object cast suddenly makes this work.
Update: For anyone interested, I used this as one solution for Common Service Locator with the three functions below. Each service requested must support null, so if the service class is defined in F#, you need to add the [<AllowNullLiteral>]:
let private getServiceLocator () =
try Some(Microsoft.Practices.ServiceLocation.ServiceLocator.Current)
with | _ -> None
let private getService serviceFactory =
let serviceLocator = getServiceLocator()
let service = match serviceLocator with
| None -> serviceFactory()
| _ ->
match serviceLocator.Value.GetInstance<'a>() with
| null -> serviceFactory()
| svc -> svc
match service with
| null -> None
| _ -> Some(service)
let private getRequiredService serviceFactory =
let service = getService serviceFactory
match service with
| None -> raise(MissingServiceException(""))
| _ -> service.Value
Use the [<AllowNullLiteral>] attribute:
[<AllowNullLiteral>]
type public MyClass(reasonForLiving:string) =
member x.ReasonForLiving with get() = reasonForLiving
By default, F# types do not allow null (thank heavens!). This attribute is useful for interop with other .NET languages and allows assignment/comparison with null.
The problem with the AllowNullLiteral attribute is that in addition to allowing you to compare your objects to null, it also makes it possible to set your objects to null.
Assuming that this is not desirable for your use-case, there is an easy alternative with unobservable performance impact:
let inline isNull (x:^T when ^T : not struct) = obj.ReferenceEquals (x, null)
Then rather than doing if instance = null then, do if isNull instance then instead.
This will work for any reference type (including records and DUs), but does not introduce the possibility of setting objects of your F# types to null from F# – the best of both worlds.