如何解决OCaml - 未绑定记录字段
我是 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
我一直遇到错误 Unbound record field foo
。
Foo
是函子这一事实使问题复杂化,我觉得我无法提供我想要的注释。
我错过了什么?
解决方法
问题出现是因为您说 Foo
具有 FOO
的签名,而在 FOO
中您说 f
是抽象的,即它的定义被隐藏。从编译器的角度来看,您故意隐藏了 Foo.f
的实现细节。
有几种方法可以解决这个问题:
- 从
FOO
中删除签名Foo
,允许对其进行推断。
module Foo =
functor (C : F) ->
struct
type f = { foo : 'x . 'x C.f -> 'x ;
bar : 'x . 'x C.f -> 'x C.f }
end
将推断其类型为
module Foo :
functor (C : F) ->
sig type f = { foo : 'x. 'x C.f -> 'x; bar : 'x. 'x C.f -> 'x C.f; } end
- 在
f
中提供FOO
的完整类型定义。
module type FOO =
functor (C : F) ->
sig
type f = { foo : 'x . 'x C.f -> 'x ;
bar : 'x . 'x C.f -> 'x C.f }
end
- 向
Foo
和FOO
添加构造函数,允许您创建f
类型的值,而无需知道其实现的确切细节。然而,在这种情况下,由于 OCaml 缺乏更高等级的多态性,这变得更加困难,这意味着您不能将通用量化的foo
和bar
函数直接传递给构造函数(参见 Section 5.3 in the OCaml manual )。解决方法是将这些函数包装在一个记录(或对象)中,这实际上只是让我们回到了解决方案 2。
在使用 OCaml 的模块系统时要谨慎的一件事是,模块类型的主要用例之一是删除信息。此外,与受限模块 (M:S
) 变得无用相比,移除如此多的信息非常容易。
您的模块类型 FOO
是删除过多信息的模块类型的示例。随着,
module type FOO =
functor (C : F) ->
sig
type f
end
type f
是一个抽象类型,它单独出现在生成的模块类型中。由于类型是抽象的,模块之外的任何函数都不能创建它。也没有可见的方法从函子内部创建这种类型的值。因此,永远不可能创建这种类型的值。换句话说,这个模块类型在功能上等同于
module type FOO = functor (C : F) -> sig end
和
module F: FOO = ...
暗示应用 F
只能用于其副作用。
作为一般建议,当开始在 OCaml 中使用函子时,通常最好让编译器推断它们的类型。这避免了编写删除过多信息的模块类型的常见问题。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。