Сверхгенерализованный карри фнс

module MapHelpers (Ord : Map.OrderedType) = struct
  include Map.Make (Ord)
  let add_all a b = fold add a b
end

работает, но, казалось бы, эквивалентно

module MapHelpers (Ord : Map.OrderedType) = struct
  include Map.Make (Ord)
  let add_all = fold add
end

не компилируется с

File "Foo.ml", line 2, characters 18-104:
Error: The type of this module,
       functor (Ord : Map.OrderedType) ->
         sig
           ...
           val add_all : '_a t -> '_a t -> '_a t
         end,
       contains type variables that cannot be generalized
Command exited with code 2.

и добавление явной аннотации типа

: 'a . 'a t -> 'a t -> 'a t

приводит к сбою компиляции ранее с

Error: This definition has type 'a t -> 'a t -> 'a t
       which is less general than 'a0. 'a0 t -> 'a0 t -> 'a0 t

Почему добавление явных формалей a b изменить способ ввода этих двух модулей?

1 ответ

Решение

Это является следствием ограничения значения, как описано в следующем разделе часто задаваемых вопросов:

Функция, полученная в результате частичного применения, недостаточно полиморфна

Более распространенным случаем получения "недостаточно полиморфного" определения является определение функции посредством частичного применения общей полиморфной функции. В Caml полиморфизм вводится только через конструкцию "let", а результаты от применения являются слабо полиморфными; следовательно, функция, полученная в результате применения, не является полиморфной. В этом случае вы восстанавливаете полностью полиморфное определение, четко демонстрируя функциональность для средства проверки типов: определите функцию с явной функциональной абстракцией, то есть добавьте функциональную конструкцию или дополнительный параметр (это переписывание известно как eta-расширение):

# let map_id = List.map (function x -> x) (* Result is weakly polymorphic *)
val map_id : '_a list -> '_a list = <fun>
# map_id [1;2]
- : int list = [1;2]
# map_id (* No longer polymorphic *)
- : int list -> int list = <fun>
# let map_id' l = List.map (function x -> x) l
val map_id' : 'a list -> 'a list = <fun>
# map_id' [1;2]
- : int list = [1;2]
# map_id' (* Still fully polymorphic *)
- : 'a list -> 'a list = <fun>

Эти два определения семантически эквивалентны, и новому может быть назначена схема полиморфного типа, поскольку она больше не является функциональным приложением.

Смотрите также это обсуждение о том, что _ в '_a указывает - слабые переменные неполиморфного типа.

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