Simulating higher-kinded polymorphism with Object Algebra's in F# - f#

In the paper Streams à la carte: Extensible Pipelines with
Object Algebras Biboudis et al. outline a method of "emulating type-constructor ploymorphism" using object algebras.
I am trying to use this method to implement a higher-order example, similar to those described in Typed Tagless Final Interpreters, within F# and have the following:
type App<'f,'a> = interface end
type ExprSYM<'f,'a> =
abstract litInt: int -> App<'f,int>
abstract litBool : bool -> App<'f,bool>
abstract add : App<'f,int> -> App<'f,int> -> App<'f,int>
abstract gt : App<'f,int> -> App<'f,int> -> App<'f,bool>
abstract conj : App<'f,bool> -> App<'f,bool> -> App<'f,bool>
The section relating to Brand Freshness describes nesting a class inside a type constructor. My translation to F# looks like:
type Eval<'a> =
static member t = new obj()
static member prj (app : App<Eval.t,'a>) = app :> Eval<'a>
inherit App<Eval.t,'a>
However, I get the error The type 't' is not defined.
What is the correct way to write this in F#?

Using a nested class doesn't particularly buy you anything; as the authors say
In the Yallop and White technique for OCaml, this is ensured syntactically by the “freshness” of the brand, t, which is private to the type constructor. In Java, the property is ensured by convention: every subtype S of App has a locally defined brand t and no subtype of App<S.t, X> other than S exists.
so you can obtain the same result with a different convention in F# (which doesn't support nested classes or static members within interfaces). For example, you could create the subclass plus a separate marker class inside a module:
module Pull =
type t = class end
type Pull<'t> =
inherit App<t, 't>
let prj (app : App<t, 't>) = app :?> Pull<'t>
and then ensure that you don't use Pull.t elsewhere.

Related

Why is this code not sufficiently generic or even better why is that even checked?

I get an error on the definition of ToBar
type Foo = {foo: string}
type Bar = {bar: string}
[<AbstractClass>]
type AbstractType< ^T> (fn: ^T -> Foo) =
member inline this.ToFoo (x: ^T) = fn x
abstract ToBar: string -> Bar
This is the error message
This code is not sufficiently generic.
The type variable ^T could not be generalized
because it would escape its scope.
Apart from the fact that (even after reading all other SO questions on this) I don't get what this error tries to tell me ... but it is totally stunning that ToBar which does not even use that type parameter is getting an error
This happens because ToBar is not inline, which is a requisite for using statically resolved type constraints. But it seems that you don't really need them, simple generics would be enough. So just replace ^T with 'T, and it will work fine:
[<AbstractClass>]
type AbstractType<'T> (fn: 'T -> Foo) =
member inline this.ToFoo (x: 'T) = fn x
abstract ToBar: string -> Bar
If you think about it a bit more, it only makes sense: an abstract member can't really make use of SRTC, because it's dispatched at runtime, and SRTC-types need to be known at compile time.
On a related note, even if you get rid of ToBar in an effort to keep SRTC, you'll hit the next error:
error FS1113: The value 'ToFoo' was marked inline but its implementation makes use of an internal or private function which is not sufficiently accessible
This can be fixed by making the type itself private:
type private AbstractType< ^T> (fn: ^T -> Foo) =
member inline this.ToFoo (x: ^T) = fn x
This will work, because the type won't be accessible from outside assemblies, and therefore won't need to expose its SRTC parameters.

Passing arguments by reference in curried arguments

I'm attempting to implement the interface IDispatchMessageInspector (of WCF fame) in F#:
open System.ServiceModel.Dispatcher
open System.ServiceModel.Channels
type ServiceInterceptor() as interceptor =
abstract member PreInvoke : byref<Message> -> obj
abstract member PostInvoke : byref<Message> -> obj -> unit
default x.PreInvoke m = null
default x.PostInvoke m s = ()
interface IDispatchMessageInspector with
member x.AfterReceiveRequest(request, channel, instanceContext) = interceptor.PreInvoke(&request)
member x.BeforeSendReply(reply : byref<Message>, correlationState) = interceptor.PostInvoke &reply correlationState
This fails to compile with the following error:
However, if I modify my code to the following (note the change of signature in PostInvoke) everything works:
open System.ServiceModel.Dispatcher
open System.ServiceModel.Channels
type ServiceInterceptor() as interceptor =
abstract member PreInvoke : byref<Message> -> obj
abstract member PostInvoke : byref<Message> * obj -> unit
default x.PreInvoke m = null
default x.PostInvoke (m, s) = ()
interface IDispatchMessageInspector with
member x.AfterReceiveRequest(request, channel, instanceContext) = interceptor.PreInvoke(&request)
member x.BeforeSendReply(reply : byref<Message>, correlationState) = interceptor.PostInvoke(&reply, correlationState)
Is this behaviour expected? And if so could someone explain the reasoning behind it....
The reason is that byref<'T> is not a real type in .NET. F# uses this for representing values that are passed via ref and out parameters, but it is not a normal type that could appear anywhere in your program.
F# restricts the scope in which they can be used - you can only use them for local variables (basically passing around a reference or a pointer) and you can use them as method parameters (where the compiler can then compile it as a method parameter).
With curried methods, the compiler is producing a property that returns a function value and so (under the cover), you get something like a property PostInvoke of type FSharpFunc<T1, FSharpFunc<T2, T3>>. And here, T1 or T2 cannot be byref<T> types, because byref is not a real .NET type. So that's why curried methods cannot have byref parameters.
Another case where you can see this is if you, for example, try to create a list of byref values:
let foo () =
let a : list<byref<int>> = []
a
Here you get:
error FS0412: A type instantiation involves a byref type. This is not permitted by the rules of Common IL.

What would be the inferred type of my function here?

I am wondering why F# compiler allows the following
type MyMath() =
member this.Add a b = a + b
What would be the type of Add method and its arguments ? If I compiled this into the Library and try to use it in C# what types of arguments it is going to expect ?
Shouldn't the F# require you to explicitly specify types when it comes to Methods of classes ?
You can enter the code in F# interactive and see the inferred type yourself:
> type MyMath() =
member this.Add a b = a + b;;
type MyMath =
class
new : unit -> MyMath
member Add : a:int -> b:int -> int
end
Here, the compiler uses default type for the + operator which is int. The operator can be used with other types, but the inference uses int as the default. You can use type annotations, but you are not required to do that if you are happy with the inferred type.
In general, you can use type annotations in F# to specify types if you want to, but in many cases, the inferred type will be exactly what you want, so you do not have to make the code more verbose, if the inference behaves as expected.
Of course, if you were writing some library and wanted to be super careful about changing the API, then you might want to use type annotations (or you can add F# Interface file .fsi)
F# Interactive is your friend:
type MyMath =
class
new : unit -> MyMath
member Add : a:int -> b:int -> int
end

why is the implementation of my abstract member not public

I've been struggling to get this to compile for about an hour. It must be something stupid. Can you spot it?
in my lib project:
namespace TravelerStuff
open System
type Traveler =
abstract GetData : unit -> unit
type public DeltaTraveler() =
interface Traveler with
member v.GetData () =
printf "hello"
and in my console test app:
[<EntryPoint>] let main _ =
let traveler = new TravelerStuff.DeltaTraveler()
traveler.GetData // this line won't compile: (The field, constructor or member 'GetData' is not defined)
As gradbot says, F# doesn't currently implicitly convert values to interfaces when searching for members. Also, F# only uses explicit interface implementation (as known from C#) and not implicit implementation where members are not only compiled as implementation of an interface, but also as ordinary (directly visible) members of the type.
Aside from casting, you can duplicate the member in the type definition:
type DeltaTraveler() =
member v.GetData () = printf "hello"
interface Traveler with
member v.GetData () = v.GetData()
Also, if you just want to implement an interface, but don't need to add any members, you can use F# object expressions (which are more lightweight):
let deltaTraveler() =
{ new Traveler with
member v.GetData () = printf "hello" }
// The function directly returns value of type 'Traveler'
let t = deltaTraveler()
t.GetData()
You need to upcast. F# currently won't do it for you in this situation.
(traveler :> TravelerStuff.Traveler).GetData()
// open the namespace to reduce typing.
open TravelerStuff
(traveler :> Traveler).GetData()
Snip from F# docs.
In many object-oriented languages,
upcasting is implicit; in F#, the
rules are slightly different.
Upcasting is applied automatically
when you pass arguments to methods on
an object type. However, for let-bound
functions in a module, upcasting is
not automatic, unless the parameter
type is declared as a flexible type.
For more information, see Flexible Types (F#).

Static extension methods supporting member constraints

I need to implement a static extension method supporting member constraints on some basic primitive types like integers, floats, etc. Here's my code for signed integers:
module MyOperators =
let inline foo (x : ^T) = (^T : (static member Foo : ^T -> int) (x))
type System.Int32 with
static member Foo(x : Int32) = 7 // static extension
Test code:
open MyOperators
let x = foo 5 // x should be 7
But compiler complains with error:
The type 'System.Int32' does not
support any operators named 'Foo'
What am I missing here? Thanks!
Static member constraints in F# never find 'extension methods', they can only see intrinsic methods on types (and a few special cases called out in the F# language spec).
Perhaps you can use method overloading instead? What is your ultimate goal?
F#'s static type constraints don't work with extension methods. Extension methods cannot statically be checked at compile time, and even so, you can have multiple definitions for Int32::Foo (depending on which namespace you imported).
Unfortunately, to solve your problem you might have to resort to using reflection.

Resources