在简单组件中输入变量

时间:2018-11-09 07:51:55

标签: compiler-errors polymorphism ocaml reason reason-react

说我有这个简单的组件

type evt =
  | NoOp;

type t('a) = 'a;

let component = ReasonReact.reducerComponent("TestComponent");

let make = _children => {
  ...component,
  initialState: () => "hello",
  reducer: (evt, state: t('a)) =>
    switch (evt) {
    | NoOp => ReasonReact.NoUpdate
    },
  render: self => <div> {str("hello")} </div>,
};

(尝试here

我为什么得到

The type of this module contains type variables that cannot be generalized

? (类型变量在这里没有用,但是想象一下initialState需要它。试图使样本尽可能简单。)

1 个答案:

答案 0 :(得分:2)

技术原因是ReasonReact组件是记录类型,看起来像这样:

type fauxComponent = {
  reducer: (evt, t('a)) => t('a),
  render: t('a) => ReasonReact.reactElement
};

如果尝试对此进行编译,则会收到有关“未绑定类型参数”的错误。错误的差异是因为推断其类型为ReasonReact.component,该类型具有一堆类型变量,其中一个推断为具有多态类型。问题本质上是相同的,但是在没有所有间接的情况下,说明起来都容易得多。

您无法做到这一点的技术原因,我称为the value restriction。但是也有实际原因。如果您将'a明确指定为多态,则实际上可以使该类型编译:

type fauxComponent = {
  reducer: 'a. (evt, t('a)) => t('a),
  render: 'a. t('a) => ReasonReact.reactElement
};

这表示'a可以是任何东西,但这也是问题所在。因为它可以是任何东西,所以您不知道它是什么,因此,除了让它通过并返回之外,您无法真正对其进行任何操作。您还不知道'areducer中的render是相同的,因为它们不是有状态的对象,所以记录通常不会出现问题。之所以会出现问题,是因为ReasonReact会像滥用它们一样“滥用”它们。

那么您将如何完成您想要做的事情?容易,使用函子! ;)在Reason中,您可以参数化模块,然后将其称为函子,并使用该参数指定要在整个模块中使用的类型。这是您的示例函数化了:

module type Config = {
  type t;
  let initialState : t;
};

module FunctorComponent(T : Config) {
  type evt =
  | NoOp;

  type t = T.t;

  let component = ReasonReact.reducerComponent("TestComponent");

  let make = _children => {
    ...component,
    initialState: () => T.initialState,
    reducer: (evt, state: t) =>
      switch (evt) {
      | NoOp => ReasonReact.NoUpdate
      },
    render: self => <div> {ReasonReact.string("hello")} </div>,
  };
};

module MyComponent = FunctorComponent({
  type t = string;
  let initialState = "hello";
});

ReactDOMRe.renderToElementWithId(<MyComponent />, "preview");

函子实际上需要使用的参数必须是模块,因此我们首先定义一个模块类型Config,将其指定为参数类型,然后在使用函子创建MyComponent模块时,创建并传递一个实现Config模块类型的匿名模块。

现在您知道为什么很多人认为OCaml和Reason的模块系统是如此的棒:)(实际上还有很多,但这是一个好的开始)