Понимать ядро ​​`Fn.const`

Core lib Джейн Стрит имеет такую ​​функцию: Fn.const,

https://github.com/janestreet/core_kernel/blob/master/lib/fn.ml

let const c = (); fun _ -> c

val const: 'a ->' b -> 'a
производит функцию, которая просто возвращает свой первый аргумент

Я действительно не понимаю этого.

  1. Какова цель этой функции? По какому сценарию мы должны это использовать?
  2. Зачем ставить (); первый?
  3. Почему бы не написать это как let const c = fun () -> c? это даст функцию принятия unit как параметр и всегда возвращает начальный c,
  4. Если я сделаю let f = const 5, f станет функцией, которая принимает '_a в качестве параметра. Какова цель возврата функции со слабым полиморфным параметром?

PS Я вижу, что несколько функций внутри Fn модуль у всех есть (); перед возвратом функции, что такое использование ();?

2 ответа

Решение

Какова цель этой функции? По какому сценарию мы должны это использовать?

Вы бы использовали его в контексте, где требуется функция, принимающая аргумент, но вы на самом деле не заботитесь об аргументе и просто хотите возвращать одно и то же значение каждый раз. Тривиальный пример будет List.map (const 42) xs, который превращает список из n элементов в список из n 42s.

Менее глупым (но более абстрактным) примером была бы функция, которая делает что-то для получения значения, но при определенных (скажем, в случае, если что-то не удалось) вместо этого вызывает пользовательскую функцию для получения значения, а не дает ее некоторая информация о ситуации в качестве аргумента. В некоторых ситуациях вы можете не использовать информацию и просто возвращать одно и то же значение по умолчанию каждый раз, поэтому const будет работать здесь.

Зачем ставить (); первый?

В своем внутреннем представлении, а также сгенерированном коде, компилятор OCaml фактически имеет функции с несколькими аргументами. Если вы определите функцию как let f x y = ... или же let f x = fun y -> ..., OCaml фактически превращает это в функцию с 2 аргументами (а не функцию с 1 аргументом, возвращающую другую функцию) внутри. Итак, когда вы тогда делаете f 1 2 чтобы вызвать его, это простой вызов функции с двумя аргументами, которая намного эффективнее, чем альтернатива. Однако если вы просто делаете f xбудет создан дополнительный код для создания замыкания. Это менее эффективно, чем возвращать закрытие напрямую.

Таким образом, эта оптимизация повышает производительность, когда вы вызываете функцию со всеми ее аргументами, но на самом деле неэффективна, если вы этого не делаете. Добавление () впереди отключает оптимизацию (потому что функция больше не имеет вид f x = fun y -> ...). поскольку const предназначен для вызова только с одним аргументом (прямой вызов const x y не имеет смысла, как вы могли бы так же хорошо написать x), это улучшает производительность.

Почему бы не написать это как let const c = fun () -> c? это даст функции, принимающей единицу в качестве параметра, и всегда возвращает начальный c.

Потому что тогда функция будет работать только в контексте, где функция принимает unit ожидается, что будет подавляющее меньшинство случаев. Например List.map (const 42) xs теперь будет работать только если xs это список единиц, которых почти нет.

1., 2. и 3.: см. Ответ Сеппка

4.: Система типов OCaml такова, что функции не могут возвращать полиморфные значения. Вы должны прочитать ответы Габриэля об этом: В чем разница между "а" и "_l"? сверхгенерализованный карри фнс

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