为什么在Ocaml中使用模块类型?

问题描述 投票:3回答:3

我对Ocaml中的模块类型感到困惑。

我想知道在哪种情况下我们应该使用模块类型?

我通常在.mli中使用模块sig来公开一些细节,并在.ml中放置相应的实现模块结构。

例如:

.mli

module A:
 sig
   type t = T of string
 end

.ml

module A =
 struct
   type t = T of string
 end

出于这个原因,我认为Ocaml的模块就像C.中的.h和.c文件一样。

我知道模块类型可以声明一个接口,但是接口与Java的接口不同。

就像书中的一个例子:

open Core.Std

 module type ID = sig
  type t
   val of_string : string -> t
  val to_string : t -> string
 end

  module String_id = struct
   type t = string
    let of_string x = x
    let to_string x = x
  end

  module Username : ID = String_id
  module Hostname : ID = String_id

  type session_info = { user: Username.t;
                  host: Hostname.t;
                  when_started: Time.t;
                }

  let sessions_have_same_user s1 s2 =
       s1.user = s2.host

上面的代码有一个错误:它将一个会话中的用户名与另一个会话中的主机进行比较,在两种情况下应该比较用户名。

似乎模块类型无法为其实现提供新的通用超类型。

什么是模块类型的真正应用?

types functional-programming ocaml
3个回答
6
投票

这里,模块类型用于将类型t隐藏到模块的用户。

当一个人使用Username.tHostname.t时,不能依赖那些类型的字符串,整数或任何特定类型。模块类型使它们不透明,就好像它们不是模块接口的一部分,而只是模块编写器将来要改变的实现细节。

基本上,模块的用户只能通过模块功能对t进行操作。

编译器检查用户代码是否对这些类型t实际上是什么做出任何假设,以便将来模块编写者可以在不破坏用户代码的情况下更改它们。


3
投票

正如已经提到的,这里模块类型用于实现类型t的更抽象的视觉。当你将UsernameHostname定义为两个独立的模块时,它意味着逻辑上它们必须是不同的,并且这个模块的签名是唯一可能的方法。

但是当你说:你说错了:

似乎模块类型无法为其实现提供新的通用超类型。

实际上你可以确切地说Username.tHostname.t是相同的类型。

module Username = (String_id : ID with type t = String_id.t)
module Hostname = (String_id : ID with type t = String_id.t)

Username.to_string (Hostname.of_string "hi")

这里没用,但有时它真的很有帮助。


0
投票

module typesfunctors密切相关。阅读the module system章节。

仿函数的参数有一些模块类型,结果也是如此。

Functor被大量使用,大多数标准容器(例如Set-s或Map-s)都是仿函数。

如果您开发通用容器,您肯定会需要仿函数和模块类型。

(所以仿函数和模块类型在Ocaml中非常有用,而模板在C ++中很有用)

© www.soinside.com 2019 - 2024. All rights reserved.