For a while, a project of mine included this code:
type typ_ctx = string -> coq_type
let gamma = ref (fun _ -> Error)
let update_typctx id value =
gamma := fun x -> if x = id then value else !gamma id
I failed to realize for a very long time that the latest value
passed into update_typctx
would “overwrite” anything else inside of gamma, I’m assuming because the reference to !gamma
is only computed when the function is called, so it would just call back to the “top-level” map instead of recursively looking deeper into the map until it hits the original fun _ -> Error
. For example:
# type coq_type = Error | Z | String | Unit | Record | Bool | Vector of coq_type
;;
type coq_type =
Error
| Z
| String
| Unit
| Record
| Bool
| Vector of coq_type
# let gamma = ref (fun _ -> Error)
;;
val gamma : ('_weak1 -> coq_type) ref = {contents = <fun>}
# !gamma "id";;
- : coq_type = Error
# let update id value = gamma := fun x -> if x = id then value else !gamma id;;
val update : string -> coq_type -> unit = <fun>
# update "array" (Vector Bool);;
- : unit = ()
# !gamma "array";;
- : coq_type = Vector Bool
# !gamma "id";;
- : coq_type = Vector Bool (* This should still be Error! *)
Is it at all possible to create a reference to a map like this? I’ve made the mistake of building much of my project’s structure around not needing to pass around a gamma and it would be a big hassle to reconfigure everything.