开发者

SML/NJ - Pattern Matching an Dynamic Typing

Is it possible to write functions with dynamically typed input parameters? I tried pattern matching, but apparently it does not work like this.

I wish to do something like this:

fun firstStr (0,n:string) = n
  | firstStr (b:string,n:stri开发者_C百科ng) = if b>n then n else b;

Thank you.


StandardML is a strict, statically typed language. Therefore, you can't have a function which accepts an int in the first case and a string in the second. The error you get is

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)

If you want to have one case which is a string and one case which is an int, you can make a new type, a "tagged union" (aka "discriminated union"), which is designed to be easy to use with pattern matching. It would look like this:

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

Of course, you might want to find some more appropriate name for this Wrapper type, something that makes sense in the context of your programme. Also please note that the type annotation on n is not really necessary; it would be more idiomatic to write

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

Additionally, the compiler will tell you you have left a case uncovered: What if the first argument is an integer not equal to zero?

Finally, it's not really clear what you mean by the comparison b>n, what aspect of the two strings did you want to compare? I see that when I compare two strings in SML, I see a lexicographic (aka alphabetic) comparison. Is that what you wanted?


To elaborate a little bit, suppose you have two arguments, each of which could be a string or an integer, and if you have two strings you want the lexicographically smaller string, if you have one string you want that string, and if you have two integers you can't return a string. What do you do? Return a value of type string option (look up option, SOME, and NONE at 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

Function firstStr has type

string_or_int * string_or_int -> string option

The fastest way to becoming a proficient ML programmer is to learn to think about types first. If for example, what you really wanted was a function of type string option * string -> string, you wouldn't need to write it yourself; the builtin function getOpt does that. On the other hand, it sounds like you want string option * string -> string, so you can write

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

and you dont' need a SOME value constructor or an option type on the result.


Polymorphic variants in OCaml have more of the dynamic property you are looking for. You can take a look if you want, OCaml and SML are very close languages.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