SML How to check variable type? - sml

Is there any way to check/test the type of a variable?
I want to use it like this:
if x = int then foo
else if x = real then bar
else if x = string then ...
else .....

ML languages are statically typed, so it's not possible for something to have different types at different times. x can't sometimes have type int and at other times have the type string. If you need behavior like this, the normal way to go about it is to wrap the value in a container that encodes type information, like:
datatype wrapper = Int of int | Real of real | String of string
Then you can pattern-match on the constructor:
case x of Int x -> foo
| Real x -> bar
| String x -> ...
In this case, x is clearly typed as a wrapper, so that will work.

It's not possible to do what you want in general, even if x is of polymorphic type (without doing the wrapping yourself as Chuck suggests).
This is a deliberate design decision; it makes it possible to make very strong conclusions about functions, just based on their types, that you couldn't make otherwise. For instance, it lets you say that a function with type 'a -> 'a must be the identity function (or a function that always throws an exception, or a function that never returns). If you could inspect what 'a was at runtime, you could write a sneaky program like
fun sneaky (x : 'a) : 'a = if x = int then infinite_loop() else x
that would violate the rule. (This is a pretty trivial example, but there are lots of less-trivial things you can do by knowing your type system has this property.)

Related

Why my cast on user def type doesnt work?

type card = int
type game = { dimension : int; p1 : card list; }
let fn (_dimension : int) (p1 : card list) : bool =
(int)p1 = (int)_dimension * 2
I want to check that p1 is exactly twice the size of dimension.
Your code doesn't look very much like OCaml code, so it's difficult to know how to help :-)
There is no operation in OCaml to change the type of a value. That wouldn't make sense in a strongly typed language. There are some things you can do with types, but "casting" isn't one of them.
So, there is no valid expression that looks like (int) expr. As #glennsl points out, there is a function that returns the length of a list. If that's what you're trying to calculate, you can use List.length _dimension. The other occurrences of (int) you can just remove. They aren't valid OCaml.
Your definition of fn doesn't use the type game anywhere, so the definition of game is unnecessary. However it makes me worry that you're expecting the definition to have an effect.
If you leave out all the type ascriptions in your definition of fn the compiler will deduce the most general type for your function. This means you can call it with any list to check its length. That would be more idiomatic in OCaml. I.e., you don't need to specify that p1 is a list of cards. The function makes sense for any list.

how do I assign an expression with free type variables, like I assign other functions f as val x = f :?

how do I assign an expression with free type variables, like I assign other functions f as val x = f : ??
I have
fun curry f x y = f (x,y);
val dummy = fn (x,y) => {a=x,b=y} (* or anything with free type *)
val dummCd = fn x=> fn y=> {a=x,b=y}
I thought that 'curry dummy' would work like 'dummCd', but,
dummCd
val it = fn: 'a -> 'b -> {a: 'a, b: 'b}
and
curry dummy:
stdIn:13.1-13.8 Warning: type vars not generalized because of
value restriction are instantiated to dummy types (X1,X2,...)
val it = fn : ?.X1 -> ?.X2 -> {a:?.X1, b:?.X2}
So this becomes useless when assigned.
I can do this:
fun x a b =curry dummy a b ;
but this is a bit clumsy. When I put what I do here, into a function
val a = fn tr => (fn a=> fn b=> tr a b)
val x = a (curry dummy)
val x = fn : ?.X1 -> ?.X2 -> {a:?.X1, b:?.X2}
I get the same problem back.
How can I assign 'curry dummy' without using the extra a and b ? I mean like
val x = a ( curry dummy )
where a might be a function, and x behaves like dummCd
Thanks for tips
Sadly, you cannot do what you want.
In Standard ML '97, a value declaration can only bind a type variable if the right-hand side of the binding is a "non-expansive" expression, meaning that it conforms to a very restrictive subset of the expression syntax that doesn't make it possible to generate any new ref cells or exception names. Since this is a syntactic check, it doesn't take into account the definition of curry at all; you know that curry doesn't create any ref cells or exception names (and that val dummCd = curry dummy would therefore be safe), but all the compiler sees at this point is that curry dummy calls a function that could do those things.
So if you want dummCd to be called with arbitrary types (meaning, you want it to have the non-trivial type scheme ∀αβ.α→β→{a:α,b:β} with bound type variables), then you'll need to declare it using e.g. val dummCd = fn ... or fun dummCd ...; you can't just write val dummCd = ... with whatever you want on the right-hand side.
Standard ML '90 was a bit more permissive in this respect — it encoded the relevant information about the behavior of curry into the type system (by marking a type variable as "imperative", e.g. '_a rather than 'a, if it was involved in the types of any ref cells or exception names), and used that type information to decide whether val dummCd = curry dummy should be allowed to bind its type variables — but that system was deemed too messy and complicated, especially since it forced implementation details into signatures, so it was scrapped in Standard ML '97 and replaced with the current syntax-only system where all type variables are presumed imperative.

