0
votes
let pair a b = fun select -> select a b;
let isPair(x) = x.GetType().BaseType.Name = "FSharpFunc`2"
exception OuterError of string
let first(p) = 
    if isPair(p) then p(fun a b -> a)
    else raise (OuterError("Not a pair"))
let second(p) = 
    if isPair(p) then p(fun a b -> b)
    else raise (OuterError("Not a pair"))
let p1 = fun f -> pair 2 (pair 4 5) f
second(p1);

I want get the "(pair 4 5)", but it has someting wrong:

error FS0030: Value restriction. The value 'it' has been inferred to have generic type val it: ((int -> int -> '_a) -> '_a)
Either make the arguments to 'it' explicit or, if you do not intend for it to be generic, add a type annotation.

let pair a b = fun select -> select a b;
let first(p) = p(fun a b -> a)
let second(p) = p(fun a b -> b)
let p1 = fun f -> pair 2 (pair 4 5) f
second(p1);

I have deleted the isPair function, but it's not getting any better.

I can write pair in javascript like this:

var pair = (a, b) => select => select(a, b)
var first = p => p((a, b) => a)
var second = p => p((a, b) => b)
var p1 = pair(2, pair(4, 5))
second(p1)

And I can use second(p1)'s value pair(4, 5).

var p2 = second(p1)
first(p2)
second(p2)

But it's not work in F#, because of F# is statically typed, I guess.

1
F# is statically typed. Your isPair function is nonsensical.Fyodor Soikin

1 Answers

1
votes

The reason this doesn't work is that the final expression second(p1) has a generic type.

More specifically, its type is this:

second(p1) : (int -> int -> 'a) -> 'a

It's a function that takes another function as parameter and returns that function's result. And this result can be of any type. The function pair does not specify what that result should be, so it's assumed to be generic, as denoted by 'a in the signature above.

Now, the problem is that values of generic types cannot exist. Functions of generic types can exist, but values cannot. And here I'm talking about syntactic values - i.e. let (or similar) declarations without parameters.

This is called "value restriction", and the reasons for this are a bit subtle and have to do with uncontrolled effects and mutation. See this article for an in-depth discussion.

And when you execute second(p1) in FSI, you're trying to create just such a value. A value (not a function) with a generic type. FSI calls this value it, which is what you see in the error message.


You can work around this by using the resulting value later, similar to your JavaScript example:

let p2 = second(p1)
second p2

This ☝️ will compile and run, as long as you execute both these lines together, so FSI can see them both at once.

Here, the compiler can use the expression second p2 to infer the type of p2 to be non-generic (int -> int -> int) -> int, and the value restriction does not come into play.

Another way to work around the restriction is to explicitly declare that your value should have a generic type:

let p2<'a> : (int -> int -> 'a) -> 'a = second(p1)

This will compile on its own, even in the absence of a subsequent usage like second p2.


In practice, in real-world programs, this problem never comes up. This is because in a real program all values are ultimately used for some sort of input/output or other effects, and at that point their types become known. So values are never left "hanging" like this.

The only context in which this problem comes up is exploration and experimentation, like what you're doing, where intermediate values may be explored on their own.