compiler-errors - 在简单组件中键入变量

标签 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 )

为什么我会得到

该模块的类型包含无法泛化的类型变量

? (类型变量在这里没有用,但想象一下在initialState中需要它。尝试使示例尽可能简单。)

最佳答案

技术原因是 ReasonReact 组件是记录类型,如下所示:

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

如果您尝试编译此代码,您将收到有关“未绑定(bind)类型参数”的错误。错误的差异是因为它被推断为ReasonReact.component 类型,它有一堆类型变量,其中一个被推断为具有多态类型。问题本质上是相同的,但在没有所有间接的情况下更容易说明。

我认为你不能这样做的技术原因称为 the value restriction 。但也有实际原因。如果您明确指定 'a 为多态,您实际上可以编译此类型:

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

这表明 'a 可以是任何东西,但这也是问题所在。由于它可以是任何东西,因此您无法知道它是什么,因此除了让它通过并返回之外,您实际上无法对它做任何事情。您也不知道 'areducerrender 中是相同的,这通常不是记录的问题,因为它们' re 不是有状态的对象。问题的出现是因为 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 的模块系统如此棒了:)(实际上还有很多东西,但这是一个好的开始)

关于compiler-errors - 在简单组件中键入变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53221716/

相关文章:

java - 我可以避免将接口(interface)方法参数类型转换为同一系列类的具体类型吗?

java - 在java中传递后代而不是接口(interface)

recursion - 在 OCaml 中折叠列表

c++ - C++错误的参数类型-函数指针

C++ "simple"具有任意参数和返回值的函数的函数回调

c++ - 内部交换子类型的范例

recursion - OCaml 中的多态递归 : return values

java - Java 类的问题

iphone - 编译时Xcode总线错误

debugging - 何时应使用 -g 在 OCaml 中打印堆栈跟踪?