Hi Phage, I don’t mind at all.
First of all, with your headers function you are supplying a list with different types. The type-checker will complain that
"hello" is a
string when it is expecting an
int because of the
222. OCaml lists are “homogeneous” i.e. all elements must have the same type.
Secondly, (which may just be a typo in the markdown) is that your type annotation for the function
my_value needs to use parentheses. You want to restrict
s to only
Yaml.value types. The way it is written right now will force the return type to be a
let my_value (s : Yaml.value) = match s with
| `String x -> x
| _ -> ""
Though not strictly necessary, when working with polymorphic variants (i.e.
`String s) the type-checker will say your function has type
[> `String of string ] -> string meaning it could take more than just the
Yaml.value variants as a parameter (the
>). By adding the type annotation we restrict that.
OCaml-yaml does some type-inference for us when parsing yaml files. Whenever we parse
float (wrapping it in
"hello" becomes a
string (wrapped in a
`String - note the quotation marks wouldn’t be necessary for this). There’s no way I know of without effectively wrapping values, to write a single function which extracts the primitive types because then what type would that function have (it would need to return floats, strings, lists etc.). So right now, once the above is fixed
x3 is really
`Float 222. and when passed to
my_value this hits the catch-all case and we get
So there are two possible solutions - (a) convert all Yaml values to one type (say a
string) or (b) write “unboxing” like functions for each Yaml value type and apply them based on your knowledge of what things should be. (a) is straightforward as ocaml-yaml can do it for you.
(* Raise exception version *)
let my_value = Yaml.to_string_exn
(* Provide a default version *)
let my_value s = match Yaml.to_string s with
| Ok s -> s
| _ -> ""
Note that by convention functions ending in
_exn raise an expection and without this ending they usually return an
'a t for some
option are common, ocaml-yaml uses the former).
The second option is to use unboxing function for each Yaml.value type and either provide defaults for the
_ catch-all case or raise your on error. Here are two examples:
let unbox_float (f : Yaml.value) = match f with
| `Float f -> f
| _ -> 0.
let unbox_array (a : Yaml.value) = match a with
| `A f -> f
| _ -> 
But now there’s a problem, the list returned by
unbox_array contains “boxed” elements Unfortunately without reboxing them to have a single type or through GADT magic (which I know little about) to make heterogeneous lists you just have to put up with this (which I don’t think is a bad thing).
Hope this helps – I feel like this is a great example of how OCaml’s type system feels a little “restricting” but is actually guiding you in writing safer and less error-prone code by having to handle the types and provide cases for everything that you have to.