Тип сгенерированного сгиба, iter и map не соответствует документации ppx_deriving - PullRequest
4 голосов
/ 08 апреля 2020

Я изо всех сил стараюсь правильно настроить свою среду OCaml для использования карт производных ppx, а также сворачивания и итераций, как описано здесь: https://github.com/ocaml-ppx/ppx_deriving#plugins -iter-map-and-fold

Вот мой минимальный пример (я использую Base, поскольку это библиотека, которую я использую в своем более широком проекте):

open Base;;

type data = Row of float array | Dim of data array
[@@deriving iter, map, fold, show];;

let t = Row [|2.;2.|];;
pp_data Caml.Format.std_formatter t;;
map_data (fun x -> x +. 1.) t;;
pp_data Caml.Format.std_formatter t;;

Следующий код скомпилирован с ocamlfind ocamlc -package base -package ppx_deriving.iter -package ppx_deriving.map -package ppx_deriving.fold -package ppx_deriving.show -linkpkg -g test.ml && ./a.out; Я получаю ошибку компиляции, утверждающую, что map_data имеет тип data -> data. Но согласно документации и моим общим знаниям, map получает функцию и отображаемую структуру, что, похоже, здесь не так. Проверка этого в utop выдает мне ту же ошибку.

Что-то мне не хватает?

Заранее спасибо :)

1 Ответ

3 голосов
/ 08 апреля 2020

Эти производные работают с polymorphi c структурами данных и применяют пользовательскую функцию ко всем значениям, соответствующим переменным типа этой структуры. Поскольку у вас нет переменных типа, сгенерированная функция map_data является дефектной, но вполне естественной, поскольку отсутствие переменной типа подразумевает постоянную функцию.

Другими словами, общая структура функции map_x для некоторых полиморфных c type ('s1, ..., 'sN) x с переменными типа N составляет

('s1 -> 't1) -> ... -> ('sN -> 'tN) -> ('s1,...,'sN) x -> ('t1,...,'tN) x

Т.е. для каждой переменной типа она ожидает функцию, которая отображает значения этого типа на какой-то другой тип, так что число аргументов функции map будет N+1 В вашем случае, поскольку у вас есть переменные нулевого типа, нет функций отображения, поэтому у вас просто x -> x .

Если вы переопределите свой тип как

type 'a data = Row of 'a array | Dim of 'a data array
[@@deriving iter, map, fold, show]

Вы получите map_data с ожидаемым типом ('a -> 'b) -> 'a data -> 'b data. Производный даже поймет, что массив является структурой данных, и вернется в нее, например,

let input = Dim [|Row [|1;2;3|]; Row [|3;4;5|]|]
map_data (fun x -> x + 1) input;;
- : int data = Dim [|Row [|2; 3; 4|]; Row [|4; 5; 6|]|]

Конечно, если вам не нужен тип polymorphi c в вашем интерфейсе, вы всегда можете создайте псевдоним типа, например,

type t = float data

и предоставьте map_data как

val map_data : (float -> float) -> t -> t
...