Сохранение частично примененной функции родовым

Можно ли частично применить такую ​​функцию, как bprintf и предотвратить его ограничение на основе первоначального использования?

Я хотел бы сделать следующее:

let builder = new System.Text.StringBuilder()
let append = Printf.bprintf builder
append "%i" 10
append "%s" string_value

3 ответа

Решение

Вы можете добавить явный аргумент формата

let builder = new System.Text.StringBuilder()
let append format = Printf.bprintf builder format
append "%i" 10
append "%s" "1"

Аспект F#, который вызывает это, называется ограничением значения. Вы можете увидеть, что если вы введете только два let объявления в F# Interactive (чтобы компилятор не определял тип с первого использования):

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

Ошибка FS0030: ограничение значения. Значение 'append' было выведено, чтобы иметь универсальный тип val append: ('_a -> '_b), когда '_a:> Printf.BuilderFormat<' _ b> Либо сделать аргументы для 'append' явными, либо, если вы не указали намеревайтесь сделать его универсальным, добавьте аннотацию типа.

Есть отличная статья Дмитрия Ломова из команды F#, которая подробно объясняет это. Как показано в статье, одним из решений является добавление явного объявления параметра типа:

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

Это будет работать просто отлично.

Вы столкнулись с ограничением значения F#.

Вот хорошее объяснение некоторых обходных путей: Понимание ошибок ограничения значения F#

Вот довольно глубокая статья, объясняющая причины этого: http://blogs.msdn.com/b/mulambda/archive/2010/05/01/value-restriction-in-f.aspx

Другие вопросы по тегам