Un string
è essenzialmente una sequenza di valori char
(in Haskell, BTW, String
è un tipo alias per [Char]
). Una domanda più generale, quindi, sarebbe se fosse possibile dichiarare staticamente un elenco con una determinata dimensione.
Tale lingua è nota come Dependent Types e F # non ce l'ha. La risposta breve, quindi, è che non è possibile farlo in modo dichiarativo.
Il metodo più semplice, e probabilmente anche più idiomatica, modo, allora, sarebbe definire Code
come un unico caso Discriminazione in Union:
type Code = Code of string
Nel modulo che definisce Code
, devi anche definire un funzione che i clienti possono utilizzare per creare Code
valori:
let tryCreateCode candidate =
if System.String.IsNullOrWhiteSpace candidate
then None
else Some (Code candidate)
Questa funzione contiene la logica runtime che impedisce ai client di creare vuoti Code
valori:
> tryCreateCode "foo";;
val it : Code option = Some (Code "foo")
> tryCreateCode "";;
val it : Code option = None
> tryCreateCode " ";;
val it : Code option = None
Cosa impedisce a un client di creare un valore Code
non valido, quindi? Ad esempio, un client non potrebbe aggirare la funzione tryCreateCode
e scrivere semplicemente Code ""
?
Questo è dove signature files entra.Si crea un file di firma (.fsi
), e in che dichiarano tipi e le funzioni in questo modo:
type Code
val tryCreateCode : string -> Code option
Qui, il tipo Code
è dichiarato, ma la sua 'costruttore' non lo è. Ciò significa che non puoi creare direttamente valori di questo tipo. Questo, ad esempio, non compila:
Code ""
L'errore dato è:
errore FS0039: Il valore, costruttore dello spazio dei nomi o il tipo di 'codice' non è definito
L'unico modo per creare un valore Code
è utilizzare la funzione tryCreateCode
.
Come dato qui, non è più possibile accedere al valore di stringa sottostante Code
, a meno che non si fornisce anche una funzione per questo:
let toString (Code x) = x
e dichiararla nello stesso file .fsi
come sopra:
val toString : Code -> string
Potrebbe sembrare molto lavoro, ma in realtà sono solo sei righe di codice e tre righe di tipo dichiarazione (nel file .fsi
).
Dai un'occhiata a questo post: http://fsharpforfunandprofit.com/posts/designing-with-types-more-semantic-types/ - la sezione "Modellazione di stringhe vincolate con tipi". Probabilmente avrai bisogno di fare qualcosa del genere – Petr
@Petr Ho visto questo post ma trovo questa soluzione un po 'complicata. Grazie per il collegamento comunque. – Mikhail
Sì, sono d'accordo che quel post è un po 'complicato. Ho alcuni esempi migliori qui: https://gist.github.com/swlaschin/54cfff886669ccab895a. Come altri hanno sottolineato, le soluzioni non sono particolarmente eleganti. OTOH, dovresti fare qualcosa di simile anche nel codice OO. – Grundoon