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

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

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

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

Спасибо.

Ответы [ 3 ]

10 голосов
/ 27 ноября 2009

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, я вижу лексикографическое (или буквенное) сравнение. Это то, что вы хотели?

7 голосов
/ 28 ноября 2009

Чтобы уточнить немного, предположим, что у вас есть два аргумента, каждый из которых может быть строкой или целым числом, и если у вас есть две строки, вы хотите лексикографически меньшую строку, если у вас есть одна строка, вы хотите эту строку, и если у вас есть два целых числа, вы не можете вернуть строку. Чем ты занимаешься? Вернуть значение типа string option (поиск option, SOME и 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 -> string, вам не нужно писать ее самостоятельно; встроенная функция getOpt делает это. С другой стороны, это звучит так, как вы хотите string option * string -> string, поэтому вы можете написать

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

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

1 голос
/ 28 ноября 2009

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

...