On 09/29/22 11:58, Richard W.M. Jones wrote:
It seems to be possible with phantom types & GADTs which are a very dark corner of OCaml and one which we shouldn't use, but here's how:
*shudder* thanks for writing this all up, but I think I'm *swiftly* taking the above hint! :) Laszlo
----------------------------------------------------------------------
type nullable type not_nullable
type _ arg = | Char : not_nullable arg | Int : not_nullable arg | String : nullable arg | List : nullable arg
(* # Char ;; - : not_nullable arg = Char # String ;; - : nullable arg = String *)
let only_for_nullables = function | String -> "do something" | List -> "do something else" | not_nullable -> . (* val only_for_nullables : nullable arg -> string = <fun> *)
----------------------------------------------------------------------
Notes:
(1) The “| not_nullable -> .” line can be omitted. It's just there to document the unreachable case, but (in this case) the compiler can infer this.
(2) If you omit either of the “| String“ or “| List“ cases then the compile will warn about incomplete matching, which is good.
Extending the example further, you can see how GADTs make the common case (second one below) possible, but harder to write:
---------------------------------------------------------------------- # let only_not_nullables = function | Char -> "char" | Int -> "int" ;; val only_not_nullables : not_nullable arg -> string = <fun>
# let all : type a. a arg -> string = function | Char -> "char" | Int -> "int" | String -> "string" | List -> "list";; val all : 'a arg -> string = <fun> ----------------------------------------------------------------------
Rich.