Filter by constraint - f#

Ok, I realise this might be a weird question. But I need to ask it anyway. It goes as follows:
Suppose I have something like the following:
type Foo() =
member this.MyFooFun i = 2*i
type Bar() =
inherit Foo()
member this.MyBarFun i = 3*i
type Baz() =
inherit Foo()
member this.MyBazFun i = 5*i
type FooSeq = seq<Foo>
What I want to do, is to filter out all the Foo's from a FooSeq that has the member MyBarFun. Is it possible to do anything like that?
I realise I will probably have to use the :? operator to check whether each element is a Bar, but as I said - I have to ask. The reason I would rather not do this, is that the types corresponding to Foo, Bar and Baz lies in a library developed somewhere else in the company. And there might be added more types containing the MyBarFun-member at any given time.

If you only want to filter on the subtype, it's easy:
let foos = candidates |> Seq.filter (fun x -> not (x :? Bar))
If you explicitly want to filter away types that have a member called "MyBarFun", you'll need to use reflection:
let foos' =
candidates
|> Seq.filter (fun x ->
not (x.GetType().GetMembers() |> Array.exists (fun m ->
m.Name = "MyBarFun")))

Related

What is missing using interfaces compared to true type-classes?

F# does not (currently) support type-classes. However, F# does support the OOP aspects of C#.
I was wondering, what is lost doing this approach compared to true type-classes?
// A concrete type
type Foo =
{
Foo : int
}
// "Trait" for things that can be shown
type IShowable =
abstract member Show : unit -> string
module Showable =
let show (showable : IShowable) =
showable.Show()
// "Witness" of IShowable for Foo
module Foo =
let asShowable (foo : Foo) =
{
new IShowable with
member this.Show() = string foo.Foo
}
// Slightly awkward usage
{ Foo = 123 }
|> Foo.asShowable
|> Showable.show
|> printfn "%s"
Your suggestion works for simple typeclasses that operate on a single value of a type, like Show. However, what happens when you need a typeclass that isn't so object-oriented? For example, when we want to add two numbers, neither one corresponds to OO's this object:
// not real F#
typeclass Numeric<'a> = // e.g. Numeric<int> or Numeric<float>
abstract member (+) : 'a -> 'a -> 'a // e.g. 2 + 3 = 5 or 2.0 + 3.0 = 5.0
...
Also, keep in mind that many useful typeclasses require higher-kinded types. For example, consider the monad typeclass, which would look something like this:
// not real F#
typeclass Monad<'m<_>> = // e.g. Monad<Option<_>> or Monad<Async<_>>
abstract member Return<'a> : 'a -> 'm<'a>
abstract member Bind<'a, 'b> : 'm<'a> -> ('a -> 'm<'b>) -> 'm<'b>
There's no good way to do this with .NET interfaces.
Higher-kinded type classes are indeed impossible to model with interfaces, but that's just because F# does not support higher-kindedness, not because of type classes themselves.
The deeper thing to note is that your encoding isn't actually correct. Sure, if you just need to call show directly, you can do asShowable like that, but that's just the simplest case. Imagine you needed to pass the value to another function that wanted to show it later? And then imagine it was a list of values, not a single one:
let needsToShow (showable: IShowable) (xs: 'a list) =
xs |> List.iter (fun x -> ??? how do I show `x` ???)
No, this wouldn't do of course. The key is that Show should be a function 'a -> string, not unit -> string. And this means that IShowable itself should be generic:
// Haskell: class Showable a where show :: a -> String
type IShowable<'a> with
abstract member Show : 'a -> string
// Haskell: instance Showable Foo where show (Foo i) = show i
module Foo =
let showable = { new IShowable<Foo> with member _.Show foo = string foo.Foo }
// Haskell: needsToShow :: Show a => [a] -> IO ()
let needsToShow (showable: IShowable<'a>) (xs: 'a list) =
xs |> List.iter (fun x -> printfn "%s" (showable.Show x))
// Haskell: needsToShow [Foo 1, Foo 42]
needsToShow Foo.showable [ { Foo: 1 }; { Foo: 42 } ]
And this is, essentially, what type classes are: they're indeed merely dictionaries of functions that are passed everywhere as extra parameters. Every type has such dictionary either available right away (like Foo above) or constructable from other such dictionaries, e.g.:
type Bar<'a> = Bar of 'a
// Haskell: instance Show a => Show (Bar a) where show (Bar a) = "Bar: " <> show a
module Bar =
let showable (showA: IShowable<'a>) =
{ new IShowable<Bar<'a>> with member _.Show (Bar a) = "Bar: " + showA.Show a }
This is completely equivalent to type classes. And in fact, this is exactly how they're implemented in languages like Haskell or PureScript in the first place: like dictionaries of functions being passed as extra parameters. It's not a coincidence that constraints on function type signatures even kinda look like parameters - just with a fat arrow instead of a thin one.
The only real difference is that in F# you have to do that yourself, while in Haskell the compiler figures out all the instances and passes them for you.
And this difference turns out to be kind of important in practice. I mean, sure, for such a simple example as Show for the immediate parameter, you can just pass the damn instance yourself. And even if it's more complicated, I guess you could suck it up and pass a dozen extra parameters.
But where this gets really inconvenient is operators. Operators are functions too, but with operators there is nowhere to stick an extra parameter (or dozen). Check this out:
x = getY >>= \y -> getZ y <&> \z -> y + 42 > z
Here I used four operators from four different classes:
>>= comes from Monad
<&> from Functor
+ from Num
> from Ord
An equivalent in F# with passing instances manually might look something like:
let x =
bind Foo.monad getY <| fun y ->
map Bar.functor (getZ y) <| fun z ->
gt Int.ord (add Int.num y 42) z
Having to do that everywhere is quite unreasonable, you have to agree.
And this is why many F# operators either use SRTPs (e.g. +) or rely on "known" interfaces (e.g. <) - all so you don't have to pass instances manually.

Strongly typed but user-extensible collection in F#?

I am designing a data-structure for interacting with a C# API from F#. Broadly speaking, it is a strongly-typed collection of components (ComponentCollection), where components may have different types.
A first-pass looks like this:
type Foo =
{
Foo : int
}
type Bar =
{
Bar : string
}
type ComponentCollection =
{
FooComponents : Map<Foo, Component<Foo>>
BarComponents : Map<Bar, Component<Bar>>
}
module ComponentCollection =
let addFoo foo comp xs =
{ xs with FooComponents = xs.FooComponents |> Map.add foo comp }
let addBar bar comp xs =
{ xs with BarComponents = xs.BarComponents |> Map.add bar comp }
let tryFindFoo foo xs =
xs.FooComponents |> Map.tryFind foo
let tryFindBar bar xs =
xs.BarComponents |> Map.tryFind bar
There are two problems with this design:
Repetition of boiler-plate code (e.g. addFoo, addBar, tryFindFoo, ...)
The type of components is not extensible without changing the type ComponentCollection, e.g. a user cannot add QuxComponents : Map<Qux, Component<Qux>> themselves
I can redesign things using interfaces, but this loses much of the type safety F# is famous for!
open System
type ComponentKey =
interface
inherit IComparable
end
type Foo =
{
Foo : int
}
with interface ComponentKey
type Bar =
{
Bar : string
}
with interface ComponentKey
type ComponentCollection =
{
Components : Map<ComponentKey, obj>
}
module ComponentCollection =
let addFoo (foo : Foo) (comp : Component<Foo>) xs =
{ xs with Components = xs.Components |> Map.add (foo :> ComponentKey) (comp :> obj) }
let addBar (bar : Bar) (comp : Component<Bar>) xs =
{ xs with Components = xs.Components |> Map.add (bar :> ComponentKey) (comp :> obj) }
let tryFindFoo (foo : Foo) xs =
xs.Components
|> Map.tryFind (foo :> ComponentKey)
|> Option.map (fun x -> x :?> Component<Foo>) // Big assumption!
let tryFindBar (bar : Bar) xs =
xs.Components
|> Map.tryFind (bar :> ComponentKey)
|> Option.map (fun x -> x :?> Component<Bar>) // Big assumption!
// User can easily add more in their own code
How can I design ComponentCollection achieving type-safety and extensibility?
There's a few layers to this question, so I'll try give an answer that addresses the essence of it without running too long.
What you're essentially trying to get here is a map that is heterogenous both with regard to the key and to the value types. This is not something F# type system is well suited to represent, as it requires support for existential types that F# doesn't have. Let's leave the key part for a moment and talk about values.
What you have done in your second approach with boxing the values is generally a reasonable solution to storing heterogenous values in a collection, and a trade-off that people would often make. You give up some type safety by boxing and casting, but if you restrict access to your Components map by making it private/internal, and ensure it's only accessed through the module functions, you can easily keep the invariant that the type of key matches the type of component.
So you can remove the boilerplate with something like this:
module ComponentCollection =
let add<'key when 'key :> ComponentKey> (key: 'key) (comp: Component<'key>) coll =
{ coll with Components =
coll.Components |> Map.add (key :> ComponentKey) (box comp) }
let tryFind<'key when 'key :> ComponentKey> (key: 'key) coll =
coll.Components
|> Map.tryFind (key :> ComponentKey)
|> Option.map (fun x -> x :?> Component<'key>)
There is a solution around this problem that would work within the F# type system without resorting to casting or reflection, and it involves emulating existential types using a set of wrappers. This approach has been covered in other questions as well as this blog post in great detail. It is however a bulky encoding that would be hard for me to justify in a small project.
There is a separate problem with your proposed solution however - the fact you're using heterogenous keys for the map. As it currently stands, your approach (a marker interface that is essentially an alias for IComparable) will work fine as long as all the keys are of the same type, but the moment you try to add a key of a different type, the operation will fail in the Map internals - as the default comparison implementation would throw an exception when the compared values are of different runtime types.
To avoid that, you should either wrap your keys in a type that would have a custom implementation of comparisons that would circumvent that, or you should consider defining a common key type that you could use with all the component types you expect.

Is there already or can I declare a more pipe friendly upcast?

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
:> _

Is there a way to make different implementation of do! and let! in a computation expression?

I need a different behavior for do! and let! in my custom computation expression.
I try to achieve this in the following way:
type FooBuilder() = class
member b.Bind<'T, 'U>(x:'T, f:unit->'U):'U = failwith "not implemented" //do! implementation
member b.Bind<'T, 'U>(x:'T, f:'T->'U):'U = failwith "not implemented" //let! implementation
member b.Return<'T>(x:'T):'T = failwith "not implemented" //return implementation
end
let foo = FooBuilder()
let x = foo {
do! ()
return 2
}
But compiler gives me an error:
A unique overload for method 'Bind' could not be determined based on type information prior to this program point. The available overloads are shown below (or in the Error List window). A type annotation may be needed.
Is there a way to have a different implementation of do! and let!?
If you want to keep the Bind operation used in let! generic, then there is no way to say that F# should use different implementation when translating do! (the overloads will necessarily have to overlap).
In general, if you want to get different behavior for let! and for do! then it suggests that your computation expression is probably incorrectly defined. The concept is quite flexible and it can be used for more things than just for declaring monads, but you may be stretching it too far. If you can write more information about what you want to achieve, that would be useful. Anyway, here are some possible workarounds...
You can add some additional wrapping and write something like do! wrap <| expr.
type Wrapped<'T> = W of 'T
type WrappedDo<'T> = WD of 'T
type FooBuilder() =
member b.Bind<'T, 'U>(x:Wrapped<'T>, f:'T->'U):'U = failwith "let!"
member b.Bind<'T, 'U>(x:WrappedDo<unit>, f:unit->'U):'U = failwith "do!"
member b.Return<'T>(x:'T):Wrapped<'T> = failwith "return"
let wrap (W a) = WD a
let bar arg = W arg
let foo = FooBuilder()
// Thanks to the added `wrap` call, this will use the second overload
foo { do! wrap <| bar()
return 1 }
// But if you forget to add `wrap` then you still get the usual `let!` implementation
foo { do! wrap <| bar()
return 1 }
Another alternative would be to use dynamic type tests. This is a bit inefficient (and a bit inelegant), but it may do the trick, depending on your scenario:
member b.Bind<'T, 'U>(x:Wrapped<'T>, f:'T->'U):'U =
if typeof<'T> = typeof<unit> then
failwith "do!"
else
failwith "let!"
However, this would still use the do! overload when you write let! () = bar.
You could try something else, a bit ugly, but should work:
let bindU (x, f) = f x // you must use x, or it'll make the Bind method less generic.
let bindG (x, f) = f x
member b.Bind(x : 'a, f : 'a -> 'b) =
match box x with
| :? unit -> bindU (x, f)
| _ -> bindG (x, f)
It boxes a (converts it to obj) and checks if it is of type unit, then redirects to the correct overload.

F# Equivalent to Enumerable.OfType<'a>

...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]

Resources