What's the closest thing to Haskell GADTs and typeclasses in F#? - f#

F# is an ML with OOP. What's the closest it comes to Haskell generalized algebraic data types and typeclasses?

The answer depends on what problem are you trying to solve. F# does not have typeclasses and GADTs, so there is no direct mapping. However, F# has various mechanisms that you would use to solve problems that you typically solve in Haskell using GADTs and typeclasses:
If you want to represent object structures and be able to add new concrete implementations with different behaviour, then you can often use standard OO and interfaces.
If you want to write generic numeric code, you can use static member constraints (here is an example), which is probably technically the closest mechanism to type classes.
If you want to write more advanced generic code (like universal printer or parser) then you can often use the powerful F# runtime reflection capabilities.
If you need to parameterize code by a set of functions (that perform various sub-operations required by the code) then you can pass around an implementation of an interface as #pad shows.
There is also a way to emulate Haskell type classes in F#, but this is usually not an idiomatic F# solution, because the F# programming style differs from the Haskell style in a number of ways. One fairly standard use of this is defining overloaded operators though (see this SO answer).
At the meta-level, asking what is an equivalent to a feature X in aother language often leads to a confused discussion, because X might be used to solve problems A, B, C in one language while another language may provide different features to solve the same problems (or some of the problems may not exist at all).

