Сохранение частично примененной функции родовым
Можно ли частично применить такую функцию, как 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