Skip to content

Instantly share code, notes, and snippets.

@Savelenko
Created November 25, 2020 14:42
Show Gist options
  • Save Savelenko/dd50e27688672371d1f8eaf35c4adc54 to your computer and use it in GitHub Desktop.
Save Savelenko/dd50e27688672371d1f8eaf35c4adc54 to your computer and use it in GitHub Desktop.
What if F# had type families
(* What if F# had type families? *)
// We are a message processing system. There are regular and confidential messages to be delivered. Several delivery
// methods are supported. The main "business rule" is that regular messages must be sent by e-mail and confidential
// messages by post.
// Delivery methods.
type EMail = DeliveryMethodEmail of string
type Post = DeliveryMethodPost of {| RecipientName : string; Address : string |}
// Regular and confidential messages.
type Message = Message of string
type ConfidentialMessage = {
Contents : string
Signature : int
}
// A type family is like a function, only not accepting and returning values, but types.
type family DeliveryMethod<'m> where
DeliveryMethod<Message> = Email
DeliveryMethod<ConfidentialMessage> = Post
// Remember we are a message processing system, so there is a message queue somewhere. Now we can statically ("in the
// type system") enforce that messages are sent only using the required delivery method. It is not possible to add a
// message to the send queue with a wrong delivery method.
type DeliveryQueueItem<'m> = {
Message : 'm
Method : DeliveryMethod<'m>
}
// The following is OK.
let regularQueue = [
{ Message = Message "You sleepy?"; Method = EMail "totoro@bigtree.net"}
// Other regular messages here...
]
// This would not compile because (EMail ...) is not a value of type DeliveryMethod<ConfidentialMessage>.
let confidentialQueue = [
{ Message = ConfidentialMessage { Contents = "A secret"; Signature = 666 }; Method = EMail "me@home.com" }
]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment