SML / NJ - Pattern corrispondente a una digitazione dinamica
-
05-07-2019 - |
Domanda
È possibile scrivere funzioni con parametri di input tipizzati dinamicamente? Ho provato la corrispondenza dei modelli, ma a quanto pare non funziona in questo modo.
Vorrei fare qualcosa del genere:
fun firstStr (0,n:string) = n
| firstStr (b:string,n:string) = if b>n then n else b;
Grazie.
Soluzione
StandardML è un linguaggio rigorosamente tipizzato staticamente. Pertanto, non è possibile avere una funzione che accetta un int nel primo caso e una stringa nel secondo. L'errore che ricevi è
this clause: string * string -> 'Z
previous clauses: int * string -> 'Z
in declaration:
firstStr =
(fn (0,<pat> : string) => n
| (<pat> : string,<pat> : string) => if <exp> > <exp> then n else b)
Se vuoi avere un caso che è una stringa e un caso che è un int, puoi creare un nuovo tipo, un " taggato unione " (aka "unione discriminata"), progettata per essere facile da usare con la corrispondenza dei motivi. Sembrerebbe così:
datatype Wrapper = Int of int
| String of string
fun firstStr(Int 0, n:string) = n
| firstStr(String b, n:string) = if b>n then n else b
Naturalmente, potresti voler trovare un nome più appropriato per questo tipo di wrapper, qualcosa che ha senso nel contesto del tuo programma. Si noti inoltre che l'annotazione del tipo su n
non è realmente necessaria; sarebbe più idiomatico scrivere
fun firstStr(Int 0, n) = n
| firstStr(String b, n) = if b>n then n else b
Inoltre, il compilatore ti dirà che hai lasciato un caso scoperto: cosa succede se il primo argomento è un numero intero non uguale a zero?
Infine, non è davvero chiaro cosa intendi con il confronto b > n
, quale aspetto delle due stringhe vuoi confrontare? Vedo che quando confronto due stringhe in SML, vedo un confronto lessicografico (aka alfabetico). È quello che volevi?
Altri suggerimenti
Per elaborare un po ', supponi di avere due argomenti, ognuno dei quali potrebbe essere una stringa o un numero intero, e se hai due stringhe vuoi la stringa lessicograficamente più piccola, se hai una stringa vuoi quella stringa, e se hai due numeri interi non puoi restituire una stringa. cosa fai? Restituisce un valore di tipo opzione stringa
(cerca opzione
, SOME
e NONE
in http://www.standardml.org/Basis/option.html ):
datatype string_or_int = String of string
| Int of int
fun firstStr(String a, String b) = SOME (if a < b then a else b)
| firstStr(String a, Int _ ) = SOME a
| firstStr(Int _, String b) = SOME b
| firstStr(Int _, Int _ ) = NONE
La funzione firstStr
ha il tipo
string_or_int * string_or_int -> string option
Il modo più veloce per diventare un abile programmatore ML è imparare a pensare prima ai tipi . Se per esempio, quello che volevi veramente era una funzione di tipo stringa opzione * stringa - > stringa
, non dovresti scriverlo tu stesso; la funzione integrata getOpt
lo fa. D'altra parte, sembra che tu voglia l'opzione string * string - > stringa
, così puoi scrivere
fun firstStr(SOME a, b) = if a < b then a else b
| firstStr(NONE, b) = b
e non è necessario un SOME
costruttore di valori o un'opzione
sul risultato.
Varianti polimorfiche in OCaml hanno più di la proprietà dinamica che stai cercando. Puoi dare un'occhiata se vuoi, OCaml e SML sono lingue molto vicine.