数据类型 Nt = int | ML 中的字符串
datatype Nt = int | string in ML
当我只有 datatype Nt = int | string
时,sml 不会抱怨。但是当我也有 val n = 6 : Nt
时,ml 不接受 6 作为 Nt
。为什么是这样?我确实知道,通常在 int
和 string
之前应该有数据构造函数,但在这里我用它来定义可以采用 int
或 string
的函数。
您误解了代码。需要明确的是,您不能在没有构造函数的情况下定义数据类型。但是 ML 对于类型和值有不同的名称空间。在您的示例中出现的 int
和 string
是值标识符。因此,它们只是定义了新的 nullary 构造函数,并且与同名类型的关系绝对为零。您现在可以定义 val n = int : Nt
。就好像你写了 datatype Nt = foo | bar
.
拥有一个可以接受 int 或 string 的函数可以用两种方式解释。你可能意味着你想要一个可以接受任何东西并用它做一些通用的函数——这将是一个多态函数。例如
fun id x = x
可以接受整数和字符串,return 它们,但对它们的具体内容没有太多作用。如果你想要一个可以接受 int 或 string 的函数,并根据你的输入对它们做不同的事情,你可以使用 union type,例如
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 类型的值,作为参数和 return 联合类型 Nt 的值。我将它们命名为 int
和 string
以外的名称,以表示值构造函数不同于 int 和 string 类型。如果他们不进行争论,他们唯一的用途就是区分彼此(在这种情况下,他们将同构于 true
/false
)。
采用这样的值作为输入的函数必须与同名的模式构造函数匹配。以下是一些将此联合类型作为参数的函数:
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"
当我只有 datatype Nt = int | string
时,sml 不会抱怨。但是当我也有 val n = 6 : Nt
时,ml 不接受 6 作为 Nt
。为什么是这样?我确实知道,通常在 int
和 string
之前应该有数据构造函数,但在这里我用它来定义可以采用 int
或 string
的函数。
您误解了代码。需要明确的是,您不能在没有构造函数的情况下定义数据类型。但是 ML 对于类型和值有不同的名称空间。在您的示例中出现的 int
和 string
是值标识符。因此,它们只是定义了新的 nullary 构造函数,并且与同名类型的关系绝对为零。您现在可以定义 val n = int : Nt
。就好像你写了 datatype Nt = foo | bar
.
拥有一个可以接受 int 或 string 的函数可以用两种方式解释。你可能意味着你想要一个可以接受任何东西并用它做一些通用的函数——这将是一个多态函数。例如
fun id x = x
可以接受整数和字符串,return 它们,但对它们的具体内容没有太多作用。如果你想要一个可以接受 int 或 string 的函数,并根据你的输入对它们做不同的事情,你可以使用 union type,例如
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 类型的值,作为参数和 return 联合类型 Nt 的值。我将它们命名为 int
和 string
以外的名称,以表示值构造函数不同于 int 和 string 类型。如果他们不进行争论,他们唯一的用途就是区分彼此(在这种情况下,他们将同构于 true
/false
)。
采用这样的值作为输入的函数必须与同名的模式构造函数匹配。以下是一些将此联合类型作为参数的函数:
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"