Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

F# phantom types in practice

Tags:

types

f#

I often have a function with multiple parameters of the same type, and sometimes use them in the wrong order. As a simple example

let combinePath (path : string) (fileName : string) = ...

It seems to me that phantom types would be a good way to catch any mix ups. But I don't understand how to apply the example in the only F# phantom types question.

How would I implement phantom types in this example? How would I call combinePath? Or am I missing a simpler solution to the problem?

like image 565
Fsharp Pete Avatar asked Sep 29 '14 13:09

Fsharp Pete


2 Answers

I think the easiest way is to use discriminated unions:

type Path = Path of string
type Fname = Fname of string
let combinePath (Path(p)) (Fname(file)) = System.IO.Path.Combine(p, file)

You could call it this way

combinePath (Path(@"C:\temp")) (Fname("temp.txt"))
like image 61
Petr Avatar answered Oct 04 '22 21:10

Petr


I agree with Petr's take, but for completeness, note that you can only use phantom types when you've got a generic type to use them with so you can't do anything with plain string inputs. Instead, you could do something like this:

type safeString<'a> = { value : string }

type Path = class end
type FileName = class end

let combinePath (path:safeString<Path>) (filename:safeString<FileName>) = ...

let myPath : safeString<Path> = { value = "C:\\SomeDir\\" }
let myFile : safeString<FileName> = { value = "MyDocument.txt" }

// works
let combined = combinePath myPath myFile

// compile-time failure
let combined' = combinePath myFile myPath
like image 42
kvb Avatar answered Oct 04 '22 21:10

kvb