module type SlotsType = { type t('slot, 'nextSlots); let create: unit => t('slot, 'nextSlots); let use: ( ~default: 'slot, (('slot, t('slot2, 'nextSlots))) => 'c, t('slot, t('slot2, 'nextSlots)) ) => ('c, 'slot); }; module Slots: SlotsType = { type t('slot, 'nextSlots) = option(('slot, 'nextSlots)); let create = () => None; let use = (~default, continuation, slots: t(_)) => switch (slots) { | None => let slot = default; let nextSlots = create(); let next = (slot, nextSlots); (continuation(next), slot); | Some((slot, nextSlots)) => let next = (slot, nextSlots); (continuation(next), slot); }; }; type element = int; type hook('slot, 'nextSlots) = (element, Slots.t('slot, 'nextSlots)); let useState = (initial, slots) => slots |> Slots.use(~default=initial); let primitive: 'a => 'a = x => x; module type Component = { type element; type slots; type createElement; let createElement: createElement; let createSlots: unit => Slots.t(slots, _); }; let createComponent = (type c, type e, type s, create: ((e, s) => (e, s), Slots.t(s, _)) => c) : (module Component with type createElement = c and type element = e and type slots = s) => (module { type element = e; type slots = s; type createElement = c; let createSlots = () => Slots.create(); let createElement = create((element, slot) => (element, slot), createSlots()); }); module MyComponent = ( val createComponent((render, slots, ~one, ~two) => render( useState( 3, ((state, slots)) => useState( "3", ((stateStr, _slots)) => primitive(one + two + state + int_of_string(stateStr)), slots, ), slots, ), ) ) ); let test = (slots) => useState( 3, ((state, slots)) => useState( "3", ((stateStr, _slots)) => state + int_of_string(stateStr), slots, ), slots, ); let (slot, element) = test(Slots.create());