[<Extension>]
static member ToOrganizationRequest<'T when 'T :> OrganizationRequest> (entity: Entity) =
let request = Activator.CreateInstance(typeof<'T>) :?> OrganizationRequest
request.Parameters.Item "Target" <- entity
request
[<Extension>]
static member ToOrganizationRequest<'T when 'T :> OrganizationRequest> (entities: seq<Entity>) =
entities
|> Seq.map (fun x -> x.ToOrganizationRequest<'T>())
The second extensionmethod is not able to reference the first, so
|> Seq.map (fun x -> x.ToOrganizationRequest<'T>())
fails, because im not able to use ToOrganizationRequest.
Is there any way to make it understand the reference?
If you don't need your extension method to be visible in C#, you can (and probably should) extend the Entity type like this instead:
type Entity with
member this.ToOrganizationRequest<'T when 'T :> OrganizationRequest>() =
let request = Activator.CreateInstance(typeof<'T>) :?> OrganizationRequest
request.Parameters.Item "Target" <- entity
request
This will allow your second C# style extension method to function as you originally wrote it:
[<Extension>]
type Ext =
[<Extension>]
static member ToOrganizationRequest<'T when 'T :> OrganizationRequest> (entities: seq<Entity>) =
entities
|> Seq.map (fun x -> x.ToOrganizationRequest<'T>())
If you do need them in C#, you'll have to call the other extension method statically within the type that the extension methods are defined within.
[<Extension>]
type Ext =
[<Extension>]
static member ToOrganizationRequest<'T when 'T :> OrganizationRequest> (entity: Entity) =
let request = Activator.CreateInstance(typeof<'T>) :?> OrganizationRequest
request.Parameters.Item "Target" <- entity
request
[<Extension>]
static member ToOrganizationRequest<'T when 'T :> OrganizationRequest> (entities: seq<Entity>) =
entities
|> Seq.map (Ext.ToOrganizationRequest)
You can read more about the various types of extension methods within the F# documentation here.
Related
I'd like to transform my F# OOP version of Tagless Final into a typical FP approach and I'm thinking to use Statically Resolved Type Parameters of Type Classes from OO.
What I've done is
open System
open FSharpPlus
type UserName = string
type DataResult<'t> = DataResult of 't with
static member Map ( x:DataResult<'t> , f) =
match x with
| DataResult t -> DataResult (f t)
creating the SRTP I need
type Cache =
static member inline getOfCache cacheImpl data =
( ^T : (member getFromCache : 't -> DataResult<'t> option) (cacheImpl, data))
static member inline storeOfCache cacheImpl data =
( ^T : (member storeToCache : 't -> unit) (cacheImpl, data))
type DataSource() =
static member inline getOfSource dataSourceImpl data =
( ^T : (member getFromSource : 't -> DataResult<'t>) (dataSourceImpl, data))
static member inline storeOfSource dataSourceImpl data =
( ^T : (member storeToSource : 't -> unit) (dataSourceImpl, data))
and their concrete implementations
type CacheNotInCache() =
member this.getFromCache _ = None
member this.storeCache _ = ()
type CacheInCache() =
member this.getFromCache user = monad {
return! DataResult user |> Some}
member this.storeCache _ = ()
type DataSourceNotInCache() =
member this.getFromSource user = monad {
return! DataResult user }
type DataSourceInCache() =
member this.getFromSource _ =
raise (NotImplementedException())
by which I can define a tagless final DSL
let requestData (cacheImpl: ^Cache) (dataSourceImpl: ^DataSource) (userName:UserName) = monad {
match Cache.getOfCache cacheImpl userName with
| Some dataResult ->
return! map ((+) "cache: ") dataResult
| None ->
return! map ((+) "source: ") (DataSource.getOfSource dataSourceImpl userName) }
and that kind of works as follows
[<EntryPoint>]
let main argv =
let cacheImpl1 = CacheInCache()
let dataSourceImpl1 = DataSourceInCache()
let cacheImpl2 = CacheNotInCache()
let dataSourceImpl2 = DataSourceNotInCache()
requestData cacheImpl1 dataSourceImpl1 "john" |> printfn "%A"
//requestData (cacheImpl2 ) dataSourceImpl2 "john" |> printfn "%A"
0
The problem is that I'm getting the warning
construct causes code to be less generic than indicated by the type
annotations
for both cacheImpl1 and dataSourceImpl1 and so I can't reuse requestData for the other case.
Is there a way to detour this issue?
I'm not familiar with the abstraction you're trying to implement, but looking at your code it seems you're missing an inline modifier here:
let inline requestData (cacheImpl: ^Cache) (dataSourceImpl: ^DataSource) (userName:UserName) = monad {
match Cache.getOfCache cacheImpl userName with
| Some dataResult ->
return! map ((+) "cache: ") dataResult
| None ->
return! map ((+) "source: ") (DataSource.getOfSource dataSourceImpl userName) }
As a side note, you can simplify your map function like this:
type DataResult<'t> = DataResult of 't with
static member Map (DataResult t, f) = DataResult (f t)
I am familiar with final tagless, but I'm not sure why you would use SRTPs.
Final tagless uses type classes, and these can be emulated with interfaces (see the way scala emulates typeclasses).
The approach is similar to (basically the same) as "object algebra", which can be implemented using standard OO constructs.
I want to be able to just
let upcast'<'T,'TResult when 'T :> 'TResult> (y:'T) = y |> upcast
However, that then constrains 'T to be 'TResult instead of it being something that can be cast to 'TResult
I know I can
|> fun x -> x :> 'TResult
|> fun x -> upcast x
|> fun x -> x :> _
but then if I'm doing anything else on that line I have to go back and put () around the fun x -> upcast x or it thinks what I'm doing is part of the fun x function.
can I define or does there exist a way to be able to
|> upcast |> doesn't work
|> ( ( :> ) 'TResult) doesn't work and is messy
edit
In response to Thomas Petricek - minimal failing auto-upcast sample:
module Test =
let inline f'<'t>():IReadOnlyCollection<'t> =
List.empty
|> ResizeArray
|> System.Collections.ObjectModel.ReadOnlyCollection
|> fun x -> x :> IReadOnlyCollection<_>
let inline f<'t> () :IReadOnlyCollection<'t> =
List.empty
|> ResizeArray
|> System.Collections.ObjectModel.ReadOnlyCollection
As far as I know, specifying the kind of constraint between 'T and 'TResult is not possible. There is a related question about this with links to more information and a feature request.
That said, I wonder why do you need this? The F# compiler is able to insert upcasts automatically, even when using pipes, so if you want to do this as part of a longer pipe, it should not be needed. Here is a simple illustration:
type Animal = interface end
type Dog = inherit Animal
let makeDog () = { new Dog }
let consumeAnimal (a:Animal) = 0
makeDog () |> consumeAnimal
I guess you might need pipe-able upcast if you wanted to have it at the end of the pipeline, but then I'd just do the upcast on a separate line. Or is your question motivated by some more complicated cases where the implicit upcast does not work?
EDIT 1: Here is a minimal example using ReadOnlyCollection and IReadOnlyList which works:
let foo () : System.Collections.ObjectModel.ReadOnlyCollection<int> = failwith "!"
let bar (x:System.Collections.Generic.IReadOnlyList<int>) = 0
foo() |> bar
EDIT 2: To comment on the update - the problem here is that automatic upcasts are only inserted when passing arguments to functions, but in the second example, the type mismatch is between the result of the pipe and the return type of the function. You can get that to work by adding an identity function of type IReadOnlyCollection<'T> -> IReadOnlyCollection<'T> to the end of the pipe:
let inline f<'t> () :IReadOnlyCollection<'t> =
List.empty
|> ResizeArray
|> System.Collections.ObjectModel.ReadOnlyCollection
|> id<IReadOnlyCollection<_>>
This works, because now the upcast is inserted automatically when passing the argument to the id function - and this then returns a type that matches with the return type of the function.
much simpler and unexpected
let inline f2<'t>() : IReadOnlyCollection<'t> =
List.empty
|> ResizeArray
|> System.Collections.ObjectModel.ReadOnlyCollection
:> _
The following code returns Some "Test" stead of None. Basically, I'm trying to implement the C# code of cObj?.B.A.P.
// Setup
[<AllowNullLiteral>]
type A() =
member x.P = "Test"
[<AllowNullLiteral>]
type B(a:A) =
member x.A = a
[<AllowNullLiteral>]
type C(b:B) =
member x.B = b
// Test
let aObj: A = null
let cObj = new C(new B(aObj))
let r =
cObj |> Option.ofObj
|> Option.map(fun c -> c.B)
|> Option.map(fun b -> b.A)
|> Option.map(fun a -> a.P) // Expect return None since a is null
// printfn "%A" a; will print <null>.
// How can F# got property of null object?
r
It seems F# doesn't treat null as None in the Option.map. Is there a simple fix to make it return None as soon as a null is found?
F#, unlike C#, tries to be explicit everywhere. In the long run this leads to more maintainable and correct programs.
In particular, null has absolutely nothing to do with Option. null is not the same as None. None is a value of type Option, while null is this very vague concept - a value that can be of any type.
If you would like to return None when the argument is null and Some otherwise, what you need is Option.bind, not Option.map. Option.bind takes a function that takes a value (extracted from a previous Option) and returns another Option. Something like this:
let maybeC = Option.ofObj cObj
let maybeB = maybeC |> Option.bind (c -> Option.ofObj c.B)
let maybeA = maybeB |> Option.bind (b -> Option.ofObj b.A)
let maybeP = maybeA |> Option.bind (a -> Option.ofObj a.P)
Or in one go:
let maybeP =
Option.ofObj cObj
|> Option.bind (c -> Option.ofObj c.B)
|> Option.bind (b -> Option.ofObj b.A)
|> Option.bind (a -> Option.ofObj a.P)
If you do this sort of thing very frequently, you can combine Option.bind and Option.ofObj calls and encode that as a separate function:
let maybeNull f = Option.bind (x -> Option.ofObj (f x))
let maybeP =
Option.ofObj cObj
|> maybeNull (c -> c.B)
|> maybeNull (b -> b.A)
|> maybeNull (a -> a.P)
However, if you find yourself buried in nulls like that, I would suggest that perhaps your domain design is not thought through very well. Nulls are not a good modeling tool, they should be avoided as much as possible. I encourage you to rethink your design.
The first argument to Option.map is a function 'T -> 'U. Its parameter is of type 'T, not 'T option. So, in your last lambda fun a -> a.P, a null argument denotes a null of type A, not a null of type A option.
Because the member P of type A just returns the string "Test," the call succeeds and returns even though the receiver is null. If you try to use the self identifier in the body of P, you will instead get a null reference exception.
I wonder why the second line reports a compiler error
the type Relations is not compatible with seq<'a>
while the first infers a type Relation for r.
type Microsoft.Office.Interop.Access.Dao.Database with
member x.f() =
let relations = [for r in x.Relations -> r]
let relations2 = x.Relations |> Seq.map id
()
What precise property makes it possible to loop over Relations using for?
// Edit reproduction step :
I create a blank solution in VS2012, add a reference to Microsoft.Office.Interop.Access.Dao, and paste the code below.
module toto =
type Class1() =
member this.X = "F#"
type Microsoft.Office.Interop.Access.Dao.Database with
member x.f() =
let relations = [for r in x.Relations -> r]
let relations2 = x.Relations |> Seq.map id
()
r is typed as Relation, and not obj
This doesn't entirely mesh with what you've said, but one scenario in which a sequence expression would work but not Seq.map is when a type implements System.Collections.IEnumerable but not System.Collections.Generic.IEnumerable<'T> (aka seq<'T>). For example, in this code t is inferred as obj list, but the next line doesn't compile.
type T() =
interface System.Collections.IEnumerable with
member x.GetEnumerator() = (Seq.init 10 id).GetEnumerator() :> _
let t = [for x in T() -> x]
let t2 = T() |> Seq.map id //ERROR: The type 'T' is not compatible with the type 'seq<'a>'
This scenario is especially common for libraries created prior to .NET 2.0.
...or, how do I filter a sequence of classes by the interfaces they implement?
Let's say I have a sequence of objects that inherit from Foo, a seq<#Foo>. In other words, my sequence will contain one or more of four different subclasses of Foo.
Each subclass implements a different independent interface that shares nothing with the interfaces implemented by the other subclasses.
Now I need to filter this sequence down to only the items that implement a particular interface.
The C# version is simple:
void MergeFoosIntoList<T>(IEnumerable<Foo> allFoos, IList<T> dest)
where T : class
{
foreach (var foo in allFoos)
{
var castFoo = foo as T;
if (castFoo != null)
{
dest.Add(castFoo);
}
}
}
I could use LINQ from F#:
let mergeFoosIntoList (foos:seq<#Foo>) (dest:IList<'a>) =
System.Linq.Enumerable.OfType<'a>(foos)
|> Seq.iter dest.Add
However, I feel like there should be a more idiomatic way to accomplish it. I thought this would work...
let mergeFoosIntoList (foos:seq<#Foo>) (dest:IList<'a>) =
foos
|> Seq.choose (function | :? 'a as x -> Some(x) | _ -> None)
|> Seq.iter dest.Add
However, the complier complains about :? 'a - telling me:
This runtime coercion or type test from type 'b to 'a involves an indeterminate type based on information prior to this program point. Runtime type tests are not allowed on some types. Further type annotations are needed.
I can't figure out what further type annotations to add. There's no relationship between the interface 'a and #Foo except that one or more subclasses of Foo implement that interface. Also, there's no relationship between the different interfaces that can be passed in as 'a except that they are all implemented by subclasses of Foo.
I eagerly anticipate smacking myself in the head as soon as one of you kind people points out the obvious thing I've been missing.
You can do this:
let foos = candidates |> Seq.filter (fun x -> x :? Foo) |> Seq.cast<Foo>
Typically just adding a 'box' is sufficient (e.g. change function to fun x -> match box x with), but let me try it out...
Yeah; basically you cannot sideways cast from one arbitrary generic type to another, but you can upcast to System.Object (via box) and then downcast to anything you like:
type Animal() = class end
type Dog() = inherit Animal()
type Cat() = inherit Animal()
let pets : Animal list =
[Dog(); Cat(); Dog(); Cat(); Dog()]
printfn "%A" pets
open System.Collections.Generic
let mergeIntoList (pets:seq<#Animal>) (dest:IList<'a>) =
pets
|> Seq.choose (fun p -> match box p with
| :? 'a as x -> Some(x) | _ -> None) //'
|> Seq.iter dest.Add
let l = new List<Dog>()
mergeIntoList pets l
l |> Seq.iter (printfn "%A")
From https://gist.github.com/kos59125/3780229
let ofType<'a> (source : System.Collections.IEnumerable) : seq<'a> =
let resultType = typeof<'a>
seq {
for item in source do
match item with
| null -> ()
| _ ->
if resultType.IsAssignableFrom (item.GetType ())
then
yield (downcast item)
}
Another option for those inclined:
Module Seq =
let ofType<'a> (items: _ seq)= items |> Seq.choose(fun i -> match box i with | :? 'a as a -> Some a |_ -> None)
I have an open source library available on nuget, FSharp.Interop.Compose
That Converts most Linq methods into a idomatic F# form. Including OfType
Test Case:
[<Fact>]
let ofType () =
let list = System.Collections.ArrayList()
list.Add(1) |> ignore
list.Add("2") |> ignore
list.Add(3) |> ignore
list.Add("4") |> ignore
list
|> Enumerable.ofType<int>
|> Seq.toList |> should equal [1;3]