ocaml - Map a subset of a polymorphic variant -
ocaml - Map a subset of a polymorphic variant -
i want apply function values within variant, result of function has same type input. how can create types work out? here's current attempt:
module t : sig type generic = [ `foo of int | `bar of int ] val map : (int -> int) -> ([< generic] 'a) -> 'a (* val : [`foo of int] *) end = struct type generic = [ `foo of int | `bar of int ] allow map fn = function | `foo x -> `foo (fn x) | `bar x -> `bar (fn x) allow map : (int -> int) -> ([< generic] 'a) -> 'a = obj.magic map (* allow : [`foo of int] = `foo 1 |> map succ allow b : [`bar of int] = `bar 1 |> map succ *) end this works as-is, if uncomment let a line get:
values not match: val map : (int -> int) -> [ `foo of int ] -> [ `foo of int ] not included in val map : (int -> int) -> ([< generic ] 'a) -> 'a it seems defining a has changed type of map, seems odd.
on other hand, putting after end of module works:
open t allow : [`foo of int] = `foo 1 |> map succ allow b : [`bar of int] = `bar 1 |> map succ finally, if alter definition of map to:
allow map : 'a. (int -> int) -> ([< generic] 'a) -> 'a = obj.magic map (i.e. adding explicit 'a. start) complains:
error: definition has type (int -> int) -> ([< generic ] 'a) -> 'a less general 'b. (int -> int) -> ([< generic ] 'b) -> 'b can explain what's going on? there improve way this? can utilize gadt avoid obj.magic, have pass every function call, i'd avoid.
in actual program, have various node types (area, project, action, contact, etc) , different operations apply different types, common.
for example, with_name can rename node type, if rename action result must action. if rename [area | project | action] result must [area | project | action], etc.
i used tuple, mutual details outside (e.g. (name * action ...)) makes hard users match on different types (especially they're abstract) , features mutual subsets (e.g. projects , actions can starred).
you got bite value restriction. typechecker, not knowing types in obj.magic map , in particular, injectivity/variance, can't generalize , waits module boundary. if merlin, shows type : (int -> int) -> (_[< generic ] 'a) -> 'a. notice _ shows monomorphic type variable. type variable specialized @ first usage, hence behavior when uncomment a.
apparently, typechecker manage generalize @ module boundary, not seek guess why since there (obj.)magic involved.
there no obvious nice solution this, since ocaml doesn't allow manipulate row variable , doesn't specialize type variable when come in 1 branch, except when using gadt (that deserve feature request. it's related this).
if have few cases, or no complicated combination, can seek that:
module t : sig type foo = foo type bar = bar type _ generic = | foo : int -> foo generic | bar : int -> bar generic val map : (int -> int) -> 'a generic -> 'a generic val : foo generic val b : bar generic end = struct type foo = foo type bar = bar type _ generic = | foo : int -> foo generic | bar : int -> bar generic allow map (type a) fn (x : generic) : generic = match x | foo x -> foo (fn x) | bar x -> bar (fn x) allow = foo 1 |> map succ allow b = bar 1 |> map succ end ocaml
Comments
Post a Comment