[Solved] Js_array map typing issue - cannot map to a new type

The following has been tried on js_of_ocaml 3.5.1 and 3.5.2.

I’m trying to transform a js_array from an 'a to a 'b however I’m getting errors which suggest that map can only transform an 'a to an 'a. The interface states the type is:

method map : ('a -> int -> 'a js_array t -> 'b) callback -> 'b js_array t meth

The important part being:

('a -> int -> 'a js_array t -> 'b) callback

But the top level gives me:

#show Js_of_ocaml.Js.js_array;;
    method map :
      ('a -> int -> 'a Js_of_ocaml.Js.js_array Js_of_ocaml.Js.t -> 'a)
      Js_of_ocaml.Js.callback ->
      'a Js_of_ocaml.Js.js_array Js_of_ocaml.Js.t Js_of_ocaml.Js.meth

The important part being:

('a -> int -> 'a Js_of_ocaml.Js.js_array Js_of_ocaml.Js.t -> 'a) Js_of_ocaml.Js.callback

And just to try it:

open Js_of_ocaml;;
let arr = Js.array [| 1; 2; 3 |];;
val arr : int Js_of_ocaml.Js.js_array Js_of_ocaml.Js.t = <abstr>
arr##map (Js.wrap_callback (fun v _ _ -> float v));;
Line 1, characters 0-8:
Error: This expression has type
         (int -> int -> int Js_of_ocaml.Js.js_array Js_of_ocaml.Js.t -> int)
         Js_of_ocaml.Js.callback ->
         int Js_of_ocaml.Js.js_array Js_of_ocaml.Js.t Js_of_ocaml.Js.meth
       but an expression was expected of type
         (unit,
          int -> int -> int Js_of_ocaml.Js.js_array Js_of_ocaml.Js.t -> float)
         Js_of_ocaml.Js.meth_callback -> 'res Js_of_ocaml.Js.meth
       Type
         (int -> int -> int Js_of_ocaml.Js.js_array Js_of_ocaml.Js.t -> int)
         Js_of_ocaml.Js.callback =
           (unit,
            int -> int -> int Js_of_ocaml.Js.js_array Js_of_ocaml.Js.t -> int)
           Js_of_ocaml.Js.meth_callback
       is not compatible with type
         (unit,
          int -> int -> int Js_of_ocaml.Js.js_array Js_of_ocaml.Js.t -> float)
         Js_of_ocaml.Js.meth_callback 
       Type int is not compatible with type float 

What’s going on here? Is there a way to use map?

Hi, I don’t think that the problem is about your usage of map but about your usage of float.
val float : float -> float is a deprecated function and it should take a float and return a float. So I suggest arr##map (Js.wrap_callback (fun v _ _ -> float_of_int v)).

edit : There’s also Js.array_map where the callback is already wrapped : Js.array_map float_of_int arr

float_of_int doesn’t work either and the type of float is int -> float in this toplevel, so I do not believe that is the issue.

But Js.array_map does work, thank you:

Js.array_map float arr;;
- : float #Js_of_ocaml.Js.js_array Js_of_ocaml.Js.t = <abstr>

Looking at the code for Js.array_map, looks like it has to do some magic to get around some type restrictions:

let array_map_poly :
    'a #js_array t -> ('a -> int -> 'a #js_array t -> 'b) callback -> 'b #js_array t =
 fun a cb -> (Unsafe.coerce a)##map cb

let array_map f a = array_map_poly a (wrap_callback (fun x _idx _ -> f x))

let array_mapi f a = array_map_poly a (wrap_callback (fun x idx _ -> f idx x))

I maybe miss something but in your example :

let arr = Js.array [| 1; 2; 3 |];;
(* val arr : int Js_of_ocaml.Js.js_array Js_of_ocaml.Js.t = <abstr> *)

So your array is int js_array Js.t, and the type of float is, according the documentation val float : float -> float. So I suppose (but i’m maybe wrong) that you want having a float js_array Js.t from an int Js.js_array Js.t and float_of_int goes from int to float.

I’m not sure I follow your response. I was trying to build the function to pass to the map method. This operates on each individual element of the Js.js_array