When I only have datatype Nt = int | string
, sml doesn't complain. But when I also have val n = 6 : Nt
, ml doesn't accept 6 as an Nt
. Why is this? I do know that, normally there should be data constructers before int
and string
, but here I'm having that to define functions that can take either int
or string
.
You are misinterpreting the code. To be clear, you cannot define datatypes without constructors. But ML has different name spaces for types and values. The occurrences of int
and string
in your example are value identifiers. As such, they just define new nullary constructors, and have absolutely zero to do with the types of the same name. You can now define val n = int : Nt
. It is as if you had written datatype Nt = foo | bar
.
Having a function that can either take an int or a string can be interpreted in two ways. You could mean that you want a function that could take anything and do something general with it – that would be a polymorphic function. E.g.
fun id x = x
can take both ints and strings and return them, but not do much with their content in specific. If you want a function that can take either an int or a string and do something different with them, depending on which input you have, you could use a union type, e.g.
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"
Here, Int
and Str
are value constructors that work like functions in that they take a value of type int/string, respectively, as argument and return a value of the union type Nt. I've named them something other than int
and string
to signify that the value constructors are different from the types int and string. If they did not take an argument, their only use would be to distinguish one from the other (in which case they would be isomorphic to true
/false
).
A function that takes such a value as input would have to match against the pattern constructors of the same names. Here are some functions that would take this union type as argument:
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
And here these functions are being tested:
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"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With