在OCaml中,我正在處理一個模塊和一個仿函數。使用參數化模塊的OCaml
我爲輸入模塊和仿函數設置了簽名和結構。 然後我使用上面的模塊創建了一個新模塊。 原來,我的新模塊不包含輸入模塊中的功能。
我應該能夠使用我的新模塊功能?順便說一句,仿函數中的函數工作正常。 另外,我怎樣才能確定它是否是一個有效的模塊?
在OCaml中,我正在處理一個模塊和一個仿函數。使用參數化模塊的OCaml
我爲輸入模塊和仿函數設置了簽名和結構。 然後我使用上面的模塊創建了一個新模塊。 原來,我的新模塊不包含輸入模塊中的功能。
我應該能夠使用我的新模塊功能?順便說一句,仿函數中的函數工作正常。 另外,我怎樣才能確定它是否是一個有效的模塊?
在一個簡單的設置,通過仿函數F
綁定的模塊M
導出的任何值可以通過使用M.
預選賽(像任何模塊)來訪問:
(* out there M does not exist *)
module F (M : sig val v : int end) =
struct
(* in there M is defined *)
let m_v = M.v
end
或通過之前的M
值的任何訪問使用open M
。
module F (M : sig val v : int end) =
struct
open M
let m_v = v
end
如果你想的M
可從F
生成的模塊中的值,你必須以某種方式將其導出,或者:直接由新模塊中走樣的M
一定值
,
module F (...) = struct
let v = M.v
end
通過包括其全部的模塊
module F (...) = struct
include M
end
因爲您可能想要定義與M
中的其他類型相沖突的類型名稱,所以並不總是可能或易於使用包含。
通過將模塊的新模塊
module F (....) = struct
module M' = M
end
module G = F(struct let v = 5 end);;
print_int G.M.v;;
包含或不包含的一部分嗎?它取決於仿函數的客戶端和生成模塊的客戶端。你可能在一個只知道生成模塊的程序上工作,或者只知道函數。如果模塊M
的內容對於運行準備好的模塊G
是必要的,那麼您必須以某種方式提供M
。
謝謝你的幫助,didierc。 – 2013-04-21 21:16:17
完成了我的答案,希望有更多有用的信息,但我擔心我不能比@gasche做得更好。 – didierc 2013-04-21 21:56:19
讓我們一個真實的例子:
module type MONAD = sig
type 'a t
val return : 'a -> 'a t
val (>>=) : 'a t -> ('a -> 'b t) -> 'b t
end
module MonadOps (M : MONAD) = struct
open M (* values from M visible in scope *)
let rec mapM f = function
| [] -> return []
| x::xs ->
f x >>= fun y ->
mapM f xs >>= fun ys ->
return (y :: ys)
end
module Option = struct
type 'a t = 'a option
let return x = Some x
let (>>=) m f = match m with
| None -> None
| Some x -> f x
end
module OptionOps = MonadOps(Option)
let test = OptionOps.mapM
(* val test : ('a -> 'b Option.t) -> 'a list -> 'b list Option.t = <fun> *)
let test = OptionOps.return x
(* Error: Unbound value OptionOps.return *)
函子MonadOps
提供建立在任何單子上面一些通用的功能,但它本身並不包含底座單子功能。它提供了額外的東西,而不包括現有的東西。
您可以更改使用include
項目包含模塊的值內現有模塊的內容被定義:
module MonadOps (M : MONAD) = struct
include M (* values from m *included* in the module *)
let rec mapM f = function
[...]
end
不過,我並不建議這樣做。你正在引入一些冗餘,這在某些情況下是很方便的(例如,如果你想open
只是一個模塊,並且範圍一切),但也可以在其他情況下解決一些問題,例如。如果你想結合兩個模塊擴展仿函數,你不得不想知道應用它們的順序,你可能會遇到奇怪的模塊系統hackery。 ML模塊系統是內部複雜的野獸,我建議保持您的使用簡單,以避免碰到拐角。
請注意,如果不將M包含在仿函數中,則可以讓仿函數的用戶選擇在需要時執行該操作:如果您決定直接將其包含在仿函數中,則它們有更多選項。我會用這個函子的方式將類似
(* file 'option.ml' *)
type 'a option = None | Some of 'a
module Monad = struct
...
end
module Ops = MonadOps(Monad)
include (Monad : MONAD with type 'a t := 'a option)
include Ops
謝謝gasche!我知道了。 – 2013-04-21 21:18:06
請顯示一些源代碼。我們將用一個小代碼示例更好地理解您的問題.... – 2013-04-21 07:36:03