SML / NJ - Pattern Matching uma tipagem dinâmica
-
05-07-2019 - |
Pergunta
É possível escrever funções com parâmetros de entrada digitadas dinamicamente? Tentei correspondência de padrão, mas aparentemente ele não funciona assim.
Eu gostaria de fazer algo parecido com isto:
fun firstStr (0,n:string) = n
| firstStr (b:string,n:string) = if b>n then n else b;
Obrigado.
Solução
StandardML é uma estrita, a linguagem de tipagem estática. Portanto, você não pode ter uma função que aceita um int no primeiro caso e uma corda no segundo. O erro que você recebe é
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 você quer ter um caso que é uma cadeia e um caso que é um int, você pode fazer um novo tipo, um " marcado união "(aka 'união discriminada'), que é projetado para ser fácil de usar com correspondência de padrão. Ele ficaria assim:
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
Claro, você pode querer encontrar algum nome mais apropriado para este tipo Wrapper, algo que faz sentido no contexto do seu programa. Também vale lembrar que o tipo de anotação em n
não é realmente necessário; seria mais idiomática para escrever
fun firstStr(Int 0, n) = n
| firstStr(String b, n) = if b>n then n else b
Além disso, o compilador irá dizer-lhe que você deixou um caso ar-livre:? Que se o primeiro argumento é um inteiro não igual a zero
Finalmente, ele não está realmente claro o que você quer dizer com o b>n
comparação, o aspecto das duas cordas que você quer comparar? Eu vejo que quando eu comparar duas cordas no SML, vejo uma comparação lexicográfica (aka alfabética). É isso que você queria?
Outras dicas
Para elaborar um pouco, suponha que tem dois argumentos, cada um dos quais poderia ser uma string ou um inteiro, e se você tem duas cordas que você quer a corda lexicographically menor, se você tem uma corda que você quer que corda, e se você tiver dois inteiros você não pode retornar uma string. O que você faz? Retornar um valor do tipo string option
(olhar para cima option
, SOME
e NONE
em http: //www.standardml .org / Base / 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
firstStr
função tem tipo
string_or_int * string_or_int -> string option
A maneira mais rápida de se tornar um programador ML proficiente é aprender a pensar sobre os tipos de início . Se, por exemplo, o que você realmente queria era uma função do tipo string option * string -> string
, você não precisa escrevê-lo sozinho; a função interna getOpt
faz isso. Por outro lado, parece que você quer string option * string -> string
, assim você pode escrever
fun firstStr(SOME a, b) = if a < b then a else b
| firstStr(NONE, b) = b
e você não' precisa de um construtor de valor SOME
ou um tipo de option
no resultado.
polimórfica variantes em OCaml ter mais de a propriedade dinâmica que você está procurando. Você pode dar uma olhada, se quiser, OCaml e SML são línguas muito próximas.