Can please someone explain this to me:
type IItem = interface end
type Item = {i:int} interface IItem
type Fail = static member foo (s:string) = fun (x:IItem) -> ""
let foo = fun (s:string) -> fun (x:IItem) -> ""
let works = {i=1} |> foo ""
let fails = {i=1} |> Fail.foo ""
Why does the currying with the static member function not work?
I'm using Visual Studio 2012 with .net 4.5.2 if that matters.
This isn't really a difference between static members and functions - it's a bit more subtle. Here's another repro:
type T =
static member A () (o:obj) = ()
static member B () = fun (o:obj) -> ()
T.A () 1 // ok
T.B () 1 // huh?
Note that the signatures of T.A and T.B are different (this is actually covered in section 11.2.1.1 of the spec):
type T =
class
static member A : unit -> o:obj -> unit
static member B : unit -> (obj -> unit)
end
This is a distinction that is usually unimportant, but basically it means that at a .NET representation level A is compiled to a method with two arguments (even though it looks curried in F#) while B is compiled to a method with a single argument which returns an F# function. This difference is ultimately what causes the behavior you're seeing.
Related
During refactoring of some code, I noticed a situation where code breaks when moved around:
type ThingBase () = class end
and Functions =
static member Create<'T when 'T :> ThingBase and 'T : (new : Unit -> 'T)> () = new 'T ()
and Thing () =
inherit ThingBase ()
static member Create () = Functions.Create<Thing> ()
// This works, but try moving the Functions type here instead.
If you move the Functions type below the Thing type, the code breaks unexpectedly:
type ThingBase () = class end
and Thing () =
inherit ThingBase ()
static member Create () = Functions.Create<Thing> ()
// ^^^^^^^^^^^^^^^^^^^^^^^^^^
// This construct causes code to be less generic than indicated by the
// type annotations. The type variable 'T has been constrained to be
// type 'Thing'.
and Functions =
static member Create<'T when 'T :> ThingBase and 'T : (new : Unit -> 'T)> () = new 'T ()
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// The type ''T' does not match the type 'Thing'.
And no matter what I try, I cannot get this to typecheck. Why is the type inference so stubborn and refusing to generalize the Create method.
By the way, I also attempted F# 4.1 module rec and it also doesn't matter if Create is a function in a module either.
Any insights? To me it seems this should be something the compiler shouldn't have any troubles with.
It will compile if you do this
static member Create<'T when 'T :> ThingBase
and 'T : (new : Unit -> 'T)> () : 'T = new 'T ()
// ^^^^
where the return type is explicitly stated.
Recursive definitions are typechecked left-to-right in two passes; first function/method signatures, then bodies. You need the body (or an explicit return type annotation) to get the result type, so you either need the body to come first, or else the annotation so that it gets solved in the first of the two passes.
I have no idea why the compiler over-constrains the type parameter of the Create method when you move it up. A work-around could be an intrinsic type extension, so you can split the type definition into multiple sections. Which can help to avoid recursive dependencies.
type ThingBase () = class end
type Thing () =
inherit ThingBase ()
type Functions =
static member Create<'T when 'T :> ThingBase and 'T : (new : Unit -> 'T)> () =
new 'T ()
type Thing with
static member Create () = Functions.Create<Thing> ()
If you want to keep moving forward with that pattern, here's how to do it. I'm assuming you want some kind of factory pattern embedded in the base.
Incidentally, when #Fyodor says left-to-right, this also means top-down. So... you may be fighting against this, too, even though the and functionality should logically, be working. I also agree re: flatter hierarchies, but sometimes, we don't get to have the luxury of choice for various reasons.
type ThingBase () = class end
and Thing () =
inherit ThingBase ()
and Functions() =
static member Create<'T when 'T :> ThingBase and 'T : (new : Unit -> 'T)> () = new 'T ()
and Thing with
static member Create () = Functions.Create<Thing> ()
// typically, I'd prefer
//type Thing with
// static member Create () = Functions.Create<Thing> ()
// or
//module Thing =
// let Create() = Functions.Create<Thing> ()
references:
https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/type-extensions
The below is incorrect. Apparently recursive definitions get two passes of type checking - once for signatures, then for implementations. I'm leaving the answer here anyway, just for reference.
Original answer
Type inference works left to right, in one pass. Once it encountered a call to Functions.Create, it has decided what the signature has to be, and later augmentations can't change that.
It's the same reason that xs |> Seq.map (fun x -> x.Foo) works, but Seq.map (fun x -> x.Foo) xs doesn't: in the first instance the type of x is known from the previous encounter of xs, and in the second instance it's not known, because xs hasn't been encountered yet.
P. S. You don't actually need a recursive group there. There are no recursive dependencies between your types.
I'm using a third party library (Sauve.IO) which defines the standard bind operator >>= :
val inline (>>=) : first:('T -> Async<'U option>) -> second:('U -> Async<'V option>) -> input:'T -> Async<'V option>
I also have an internal library that would also like to define the operator over the type signature
Async<Response<'a>> -> ('a -> Async<Response<'b>>) -> Async<Response<'b>>
What is the cleanest way to use these two functions in the same namespace/module without running afoul of the restriction on overloading inline functions ?
How about renaming Suave's operator to some other infix operator?
let (>=>) = Suave.(>>=)
Judging from the signature, it looks like it is not bind anyway,
but actually Kleisli composition.
You may be able to leverage F#'s statically resolved ad-hoc polymorphism: hide the qualified operator invocation behind a separate, overloaded operator; then define yet another, inlined operator for actual use.
type Foo = Foo with
static member ($) (_ : Foo, first : _ -> Async<_ option>) =
fun second value -> Module1.(>>=) first second value
static member ($) (_ : Foo, arg1 : Async<Response<_>>) =
Module2.(>>=) arg1
let inline (>>=) arg1 arg2 = (Foo $ arg1) arg2
Do both operators have the same name (>>=) ?
If so I assume that Suave's operator came with it's own module or namespace?
In this case you can qualify their operator appending their module/namespace name like this Suave.(>>=) but in this case you have to call it as usual function. Here is simplified example:
module Suave =
let inline (>>=) a b = a + 2 * b
module Mine =
open Suave
let (>>=) a b = a - 3 * b
let r1 = Suave.(>>=) 1 3
let r2 = 1 >>= 3
Result:
val r1 : int = 7
val r2 : int = -8
This question is based on the Functional Random Generators in week one of this course: https://www.coursera.org/course/reactive
The course is Scala based, I'm trying to replicate it in FSharp.
Here's my problem:
I have an abstract generator
[<AbstractClass>]
type Generator<'a>() =
abstract member Generate: 'a
And I have an implementation of that that generates random integers
type IntGenerator() =
inherit Generator<Int32>()
let rand = new System.Random()
override this.Generate = rand.Next(Int32.MinValue, Int32.MaxValue)
Now, I want to add a Map method to my base class so that new types of generators can be created using code like this
let integers = new IntGenerator()
let booleans = integers.Map (fun x -> x > 0)
So, here's how I modified the base class
[<AbstractClass>]
type Generator<'a>() =
abstract member Generate: 'a
member this.Map (f:'a -> 'b) = { new Generator<'b>() with member this.Generate = f base.Generate }
Unfortunately that call to base.Generate seems to be constraining the type 'b to the same as 'a
I don't get why. I'm sure I'm tripping up on something simple.
The problem here is that you have to be careful with the instance names of the member methods:
I think this should work out:
[<AbstractClass>]
type Generator<'a>() =
abstract member Generate: unit -> 'a
static member Map (f:'a -> 'b) =
fun (g : Generator<'a>) ->
{ new Generator<'b>() with
member this.Generate () = g.Generate () |> f
}
or if you insist on the member-method:
[<AbstractClass>]
type Generator<'a>() =
abstract member Generate: unit -> 'a
member this.Map (f:'a -> 'b) : Generator<'b> =
{ new Generator<'b>() with
member __.Generate () = this.Generate () |> f
}
note the differences with the this and base and __ ;)
BTW this will even work without the unit -> (as you wrote it):
[<AbstractClass>]
type Generator<'a>() =
abstract member Generate: 'a
member this.Map (f:'a -> 'b) : Generator<'b> =
{ new Generator<'b>() with
member __.Generate = this.Generate |> f
}
but I would not recommend this as you get a value-looking method in disguise: Generate
more idiomatic way
type Generator<'a> = unit -> 'a
module Generator =
let map (f:'a -> 'b) (g : Generator<'a>) =
fun () -> g () |> f
let intGenerator : Generator<int> =
let rand = new System.Random()
fun () -> rand.Next(System.Int32.MinValue, System.Int32.MaxValue)
fun fact
As you can see here (if you look closely) you will see that this map is really just the Functor-map for unit -> * ;)
disclaimer but of course as the generators are sadly impure none of the functor-laws will really hold (if you don't fix your system time)
type MyOpenFileDialog(dg: OpenFileDialog) =
member x.ShowDialog = dg.ShowDialog
member x.OpenFile = dg.OpenFile
type MySaveFileDialog(dg: SaveFileDialog) =
member x.ShowDialog = dg.ShowDialog
member x.OpenFile = dg.OpenFile
The following indicated 'T (^T) would escape it's scope:
type MyFileDialog<'T
when
'T : (member OpenFile:unit->Stream) and
'T : (member ShowDialog:unit->Nullable<bool>)
>(dg: 'T) =
member x.ShowDialog = dg.ShowDialog
member x.OpenFile = dg.op
Note, the constraint expression MyFileDialog<'T...>(dg: 'T)= should all be on one line. Is split for clarity (should be allowed in language I think :) )
Static member constraints let you do quite a lot of things, but they are somewhat cumbersome (they work well for generic numerical computations, but not so well as a general-purpose abstraction). So, I would be careful about using them.
Anyway, if you want to do this, then you can - to some point. As John mentioned in the comments, code that uses static member constraints need to be inline. But you can make that a static member, which captures the operations that your type uses:
type MyFileDialog
private(openFile:unit -> Stream, showDialog : unit -> DialogResult) =
member x.OpenFile() = openFile()
member x.ShowDialog() = showDialog()
static member inline Create(dg : ^T) =
MyFileDialog
( (fun () -> (^T : (member OpenFile:unit -> Stream) dg)),
(fun () -> (^T : (member ShowDialog:unit -> DialogResult) dg)) )
let d1 = MyFileDialog.Create(new OpenFileDialog())
let d2 = MyFileDialog.Create(new SaveFileDialog())
I have the following code snippet using the reactive extensions:
let value : 't = ...
Observable.Create<'t>(fun observer ->
let subject = new BehaviorSubject<'t>(value)
let d0 = subject.Subscribe(observer)
let d1 = observable.Subscribe(subject)
new CompositeDisposable(d0, d1) :> IDisposable
)
This works. However if I drop the upcast to IDisposable then the code fails
to compile, citing ambiguous overloads. However CompositeDisposable is an
IDisposable. Why is the type inference engine failing to resolve this? Note I use this pattern almost all the time in C# returning CompositeDisposable from Observable.Create without having to upcast.
As #kvb said, functions don't support variance so upcast is required for interfaces and subclasses.
Here is a small example demonstrating the behavior with subclasses:
type A() =
member x.A = "A"
type B() =
inherit A()
member x.B = "B"
let f (g: _ -> A) = g()
let a = f (fun () -> A()) // works
let b = f (fun () -> B()) // fails
If function f is written by you, adding type constraints could help:
// This works for interface as well
let f (g: _ -> #A) = g()
let a = f (fun () -> A()) // works
let b = f (fun () -> B()) // works
Otherwise, you have to do a litle upcast as your example described.
EDIT: Since F# 6.0, auto-upcasting of interfaces and subclasses is now supported by default.