2013-04-21 69 views
0

在OCaml中,我正在處理一個模塊和一個仿函數。使用參數化模塊的OCaml

我爲輸入模塊和仿函數設置了簽名和結構。 然後我使用上面的模塊創建了一個新模塊。 原來,我的新模塊不包含輸入模塊中的功能。

我應該能夠使用我的新模塊功能?順便說一句,仿函數中的函數工作正常。 另外,我怎樣才能確定它是否是一個有效的模塊?

+4

請顯示一些源代碼。我們將用一個小代碼示例更好地理解您的問題.... – 2013-04-21 07:36:03

回答

2

在一個簡單的設置,通過仿函數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

+0

謝謝你的幫助,didierc。 – 2013-04-21 21:16:17

+0

完成了我的答案,希望有更多有用的信息,但我擔心我不能比@gasche做得更好。 – didierc 2013-04-21 21:56:19

5

讓我們一個真實的例子:

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 
+0

謝謝gasche!我知道了。 – 2013-04-21 21:18:06