In F#, you often use interfaces and inheritance for these purposes.
For examples' sake, here is a simple typeclass using interfaces and object expressions:
/// Typeclass
type MathOps<'T> =
abstract member Add : 'T -> 'T -> 'T
abstract member Mul : 'T -> 'T -> 'T
/// An instance for int
let mathInt =
{ new MathOps<int> with
member __.Add x y = x + y
member __.Mul x y = x * y }
/// An instance for float
let mathFloat =
{ new MathOps<float> with
member __.Add x y = x + y
member __.Mul x y = x * y }
let XtimesYplusZ (ops: MathOps<'T>) x y z =
ops.Add (ops.Mul x y) z
printfn "%d" (XtimesYplusZ mathInt 3 4 1)
printfn "%f" (XtimesYplusZ mathFloat 3.0 4.0 1.0)
It may not look very beautiful, but it's F#-ish way to do it. For a more Haskell-like solution which uses a dictionary-of-operations, you can have a look at this nice answer.

Related

F#: Meaning of "type X = Y of Z"

What does type X = Y of Z mean in F#? In particular, does the Y token have any material purpose? If I want to express the fact that X is a type backed by the underlying type Z, why do I need Y in that expression?
According to https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/keyword-reference, the of keyword is used to express one of these:
Discriminated Unions
Delegates
Exception Types
Strictly speaking, according to the docs, type X = Y of Z doesn't fall into ANY of the above 3 categories.
It's not Discriminated Union syntax because it's lacking the pipe | character.
It's not a Delegate, because the delegate keyword is absent.
It's not an Exception Type because the exception type is absent.
So it seems like type X = Y of Z is invalid syntax even though it is used pervasively in https://fsharpforfunandprofit.com/posts/conciseness-type-definitions/. Very puzzling - is it that the docs are inaccurate?
Contrary to your intuition, such declaration is, in fact, a discriminated union - one with just one case. Yes, discriminated unions with only one case are totally legal and are sometimes used for type safety or for hiding implementation details.
If you don't want to have that extra Y in there, that is also legal:
type X = Z
This is called "type alias". Its advantage over discriminated union is resource consumption (both performance and memory), but its drawback is that it doesn't provide any extra safety, because X ends up being equivalent and interchangeable with Z in all contexts.
It's not Discriminated Union syntax because it's lacking the pipe | character.
It's possible to omit the first pipe in a Discriminated union:
type DU = A of int | B
This is bad style for standard multi-line definitions but can be appropriate for one-liners. In your example there is only one case so it is possible to omit the pipe completely, which admittedly causes confusion. It would improve clarity to include the bar: type X = | Y of Z
In type X = Y of Z, does the Y token have any material purpose?
Y is used to disambiguate between cases, and for matching against data. If there are are likely to be more cases in future then it makes sense to have this scaffolding for matching. If you know that there will only ever be one case then a DU is not the most appropriate type, since a record type X = { Y: Z } is a simpler construct which achieves the same purpose.

How to access elements correctly in own defined type in F#

I'm just starting to learn F# and am confused with this school assignment. Please excuse me if this is a dumb question, I couldn't find the answer by searching. The assignment wants me to:
The set of complex numbers is the set of pairs of real numbers.
Define a type complex that represents complex numbers with floating point components.
Define a function mkComplex : float -> float -> complex that given two floating point
numbers return the corresponding complex number.
Define a function complexToPair : complex -> float * float that given a complex number (a,b)
returns the pair (a, b) .
Here's my attempt at this:
first I define the type complex:
type Complex = float * float
I define the function mkComplex:
let mkComplex a b = Complex (a, b)
The function complexToPair is the one giving me trouble. How do I given the complex type access the elements inside it correctly? the following works runs fine but I am getting spammed with typecheck errors.
let complexToPair (a: Complex) = (a.[0], a.[1])
a.[0] and a.[1] is underlined in red and giving me the following warning:
The operator 'expr.[idx]' has been used on an object of indeterminate type based on information prior to this program point. Consider adding further type constraints.
So, what am I doing wrong? The code works just fine.
The type definition that you are using is defining a type alias. When you say:
type Complex = float * float
Then the type Complex is just a tuple. You can create its values using (1.0, 1.0). When you have a value c of this type, you can access elements using fst c and snd c, or by using pattern matching.
Using a type alias is sometimes useful, but I guess that, in this case, it would be more desirable to use a single-case discriminated union or a record, i.e.:
type Complex = { a:float; b:float } // Using a record
type Complex = Complex of float * float // Using a discriminated union
The documentation on F# records explains everything you need to know about using records. For single-case discriminated unions, you can refer to an article in the Desinging with Types series at F# for Fun and Profit.

What is the best way to pass generic function that resolves to multiple types

For the background: It's a variation on functional DI. Following Scott's post I wrote an interpreter. The twist is that my interpreter is generic and parametrized based on what you feed to it.
For testing purposes I'd like to pass another interpreter in, and therein lies the rub - how can I? Here's the simplified outline of the problem:
let y f =
let a = f 1
let b = f 2L
(a,b)
f is my generic interpreter, but here it is obviously constrained by the first use to int -> 'a.
In this simplified scenario I could just pass the interpreter twice, but in my actual implementation the type space is rather large (base type x3 output types).
Is there some F# mechanism that would let me do that, w/o too much overhead?
You can't do this in F# with functions. Functions lose genericity when passed as values.
However, F# does have a mechanism for doing it anyway, albeit a bit awkwardly: interfaces. Interface methods can be generic, so you can use them to wrap your generic functions:
type Wrapper =
abstract member f<'a> : 'a -> 'a
let y (w: Wrapper) =
let a = w.f 1
let b = w.f 2L
(a, b)
let genericFn x = x
// Calling y:
y { new Wrapper with member __.f x = genericFn x }
The downside is, you can't go back to higher-order functions, lest you lose genericity. You have to have interfaces all the way down to the turtles. For example, you can't simplify the instance creation by abstracting it as a function:
let mkWrapper f =
// no can do: `f` will be constrained to a non-generic type at this point
{ new Wrapper with member __.f x = f x }
But you can provide some convenience on the other side. At least get rid of type annotations:
type Wrapper = abstract member f<'a> (x: 'a): 'a
let callF (w: Wrapper) x = w.f x
let y w =
let a = callF w 1
let b = callF w 2L
(a,b)
(NOTE: there may be minor syntactic mistakes in the above code, as I'm writing on my phone)
Not sure if you're still interested, since you already accepted an answer, but as #Fyodorsoikin requested it, here's the 'static' way, it all happens at compile time, so no runtime overhead:
let inline y f =
let a = f $ 1
let b = f $ 2L
(a, b)
type Double = Double with static member inline ($) (Double, x) = x + x
type Triple = Triple with static member inline ($) (Triple, x) = x + x + x
type ToList = ToList with static member ($) (ToList, x) = [x]
let res1 = y Double
let res2 = y Triple
let res3 = y ToList
I use this technique when I need a generic function over arbitrary structures, I use to name the types with a single method 'Invokable'.
UPDATE
To add parameters to the function you add it to the DU, like this:
type Print<'a> = Print of 'a with
static member inline ($) (Print printer, x) = printer (string x)
let stdout (x:string) = System.Console.WriteLine x
let stderr (x:string) = System.Console.Error.WriteLine x
let res4 = y (Print stdout)
let res5 = y (Print stderr)
This is just a quick and simple sample code but this approach can be refined: you can use a method name instead of an operator, you can avoid having to repeat the DU in the declaration, and you can compose Invokables. If you are interested in these enhancements, let me know. I used a refinement of this approach before in production code and never had any issue.
Please look at Crates.
Here is a quick snippet describing the crux of what you want to accomplish. I believe this snippet is valuable in it helps teach us how we can formally reason about using F# and other ML type systems, by using mathematical language. In other words, it not only shows you how, it teaches you the deep principle of why it works.
The issue here is that we have reached a fundamental limitation of what is directly expressible in F#. It follows that the trick to simulating universal quantification is, therefore, to avoid ever passing the function around directly, instead hiding the type parameter away such that it cannot be fixed to one particular value by the caller, but how might one do that?
Recall that F# provides access to the .NET object system. What if we made our own class (in the object-oriented sense) and put a generic method on that? We could create instances of that which we could pass around, and hence carry our function with it (in the form of said method)?
// Encoding the function signature...
// val id<'a> : 'a -> 'a
// ...in terms of an interface with a single generic method
type UniversalId = abstract member Eval<'a> : 'a -> 'a
Now we can create an implementation which we can pass around without the type parameter being fixed:
// Here's the boilerplate I warned you about.
// We're implementing the "UniversalId" interface
// by providing the only reasonable implementation.
// Note how 'a isn't visible in the type of id -
// now it can't be locked down against our will!
let id : UniversalId =
{ new UniversalId with
member __.Eval<'a> (x : 'a) : 'a = x
}
Now we have a way to simulate a universally quantified function. We can pass id around as a value, and at any point we pick a type 'a to pass to it just as we would any value-level argument.
EXISTENTIAL QUANTIFICATION
There exists a type x, such that…
An existential is a value whose type is unknown statically, either because we have intentionally hidden something that was known, or because the type really is chosen at runtime, e.g. due to reflection. At runtime we can, however, inspect the existential to find the type and value inside.
If we don’t know the concrete type inside an existentially quantified type, how can we safely perform operations on it? Well, we can apply any function which itself can handle a value of any type – i.e. we can apply a universally quantified function!
In other words, existentials can be described in terms of the universals which can be used to operate upon them.
This technique is so useful that it is used in datatype generic programming library TypeShape, which allows you to scrap your boilerplate .NET reflection code, as well as MBrace and FsPickler for "packing existential data types". See Erik Tsarpalis' slides on TypeShape for more on "encoding safe existential unpacking in .NET" and encoding rank-2 types in .NET.
A reflection helper library like TypeShape also intuitively should cover most if not all your use cases: dependency injection needs to implement service location under the hood, and so TypeShape can be thought of as the "primitive combinator library" for building dependencies to inject. See the slides starting with Arbitrary Type Shapes: In particular, note the Code Lens data type:
type Lens<'T,'F> =
{
Get : 'T -> 'F
Set : 'T -> 'F -> 'T
}
Finally, for more ideas, you may care to read Don Stewart's PhD dissertation, Dynamic Extension of Typed Functional Languages.
We present a solution to the problem of dynamic extension in statically
typed functional languages with type erasure. The presented solution retains
the benefits of static checking, including type safety, aggressive optimizations, and native code compilation of components, while allowing
extensibility of programs at runtime.
Our approach is based on a framework for dynamic extension in a statically
typed setting, combining dynamic linking, runtime type checking,
first class modules and code hot swapping. We show that this framework
is sufficient to allow a broad class of dynamic extension capabilities in any
statically typed functional language with type erasure semantics.
Uniquely, we employ the full compile-time type system to perform runtime
type checking of dynamic components, and emphasize the use of native
code extension to ensure that the performance benefits of static typing
are retained in a dynamic environment. We also develop the concept of
fully dynamic software architectures, where the static core is minimal and
all code is hot swappable. Benefits of the approach include hot swappable
code and sophisticated application extension via embedded domain specific
languages.
Here are some coarse-grained design patterns Don lays out for future engineers to follow:
Section 3.6.3: Specializing Simulators Approach.
Demonstrates how to apply program specialization techniques to Monte-Carlo simulation of polymer chemistry. This approach demonstrates how you can "inject" specialized code to address so-called "peephole optimizations".
and a general chart to help frame the "tower of extensibility":
You could do that with a full fledged type:
type Function() =
member x.DoF<'a> (v:'a) = v
let y (f: Function) =
let a = f.DoF 1
let b = f.DoF 2L
(a,b)
y (Function())
I don't know a way to make it work with first class functions in F#

