title: Expert f# script compile oddity
body: <p>On page 209 - 210 there is an extended example (see below) (I'm using F# 4.5).</p>
  <p>In summary what I don't understand is: if I type each statement individually, there is a declaration that raises an error. If I submit the whole script at once, with the functions that come after the declaratation that raises the error, everything is OK. So what happens in interactive when I submit all the statements as a batch? Does the function that follows the error get used to create a specific version of the potential generic? The ionide hints do not show a generic for the whole script.</p>
  <p>In detail (sorry it's so long)
  If you execute each of the statements in order upto and including the declaration of <code>formatP </code>, (or paste all of them upto and including <code>formatP </code> at once - e.g. select and alt-enter with ionide in vs code) in interactive, it produces an error:</p>
  <pre><code>    binary.fsx(67,5): error FS0030: Value restriction. The value 'formatP' has been inferred to have generic type
          val formatP : ((int * bool) list -&gt; '_a -&gt; unit) when '_a :&gt; OutState
      Either make the arguments to 'formatP' explicit or, if you do not intend for it to be generic, add a type annotation.
  </code></pre>
  <ul>
  <li>if you paste all of the script including the functions which follow <code>formatP </code></li>
  </ul>
  <pre class="lang-ml prettyprint-override"><code>let writeData file data =
      use outStream = BinaryWriter(File.OpenWrite(file))
      formatP data outStream
  
  let readData file =
      use inStream = BinaryReader(File.OpenRead(file))
      formatU inStream
  </code></pre>
  <p>it works without error.</p>
  <p><strong>Given that compilation order is important - what is happening here?</strong></p>
  <p>i.e. why do the functions that are declared after <code>formatP </code> allow the function to compile.</p>
  <p>Whole script - which functions without error (It's a bit long - but because I really don't understand the issue, I'm not sure what I can remove to create an accurate example illustrating what is happening.
  I guess I could drop <code>formatU</code> and <code>readData</code>? (which have the same relationship) but they are needed to make the last 2 stamenets work which sahows that the code does complie and execute as expected):</p>
  <pre class="lang-ml prettyprint-override"><code>open System.IO
  
  type OutState = BinaryWriter
  type InState = BinaryReader
  type Pickler&lt;'T&gt; = 'T -&gt; OutState -&gt; unit
  type Unpickler&lt;'T&gt; = InState -&gt; 'T
  
  // P is the suffix for pickling and U is the suffix for unpickling
  let byteP (b : byte) (st : OutState) = st.Write(b)
  let byteU (st : InState) = st.ReadByte()
  
  let boolP b st = byteP (if b then 1uy else 0uy) st
  let boolU st = let b = byteU st in (b = 1uy)
  
  let int32P i st =
      byteP (byte (i &amp;&amp;&amp; 0xFF)) st
      byteP (byte ((i &gt;&gt;&gt; 8) &amp;&amp;&amp; 0xFF)) st
      byteP (byte ((i &gt;&gt;&gt; 16) &amp;&amp;&amp; 0xFF)) st
      byteP (byte ((i &gt;&gt;&gt; 24) &amp;&amp;&amp; 0xFF)) st
  
  let int32U st =
      let b0 = int (byteU st)
      let b1 = int (byteU st)
      let b2 = int (byteU st)
      let b3 = int (byteU st)
      b0 ||| (b1 &lt;&lt;&lt; 8) ||| (b2 &lt;&lt;&lt; 16) ||| (b3 &lt;&lt;&lt; 24)
  
  let tup2P p1 p2 (a, b) (st : OutState) =
      (p1 a st : unit)
      (p2 b st : unit)
  let tup3P p1 p2 p3 (a, b, c) (st : OutState) =
      (p1 a st : unit)
      (p2 b st : unit)
      (p3 c st : unit)
  let tup2U p1 p2 (st : InState) =
      let a = p1 st
      let b = p2 st
      (a, b)
  let tup3U p1 p2 p3 (st : InState) =
      let a = p1 st
      let b = p2 st
      let c = p3 st
      (a, b, c)
  
  /// Outputs a list into the given output stream by pickling each element via f.
  /// A zero indicates the end of a list, a 1 indicates another element of a list.
  let rec listP f lst st =
      match lst with
      | [] -&gt; byteP 0uy st
      | h :: t -&gt; byteP 1uy st; f h st; listP f t st
  
  // Reads a list from a given input stream by unpickling each element via f.
  let listU f st =
      let rec loop acc =
          let tag = byteU st
          match tag with
          | 0uy -&gt; List.rev acc
          | 1uy -&gt; let a = f st in loop (a :: acc)
          | n -&gt; failwithf &quot;listU: found number %d&quot; n
      loop []
  
  type format = list&lt;int32 * bool&gt;
  
  //the types in these two lines only get fully inferred if the lines after are part of the batch
  //eh?
  let formatP = listP (tup2P int32P boolP)
  let formatU = listU (tup2U int32U boolU)
  //IE if you only run to here it is an error
  
  let writeData file data =
      use outStream = BinaryWriter(File.OpenWrite(file))
      formatP data outStream
  
  let readData file =
      use inStream = BinaryReader(File.OpenRead(file))
      formatU inStream
  //If you run to here it does not error
  
  writeData &quot;out.bin&quot; [(102, true); (108, false)] ;;
  readData &quot;out.bin&quot;
  </code></pre>