So, how should I change this piece of code to make the compiler and type system happy? I was getting errors on different places of my app, but I realised that the problem must bu up in the chain, so I started to type things and I traced the problem to here:
open Standard
type col = String of string | Int of int
type row = col array
type sheet = row array
let pick_columns (a,b) (row: row): (string * int) =
((Array.get row a), Array.get row b)
Obviously the problem here is that pic_columns returns a tuple of col * col but it needs to be string * int, but since col can be string or int, I need to narrow it down, but I have no idea how.
Also, I don’t understand why I can’t return (row[a], row[b]), it tries to call row with a or something very weird.
The syntax for array access is row.(a). The compiler reads row[a] as applies row to the list [a]. Concerning your type problem, I don’t see any variadic arguments? And if you start with a sum type that handles all possible case, you nee a conversion function to translate your row to a more finely typed tuple:
let type_row a b row = match row.(a), row.(b) with
| String x, Int y -> Some (x, y)
| _ -> None
And the conversion function might fail, thus it needs to either raises an exception or returns an option.
That looks like exactly what I need! thanks!
I think the syntax for array access I saw it on a reason focused docs (albeit I changed the syntax to ocaml, this was hand-written).
I think I can use your function with some kind of flatMap to get rid of the rows that doesn’t match my desired shape.
Thanks!
You might be also interested in how we tackled with this problem in the Ogre library, which enables typed queries and employs variadic functions. Here is the link to the implementation.
This is what I had to add just to properly match the js code with ADTs. It is a lot of boilerplate and I don’t understand exactly how it works, but I checked that it works on real world. I’m not sure why I need an internal module inside my module, why do I need two functions inside the module (number, and string seem useless to me).
module Number_or_string : sig
type t
type case =
| Int of int
| String of string
val number : int -> t
val string : string -> t
val classify : t -> case
end = struct
type t =
| Any : 'a -> t
[@@unboxed]
type case =
| Int of int
| String of string
let number (v : int) = Any v
let string (v : string) = Any v
let classify (Any v : t) : case =
if Js.typeof v = "number" then Int (Obj.magic v : int)
else String (Obj.magic v : string)
end
type row = Number_or_string.t array
type sheet = row array
type sheet_map = int Standard.Map.String.t
let pick_columns (a,b) (row: row): (string * int) option =
match Number_or_string.classify(row.(a)), Number_or_string.classify(row.(b)) with
| String x, Int y -> Some (x, y)
| _ -> None