7

Is it possible to partially apply a function such as bprintf and prevent it from being restricted based on its initial use?

I'd like to do the following:

let builder = new System.Text.StringBuilder()
let append = Printf.bprintf builder
append "%i" 10
append "%s" string_value
Brian
  • 117,631
  • 17
  • 236
  • 300
Daniel
  • 47,404
  • 11
  • 101
  • 179

3 Answers3

12

The aspect of F# that's causing this is called value restriction. You can see that if you enter just the two let declarations to F# Interactive (so that the compiler doesn't infer the type from the first use):

> let builder = new System.Text.StringBuilder() 
  let append = Printf.bprintf builder ;;

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

There is an excellent article by Dmitry Lomov from the F# team which explains it in detail. As the article suggests, one solution is to add explicit type parameter declaration:

let builder = new System.Text.StringBuilder() 
let append<'T> : Printf.BuilderFormat<'T> -> 'T = Printf.bprintf builder 
append "%i" 10 
append "%s" "Hello"

This will work just fine.

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
Tomas Petricek
  • 240,744
  • 19
  • 378
  • 553
9

you can add explicit format argument

let builder = new System.Text.StringBuilder()
let append format = Printf.bprintf builder format
append "%i" 10
append "%s" "1"
desco
  • 16,642
  • 1
  • 45
  • 56
  • Thanks. Can anyone explain why this works and partial application doesn't? – Daniel Oct 28 '10 at 21:31
  • 12
    Because in .NET, functions can be generic and variables can't. `let append format =` describes a function; `let append =` describes a variable. – Tim Robinson Oct 28 '10 at 21:34
6

You're encountering the F# value restriction.

Here's a good explanation of some workarounds: Understanding F# Value Restriction Errors

Here's a fairly in-depth article explaining the reasons behind it: Link

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
Tim Robinson
  • 53,480
  • 10
  • 121
  • 138