Skip to content

Instantly share code, notes, and snippets.

@jchavarri
Created January 7, 2019 16:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jchavarri/470e94adc174e7a452711337d6324635 to your computer and use it in GitHub Desktop.
Save jchavarri/470e94adc174e7a452711337d6324635 to your computer and use it in GitHub Desktop.
SlotsInstantiation.re
module type SlotsType = {
type t('slot, 'nextSlots);
let create: unit => t('slot, 'nextSlots);
let use:
(~default: 'slot, t('slot, t('slot2, 'nextSlots))) =>
(('slot, 'slot => unit), t('slot2, 'nextSlots));
};
module Slots: SlotsType = {
type t('slot, 'nextSlots) = ref(option(('slot, 'nextSlots)));
let create = () => ref(None);
let use = (~default, slots: t(_)) =>
switch (slots^) {
| None =>
let slot = default;
let nextSlots = create();
slots := Some((slot, nextSlots));
let set = slot => slots := Some((slot, nextSlots));
((slot, set), nextSlots);
| Some((slot, nextSlots)) =>
let set = slot => slots := Some((slot, nextSlots));
((slot, set), nextSlots);
};
};
let useState = (initial, slots) => slots |> Slots.use(~default=initial);
let primitive: 'a => 'a = x => x;
type element = int;
type component('slot, 'nextSlots) = {
initSlots: unit => Slots.t('slot, 'nextSlots),
render: Slots.t('slot, 'nextSlots) => element,
};
type opaqueComponent =
| OpaqueComponent(component('slot, 'nextSlots)): opaqueComponent;
type instance('slot, 'nextSlots) = {
slots: Slots.t('slot, 'nextSlots),
render: Slots.t('slot, 'nextSlots) => element,
};
type opaqueInstance =
| OpaqueInstance(instance('slot, 'nextSlots)): opaqueInstance;
module type Component = {
type slots;
type createElement;
let createElement: createElement;
};
let createComponent =
(
type c,
type s,
create:
(
(Slots.t(s, _) => element, ~children: list(element)) =>
opaqueComponent
) =>
c,
)
: (module Component with type createElement = c and type slots = s) =>
(module
{
type slots = s;
type createElement = c;
let createElement =
create((userRender, ~children) => {
ignore(children);
OpaqueComponent({
initSlots: () => Slots.create(),
render: slots => {
let childElement = userRender(slots);
childElement;
},
});
});
});
module MyComponent = (
val createComponent((render, ~one, ~two, ~children, ()) =>
render(
slots => {
let ((state, setState), slots) = useState(3, slots);
print_endline("before" ++ string_of_int(state));
setState(state + 1);
print_endline("after" ++ string_of_int(state));
let ((stateStr, _setStateStr), _slots) = useState("3", slots);
primitive(one + two + state + int_of_string(stateStr));
},
~children,
)
)
);
let opaqueComponent = <MyComponent one=1 two=2 />;
let render = (OpaqueInstance(instance)) => {
let bla = instance.render(instance.slots);
bla;
};
let instantiate = (OpaqueComponent(component)) => {
let instance = {slots: component.initSlots(), render: component.render};
OpaqueInstance(instance);
};
let someInstance = instantiate(opaqueComponent);
let renderOne = render(someInstance);
let renderTwo = render(someInstance);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment