Resolving type parameter in module functor

Hi [Yawar, sorry] et. al :wink:
Back into module types and functors trying to build essentially a composable reducer system.

rescript-lang/try example

module type Partial = {
  type partial
  let reduce: (partial, 'action) => option<partial>
}

module Float = {
  type partial = float
  let reduce = (partial: partial, action: 'action):  option<partial> => {
    switch action {
      | #Set(a) => ...
}

module Array = (E: Partial) => {
  type structure<'e> = array<'e>
  type partial = structure<E.partial>

  let reduce = (p: partial, action: [#Index(int, 'action)]): option<partial> => {
    switch action {
      | #Index(index, action) => <find element, send action to element, recompose array>
}

and this fails with

Signature mismatch:
  ...
  Values do not match:
    let reduce: (partial, [> #Clear | #Set(partial)]) => option<partial>
  is not included in
    let reduce: (partial, 'action) => option<partial>
  File "playground.res", line 3, characters 3-52: Expected declaration
  File "playground.res", line 8, characters 7-13: Actual declaration

Any thoughts? Saying poly variant not in type parameter doesnt compute for me.
It seems like the type parameter is being resolved at the source module maybe and not at the calling-module?

Thanks again
Alex

Someone can probably explain the nuances better than me, but one solution is to explicitly declare the action type:

module type Partial = {
  type partial
++  type action
--  let reduce: (partial, 'action) => option<partial>
++  let reduce: (partial, action) => option<partial>
}

module Float = {
  type partial = float
++  type action = [#Set(partial) | #Clear]
  let reduce = (partial: partial, action: action):  option<partial> => {
    switch action {
      | #Set(a) => ...
}

This should compile now.

Thanks John
That solves the product case but then the poly variants [would not be] summable?

sum type action composition

I’m not sure if that’s feasible (anyone, feel free to correct me), but I’d also question if that’s a desirable design in the first place. How would the implementation of Either.reduce work?

This makes more sense to me:

type action = [#Left(L.partial) | #Right(R.partial) | #LAaction(L.action) | #RAction(R.action)]

Otherwise, if L.action and R.action share any of the same constructors, then it’s ambiguous how the reduce function should behave (even if it compiles).

poly variants do sum nicely. and failed compile on conflicting constructors sounds good:

poly variant sum conflicts

My immediate application is a Sum where both sides are products with some equivalent fields. So id rather not have to be aware at the client level which value the sum is taking when i send a new action.

I could see both overlapping and non overlapping sums being useful, and available with either different Functors or some supplied policy module

@yawaramin do you know anything about this?

Other examples I’ve seen in ocaml seem to deal with concrete type name interference, but these are poly variants and type parameters mostly?

[just realized i got your name wrong above, excuse me]
Thanks
Alex