当我只有datatype Nt = int | string
时,sml并没有抱怨。但是当我也有val n = 6 : Nt
时,ml并不接受6作为Nt
。为什么是这样?我知道,通常在int
和string
之前应该有数据构造函数,但是我在这里定义了可以采用int
或{{1}的函数}。
答案 0 :(得分:9)
您误解了代码。需要说明的是,如果没有构造函数,则无法定义数据类型。但是ML对于类型和值有不同的名称空间。您的示例中出现的int
和string
是值标识符。因此,它们只是定义了新的nullary构造函数,并且与同名的类型完全无关。您现在可以定义val n = int : Nt
。就好像你写了datatype Nt = foo | bar
。
答案 1 :(得分:5)
具有可以采用int或字符串的函数可以用两种方式解释。你可能意味着你想要一个可以接受任何东西并且做一些通用的函数 - 这将是一个多态函数。 E.g。
fun id x = x
可以同时使用整数和字符串并返回它们,但不会对其内容进行特定的处理。如果你想要一个可以接受int或字符串并且做一些与它们不同的函数,根据你拥有的输入,可以使用 union类型,例如
datatype Nt = Int of int (* constructor has the type int -> Nt *)
| Str of string (* constructor has the type string -> Nt *)
val sample_1 = Int 42
val sample_2 = Str "Hello"
这里,Int
和Str
是值构造函数,它们的功能与函数类似,它们分别将int / string类型的值作为参数并返回一个值联合类型Nt。我将它们命名为int
和string
之外的其他内容,以表示值构造函数与int和string类型不同。如果他们没有参与辩论,他们唯一的用途是区分彼此(在这种情况下,他们将与true
/ false
同构。)
将输入值作为输入的函数必须与相同名称的模式构造函数匹配。以下是一些将此union类型作为参数的函数:
fun isAnInt (Int i) = true
| isAnInt (Str s) = false
fun intVal (Int i) = i
| intVal (Str i) = 0
fun strVal (Int i) = Int.toString i
| strVal (Str s) = s
fun sumNt [] = 0
| sumNt (x::xs) = intVal x + sumNt xs
fun concatNt [] = ""
| concatNt (x::xs) = strVal x ^ concatNt xs
这里正在测试这些功能:
val test_isAnInt_1 = isAnInt sample_1 = true
val test_isAnInt_2 = isAnInt sample_2 = false
val test_intVal_1 = intVal sample_1 = 42
val test_intVal_2 = intVal sample_2 = 0
val test_strVal_1 = strVal sample_1 = "42"
val test_strVal_2 = strVal sample_2 = "Hello"
val test_sumNt_1 = sumNt [] = 0
val test_sumNt_2 = sumNt [sample_1, sample_1, sample_2, sample_1] = 126
val test_sumNt_3 = sumNt [sample_2, sample_2, sample_2] = 0
val test_concatNt_1 = concatNt [] = ""
val test_concatNt_2 = concatNt [sample_1, sample_1, sample_1] = "424242"
val test_concatNt_3 = concatNt [sample_1, sample_2, sample_1] = "42Hello42"