Reputation: 2412
I'm trying to make a typed version of React as an exercise in Ocaml. To make it more functional, I'm passing a record as argument to render.
type ('props,'state) reactInstance =
{
props: 'props;
state: 'state;
updater: 'a . ('props,'state) reactInstance -> 'a -> 'state -> unit;}
and ('props,'state) reactClass =
{
getInitialState: unit -> 'state;
render: ('props,'state) reactInstance -> element;}
module type ComponentBluePrint =
sig
type props
type state
val getInitialState : unit -> state
val render : (props,state) reactInstance -> element
end
module type ReactClass =
sig
type props
type state
val mkUpdater :
props ->
((props,state) reactInstance -> 'e -> state) ->
(props,state) reactInstance -> 'e -> unit
val reactClass : (props,state) reactClass
end
module CreateComponent(M:ComponentBluePrint) =
(struct
include M
let rec mkUpdater props f i e =
let nextState = f i e in
let newInstance =
{ props; state = nextState; updater = (mkUpdater props) } in
()
let reactClass =
{ render = M.render; getInitialState = M.getInitialState }
end : (ReactClass with type props = M.props and type state = M.state))
One thing I don't understand is why the compiler can't infer the type of updater = (mkUpdater props)
in let newInstance = { props; state = nextState; updater = (mkUpdater props) }
.
Error: Signature mismatch:
Values do not match:
let mkUpdater :
props =>
(reactInstance props state => '_a => '_b) =>
reactInstance props state => '_a => unit
is not included in
let mkUpdater :
props =>
(reactInstance props state => 'e => state) =>
reactInstance props state => 'e => unit
What's the difference between '_a and 'e ? It looks exactly to same to me. How do I make this type check?
Upvotes: 2
Views: 493
Reputation: 35210
A type variable '_a
(the actual letter doesn't matter, the crucial thing is the underscore) is a so called weak type variable. This is a variable that cannot be generalized, i.e., it can be substituted with only one concrete type. It is like a mutable value, but in the realm of types.
A type denoted with a weak type variable '_a
is not included in a type that is denoted with a generic type variable. Moreover, it even can't escape the compilation unit, and should be either hidden or concretized.
Weak type variables are created when an expression is not a pure value (that is defined syntactically). Usually, it is either a function application, or an abstraction. It is usually possible, to get rid of weak type variables by doing a so called eta-expansion, when you substitute a partially applied function to a normal function application by enumerating all function arguments, i.e., updater = (fun props f i e -> mkUpdater props f i e)
.
Upvotes: 2