SML constantly implementation

I read about function constantly:
fun constantly k a = k
But I don't understand how to work with it.
I tried that way:
val a = constantly 10;
stdIn:32.5-32.28 Warning: type vars not generalized because of
value restriction are instantiated to dummy types (X1,X2,...)
val a = fn : ?.X1 -> int * int -> int
It works that way:
val a = constantly 10 ();
val a : int = 10
But not that way:
val a = constantly 10;
a ();
stdIn:36.1-36.5 Error: operator and operand don't agree [tycon mismatch]
operator domain: ?.X1
operand: unit
in expression:
a ()
Can anybody help me with understanding in that function?
This is the value restriction. Understanding it is important to understand partial application in ML. It is necessary due to mutability in the presence of polymorphism.
http://mlton.org/ValueRestriction
http://users.cis.fiu.edu/~smithg/cop4555/valrestr.html
Any time you see such a warning, you can fix it by eta-expanding the expression.
fun a x = constantly 10 x;
The thing is that fun constantly k a = k has type 'a -> 'b -> 'a
A partial function invocation like constantly 10 would be considered an expanding expression, and SML would be expecting to be capable to infer the actual types of the type variables for constantly at this point. That is, SML would be expecting that it could replace the type variables 'a and 'b with some concrete type T at this point.
Since your parameter a is not used in the body of your constantly function, SML cannot infer anything about it.
You would expect an expression like val a = constantly 10 to produce a type like 'b -> int, but instead, since SML finds that it cannot determine the type of 'b then it changes it for a dummy (concrete) type ?.X1, and that's why you end up with a function type ?.X1 -> int.
This is just SML telling you that it could not properly infer 'b because you did not provide enough type information for it in your expanding expression and so it has assigned a dummy concrete type to it, which basically renders your function impossible to use.
So, an alternative solution to the one already mentioned in another post would be to qualify your resulting function with a concrete type.
For instance, this should work:
val a = constantly 10: (int -> int)
With the obvious disadvantage of having qualified your type variable 'b as int, therefore, the curried function a is no longer a polymorphic function, but it is indeed a curried function. For this to work we would need to know the concrete type of 'b at the point where we are creating the curried function.
But if you still need the curried function to be polymorphic, because you cannot assume a specific/concrete type for 'b at that point then, as the other answer mentions, you will need to provide yet another argument that carries your polymorphic type:
val a = fn x => constantly 10 x
Which is basically the same thing in seanmcl's answer.
This would work because now x would carry the concrete type for 'b in your invocation to constantly 10 x within the wrapper function. Such concrete type will be defined when you invoke the curried function a (i.e. val _ = a(15) in this case 'b is int)

use non-default overloaded operator in smlnj

smlnj will make overloaded operator, like op + to use int by default, now I want to it returns a function in real * real -> real, how can I do in inline way?
"inline way" means not something like binding a new val:
fun add(x:real,y:real) = x + y;
If my memory is correct there is some grammar allows sml it to just do something like "cast" op + to real, but I can't really find it anywhere..
There are various ways that you can get SML to type op+ as the real counterpart.
Depending on what ever code you have,
You can as suggested, type annotate the surrounding function, thus enforcing the parameters to op+ to be of type real.
Since you are nonfixing the addition function (presumably for use as a higher order function?), you could just as well pass along the addition function from the real module Real.+
Or you could annotate it like this: op+ : real * real -> real, which is really ugly and stupid, considering you can use Real.+ instead. But it is an option.
If the default instance of the operator is not the one you need for your value's type, you can use type annotation on the operands to enforce the desired typing.
For example, while
val f = fn a => a + a
will be typed int -> int, this value
val g = fn a:real => a + a
will be typed real -> real.
You could declare
open Real
in the scope where you define the function, but I strongly advise against that. Type-annotating the function is the best way. You don't have to annotate every parameter, btw, it's enough to do one, or in this case, even the return type:
fun add(x : real, y) = x + y
fun add(x, y) : real = x + y

Polymorphic function as return value and value restriction in SML

Basically, I want to have a function to return a polymorphic function, some thing like this:
fun foo () = fn x => x
So the foo function takes in a value of type unit and returns a polymorphic identity function
and the compiler is happy with that, it gives me:
val foo = fn : unit -> 'a -> 'a
but once I actually call the foo function, the return value is not what I expected
val it = fn : ?.X1 -> ?.X2
Can't generalize because of value restriction it says, any help? thanks in advance
For technical reasons, you are not allowed to generalize (i.e., make polymorphic) the results of a function call. The result of a call must have a monomorphic type. If this weren't the case, you could subvert the type system by the following dirty trick:
Call ref [] and get back a list of type forall 'a . 'a list ref
Insert a string.
Remove a function
and there you are: you are now executing the contents of an arbitrary string as code. Not Good.
By insisting that the value returned by ref [] be monomorphic, you ensure that it can be used as a list of strings or a list of functions but not both. So this is part of the price we pay for type safety.