Dynamic dispatch for third-party type

This is related to my previous question about extending third-party types in a type-safe way. There were some good answers but they rely on the concrete type being known at compile time. I can't depend on this. Sometimes the type is boxed. Is there a way to extend third-party types to simulate dynamic dispatch?
I would use an interface for my own library. For example:
type ICanSerialize =
abstract ToSerializable : unit -> IDictionary<string,obj>
type B(items: obj[]) =
interface ICanSerialize with
member __.ToSerializable() =
dict ["Items", items |> Array.map (fun x ->
(x :?> ICanSerialize).ToSerializable()) |> box]
As a side note, it would be nice if we could do:
let inline toSerializable x =
(^T : (member ToSerializable : unit -> IDictionary<string,obj>) x)
let x = obj()
let d = toSerializable (unbox x)
But obviously it's impossible to combine runtime casts and inlining.
If I understand your question correctly, you'd like to have some cast-like operation that takes a dynamically loaded object of unknown type (System.Object) and casts that to some structural type and, preferrably guarantees that the object supports all operations that are specified by this type.
I don't think there is a standard machinery for that, but it could be implemented using System.Reflection. Emit. I implemented something similar for interoperability between C# and PHP some time ago.
The idea is to write a function that dynamically generates a class implementing the interface and all members of the interface are simply delegated to members of the wrapped object. While wrapping the object, you can check that all members exist and have the right signatures (but the object does not actually have to implement the same interface).
This is a bit too much code for a code sample, but I hope the general idea will be useful too (search Phalanger source code for NewObject method if you want to see how it is done there).

