OCaml-未绑定记录字段

OCaml-未绑定记录字段,ocaml,record,functor,Ocaml,Record,Functor,我是OCaml新手,我正在尝试将一些Haskell代码转换为OCaml 我有下面的代码,其中我研究了OCaml模块系统和函子 module type F = sig type 'a f val fmap : ('a -> 'b) -> 'a f -> 'b f end module type FOO = functor (C : F) -> sig type f end module Foo : FOO =

我是OCaml新手,我正在尝试将一些Haskell代码转换为OCaml

我有下面的代码,其中我研究了OCaml模块系统和函子

module type F =
  sig 
    type 'a f
    val fmap : ('a -> 'b) -> 'a f -> 'b f
  end

module type FOO =
  functor (C : F) ->
    sig
      type f 
    end

module Foo : FOO =
  functor (C : F) -> 
    struct
      type f = { foo : 'x . 'x C.f -> 'x ;
                 bar : 'x . 'x C.f -> 'x C.f }
    end

module List = 
  struct
    include List
    type 'a f = 'a list
    let fmap = List.map
  end

module Bar =
  struct
    include Foo (List)
    let ea = { foo = List.hd ; bar = List.tl }
  end
我一直有错误未绑定记录字段foo。 事实上,Foo是一个函子使事情复杂化了,我觉得我无法提供我想要的注释。
我遗漏了什么?

问题的出现是因为你说Foo有Foo的签名,而在Foo中你说f是抽象的,即它的定义是隐藏的。从编译器的角度来看,您故意隐藏了Foo.f的实现细节

有几种方法可以解决此问题:

从FOO中删除签名FOO,允许对其进行推断。 模块Foo= 函子C:F-> 结构 类型f={foo:'x.'xc.f->'x; 条形图:“x.”x C.f->“x C.f} 终止 将推断其类型为

模块Foo: 函子C:F-> sig type f={foo:'x.'x C.f->'x;bar:'x.'x C.f->'x C.f;}end 在FOO中提供f的完整类型定义。 模块类型FOO= 函子C:F-> 信号 类型f={foo:'x.'xc.f->'x; 条形图:“x.”x C.f->“x C.f} 终止 在Foo和Foo中添加一个构造函数,允许您创建f类型的值,而无需知道其实现的确切细节。然而,在这种情况下,由于OCaml缺乏更高级别的多态性,这使得这变得更加困难,这意味着您无法将普遍量化的foo和bar函数直接传递给构造函数。解决方法是将这些函数包装在记录或对象中,这实际上只是将我们带回解决方案2。
问题的出现是因为你说Foo有Foo的签名,而在Foo中你说f是抽象的,也就是说它的定义是隐藏的。从编译器的角度来看,您故意隐藏了Foo.f的实现细节

有几种方法可以解决此问题:

从FOO中删除签名FOO,允许对其进行推断。 模块Foo= 函子C:F-> 结构 类型f={foo:'x.'xc.f->'x; 条形图:“x.”x C.f->“x C.f} 终止 将推断其类型为

模块Foo: 函子C:F-> sig type f={foo:'x.'x C.f->'x;bar:'x.'x C.f->'x C.f;}end 在FOO中提供f的完整类型定义。 模块类型FOO= 函子C:F-> 信号 类型f={foo:'x.'xc.f->'x; 条形图:“x.”x C.f->“x C.f} 终止 在Foo和Foo中添加一个构造函数,允许您创建f类型的值,而无需知道其实现的确切细节。然而,在这种情况下,由于OCaml缺乏更高级别的多态性,这使得这变得更加困难,这意味着您无法将普遍量化的foo和bar函数直接传递给构造函数。解决方法是将这些函数包装在记录或对象中,这实际上只是将我们带回解决方案2。
在接近OCaml的模块系统时需要注意的一点是,模块类型的主要用例之一是删除信息。此外,删除如此多的信息可能非常容易,因为受约束的模块M:S变得无用

您的模块类型FOO是删除过多信息的模块类型的一个示例。有,

模块类型FOO= 函子C:F-> 信号 f型 终止 类型f是一个抽象类型,它单独出现在生成的模块类型中。由于类型是抽象的,因此模块外的任何函数都无法创建它。而且也没有可见的方法从函子内部创建这种类型的值。因此,不可能创建这种类型的值。换句话说,该模块类型在功能上等同于

模块类型FOO=函子C:F->sig end 及

模块F:FOO=。。。 这意味着应用F只能用于其副作用


作为一般建议,当开始在OCaml中使用函子时,通常最好让编译器推断它们的类型。这避免了编写删除过多信息的模块类型这一常见问题。

在接近OCaml的模块系统时需要注意的一点是,模块类型的主要用例之一是删除信息。此外,删除如此多的信息可能非常容易,因为受约束的模块M:S变得无用

您的模块类型FOO是删除过多信息的模块类型的一个示例。有,

模块类型FOO= 函子C:F-> 信号 f型 终止 类型f是一个抽象类型,它单独出现在生成的模块类型中。由于类型是抽象的,因此模块外的任何函数都无法创建它。而且也没有可见的方法从函子内部创建这种类型的值。因此,不可能创建这种类型的值。换句话说,此模块类型是功能性的 相当于

模块类型FOO=函子C:F->sig end 及

模块F:FOO=。。。 这意味着应用F只能用于其副作用

作为一般建议,当开始在OCaml中使用函子时,通常最好让编译器推断它们的类型。这样就避免了编写模块类型这一常见问题,从而删除了太多的信息