SML / NJ - Шаблон, сопоставляющий динамическую типизацию

StackOverflow https://stackoverflow.com/questions/1805547

Вопрос

Можно ли написать функции с динамически типизированными входными параметрами? Я пробовал сопоставление с образцом, но, видимо, он не работает так.

Я хочу сделать что-то вроде этого:

fun firstStr (0,n:string) = n
  | firstStr (b:string,n:string) = if b>n then n else b;

Спасибо.

Это было полезно?

Решение

StandardML - это строгий статически типизированный язык. Поэтому у вас не может быть функции, которая принимает int в первом случае и строку во втором. Вы получаете ошибку

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)

Если вы хотите, чтобы один случай был строковым, а другой - целым, вы можете создать новый тип " теговое объединение " (он же «дискриминационное объединение»), который разработан так, чтобы его было легко использовать при сопоставлении с образцом. Это будет выглядеть так:

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

Конечно, вы можете найти более подходящее имя для этого типа Wrapper, что имеет смысл в контексте вашей программы. Также обратите внимание, что аннотация типа в n на самом деле не нужна; было бы более идиоматично писать

fun firstStr(Int 0,    n) = n
  | firstStr(String b, n) = if b>n then n else b

Кроме того, компилятор скажет вам, что вы оставили случай раскрытым: что, если первый аргумент является целым числом, не равным нулю?

Наконец, не совсем понятно, что вы подразумеваете под сравнением b > n , какой аспект двух строк вы хотите сравнить? Я вижу, что когда я сравниваю две строки в SML, я вижу лексикографическое (или буквенное) сравнение. Это то, что вы хотели?

Другие советы

Чтобы уточнить немного, предположим, что у вас есть два аргумента, каждый из которых может быть строкой или целым числом, и если у вас есть две строки, вы хотите лексикографически меньшую строку, если у вас есть одна строка, вы хотите эту строку, и если у вас есть два целых числа, вы не можете вернуть строку. Чем ты занимаешься? Вернуть значение типа строковая опция (посмотрите option , НЕКОТОРЫЕ и NONE в 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

Функция firstStr имеет тип

string_or_int * string_or_int -> string option

Самый быстрый способ стать опытным программистом ML - это научиться думать о типах в первую очередь . Например, если вам действительно нужна функция типа string option * string - > строка , вам не нужно писать ее самостоятельно; встроенная функция getOpt делает это. С другой стороны, это звучит так, как будто вы хотите string option * string - > строка , так что вы можете написать

fun firstStr(SOME a, b) = if a < b then a else b
  | firstStr(NONE,   b) = b

и вам не нужен конструктор значений SOME или тип option для результата.

Полиморфные варианты в OCaml имеют больше динамическое свойство, которое вы ищете. Вы можете посмотреть, если хотите, OCaml и SML очень близкие языки.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top