2014-09-29 20 views
6

Często mam funkcję z wieloma parametrami tego samego typu, a czasami używam ich w niewłaściwej kolejności. Jako prosty przykład:F # phantom types in practice

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

Wydaje mi się, że typy fantomowe byłyby dobrym sposobem na złapanie jakichkolwiek pomyłek. Ale nie rozumiem, jak zastosować przykład w jedynym F# phantom types question.

Jak zaimplementować typy fantomowe w tym przykładzie? Jak nazwać CombinePath? Czy może brakuje prostszego rozwiązania problemu?

Odpowiedz

12

Myślę, że najprostszym sposobem jest użycie dyskryminowanych związków:

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

Można nazwać ten sposób

combinePath (Path(@"C:\temp")) (Fname("temp.txt")) 
+5

ponieważ te są jedna sprawa dalsi, można również nie 'niech combinePath (Path (p)) (Fname (f)) = ...', koniec -result będzie taki sam :) –

+0

Tak. To będzie prostsze. Zaktualizowany post, dziękuję! – Petr

+0

Oznaczałoby to deklarowanie typu dla każdego typu parametru. Sądzę, że myślałem, że może to być trochę jak jednostka miary, string string . Chociaż nadal będzie potrzebował typów dla Path i FileName, więc na końcu jest tak samo ... Odpowiadam na mój własny punkt myślę. –

7

Zgadzam się ze startu Petr, ale pod względem kompletności, trzeba pamiętać, że tylko można używaj typów fantomowych, gdy masz typ ogólny, aby ich używać, abyś nie mógł nic zrobić ze zwykłymi wejściami string. Zamiast tego, można zrobić coś takiego:

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 
+0

Najwyraźniej najlepszym rozwiązaniem jest dyskryminacja związkowa. Typy Phantom wydają się zbędne dla F #. Wydaje mi się, że dlatego nie ma o tym zbyt wiele. –

+0

@FsharpPete - Nie sądzę, że to całkiem w porządku; w tym konkretnym scenariuszu DU mogą być lepsze, ale są na pewno scenariusze, w których typy fantomowe są przydatne (i nie sądzę, że F # różni się znacząco od większości innych języków pod względem tego, kiedy stosować jedną lub drugą technikę). – kvb

+0

Tak, widzę to teraz. Przy podejściu typu fantomowego można określić typ fantomowy spoza modułu/pakietu, a nie tak, jak w przypadku dyskryminowanej unii. –