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.