Вопрос

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?

Это было полезно?

Решение 2

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)

Другие советы

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;
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top