Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

F# - string | int inference on union

Tags:

f#

I'm pretty sure this isn't possible but thought I'd double check. I guess I'm trying to mimic typescript's union types.

I have a type

type StringOrInt = 
 | String of string
 | Int of int

And then a function

let returnSelf (x: StringOrInt) = x

At the moment the function has to be called like

returnSelf (String "hello")

Is it possible to do

returnSelf "hello"

and infer that it is a valid StringOrInt?

like image 314
Josh Avatar asked Mar 10 '26 18:03

Josh


1 Answers

At the moment it's not supported out of the box, but fairly simple generic casting method can be implemented.

Given an example function:

let call v = (* v has inferred type StringOrInt *)
    match v with
    | String s -> printfn "called a string %s" s
    | Int i -> printfn "called an int %i" i

We could eventually call it like so:

(* % is a unary prefix operator *)
call %"abc" 
call %1

We need to provide some way to tell how to convert ordinary string/int into StringOrInt type. This can be used by exemplar convention call:

type StringOrInt =
    | String of string
    | Int of int
    static member inline From(i: int) = Int i
    static member inline From(s: string) = String s

Here our discriminated union provides two static methods which are responsible for casting. Since they correspond to the same naming convention, we can use them together with F# statically resolved generic type parameters - these are generics that are resolved at compile time unlike the .NET generics which exists also at runtime - to create a casting function (or operator):

(* casting operator *)
let inline (~%) (x: ^A) : ^B =
    (^B : (static member From: ^A -> ^B) x)

This way you can use % prefix operator over any type that implements a casting mechanism in form of static From method.

like image 171
Bartosz Sypytkowski Avatar answered Mar 12 '26 09:03

Bartosz Sypytkowski