0

I want to define sumOfSquares without explicity using parameter, relying instead on functional composition

Here's my code below

let sumOfSquares = Seq.map (fun n -> n * n) >> Seq.sum

However, I got the following error

stdin(80,5): error FS0030: Value restriction. The value 'sumOfSquares' has been inferred to have generic type

val sumOfSquares : ('_a -> int) when '_a :> seq<int> 

Either make the arguments to 'sumOfSquares' explicit or, if you do not intend for it to be generic, add a type annotation.

One way to resolve it is by using parameters

let sumOfSquares nums = nums |> Seq.map (fun n -> n * n) |> Seq.sum

and this will work. However, I want to see if I can define sum of squares by using composition alone

Update

Here's a nice article describing the issue I've encountered: Value Restriction.

OnesimusUnbound
  • 2,886
  • 3
  • 30
  • 40

2 Answers2

1

Make a type annotation:

let sumOfSquares : seq<int> -> int = 
    Seq.map (fun n -> n * n) >> Seq.sum
Søren Debois
  • 5,598
  • 26
  • 48
  • Thanks. Correct me if I'm wrong, F# assumed I'm making a function that accepts generic typed parameter but upon type inference, it detected I wanted to define `seq -> int`, hence it got "confused". Is is the case? – OnesimusUnbound Mar 28 '14 at 06:26
  • @OnesimusUnbound As you can see from the message, F# inferred that you want a function accepting *any collection descending from `IEnumerable` in the type hierarchy* and returning `int`. If you want the argument to be strictly `seq`, you have to annotate it :) Unfortunately, subtyping (and also overloading) can be tricky for the type inference... – Patryk Ćwiek Mar 28 '14 at 09:27
0

So lets see what happens when the type inference tries to work here. First you have

Seq.map (fun n -> n * n) >> Seq.sum

Now as Seq allows for anything that implements Seq, we can input int list int[] or many others.

As a result, you get this as the type

val sumOfSquares : ('_a -> int) when '_a :> seq<int> 

Now the problem is that sumofSquares is a value (which is a function). Unfortunately, you can't have a generic value in a top level binding. You can though have a generic function, if you make the arguments explicit.

As a result, one alternative to a type annotation is to make the argument explicit like so

let sumOfSquares s= s |> Seq.map (fun n -> n * n) |> Seq.sum

And this works

Searching SO for "value restriction errors" should give some more examples of this problem.

John Palmer
  • 25,356
  • 3
  • 48
  • 67