F#: killing redundancy in Map/Reduce/Filter

Let's say I have a list and a set and I want to do some stuff with them:
let outA = inA |> List.map(fun x -> x + 1) |> List.filter(fun x -> x > 10)
let outB = inB |> Set.map(fun x -> x + 1) |> Set.filter(fun x -> x > 10)
Now, obviously A handles lists and B handles sets. However, I find it very annoying to have to write List. List. over and over again: not only is it verbose, repetitive boilerplate which conveys no information and gets in the way of reading the functionality of the code, it is also a de-facto type annotation which I have to keep track of and keep in sync with the rest of my code.
What I want to be able to do is something like the following:
let outA = inA |> map(fun x -> x + 1) |> filter(fun x -> x > 10)
let outB = inB |> map(fun x -> x + 1) |> filter(fun x -> x > 10)
With the compiler knowing that inA is a list and inB is a set, and thus all the operations are from the correct class, and therefore outA is a list and outB is a set. I can partially achieve this with Seq:
let map(x) =
Seq.map(x)
let filter(x) =
Seq.filter(x)
And I can write exactly that. The problem with this is that it casts everything into Sequences, and I can no longer perform list/set operations on them. Similarly,
let outA = inA.Select(fun x -> x + 1).Where(fun x -> x > 10)
let outB = inB.Select(fun x -> x + 1).Where(fun x -> x > 10)
Also removes all that, but then casts everything to IEnumerable. I managed to get it pretty nice by converting all the static methods into instance methods via extensions:
type Microsoft.FSharp.Collections.List<'a> with
member this.map(f) = this |> List.map(f)
member this.filter(f) = this |> List.filter(f)
let b = a.map(fun x -> x + 1).filter(fun x -> x > 10)
but I suspect that will run into the type-inference problems mentioned here: Method Chaining vs |> Pipe Operator? I'm don't really know; I'm not familiar with how the type inference algorithm works.
The bottom line is, I figure I'm going to be doing a hell lot of these list/set/array map/reduce/filter operations and I want to make them look as pretty and clean as possible. Right now, apart from distracting me from the important bits in the expression (i.e. the "map" and the lambda) they also provide de-facto type annotations in a place where the compiler should jolly-well-know what the collection i'm passing in is.
Furthermore, this is exactly the sort of thing that OO inheritance and polymorphism is meant to solve, so I was wondering if there was some equivalent functional pattern that I do not know that would solve it just as elegantly. Perhaps I could do a type check in my own static map and perform the relevant type's map function on the input?
Does anyone have any better solution than those I've already tried, or am I bumping my head into a fundamental limitation of the F# type inference engine, that I should just accept and move on?
This is not the thing OO/inheritance/polymorphism solves. Rather it is the thing 'type classes' (a la Haskell) solve. The .NET type system is not capable of doing type classes, and F# doesn't try to add that capability. (You can do some hairy tricks with inline, but it has various limitations.)
I recommend accepting it and moving on.
I agree with Brian - you'll simply get used to this. As I mentioned in the answer to your previous question, this is sometimes quite useful, because you'll see what your code does (which part evaluates lazily, which part uses arrays for efficiency etc.)
Also, some functions are only available for some types - for example there is List.tail or List.foldBack, but similar functions don't exist for IEnumerable (in the Seq module) - for good reasons as they would lead to bad code.
In Haskell, type classes can describe types that have some functions (like map and filter), but I don't think they scale very well - to specify type classes for the F# library, you would end up with a hierarchy of type classes that specify list-like data structures, list-like data structures with tail and foldBack-like functions and too many other constraints.
Aside, for many simple list processing jobs, you can also use comprehensions which give you a lot nicer syntax (but of course, it is only useful for basic things):
let outB = seq { for x in inA do
if x > 10 do yield x + 1 }

Resources