2013-02-26 19 views
12

ı seçenekler listesi var diyelim:OCaml: Yüksek kinded polimorfizmi (modülleri üzerinde abstracting?)

let opts = [Some 1; None; Some 4] 

Ben, listenin bir seçenek haline bu dönüştürmek istiyorsanız, öyle ki:

  • Liste None içeriyorsa, sonuç None
  • Aksi takdirde, çeşitli mürekkepler toplanır. Gerçekten tip üzerinde soyut istiyorum, soru başlık da anlaşılacağı gibi,

    let sequence foo = 
    let open Option in 
    let open Monad_infix in 
        List.fold ~init:(return []) ~f:(fun acc x -> 
        acc >>= fun acc' -> 
        x >>= fun x' -> 
        return (x' :: acc') 
        ) foo;; 
    

    Ancak:

O (Core kullanarak ve Monad modülü) bu özel durum için bu yazmak için nispeten basittir Option uzmanlaşmak yerine kurucu. Çekirdek, daha iyi bir türün etkisini vermek için bir functor kullanıyor gibi görünüyor, ancak modül üzerinde soyutlanacak fonksiyonu nasıl yazabileceğimi açıklamıyorum. Scala'da, bazı Monad[M[_]]'un kullanılabilirliğini gerektiren örtük bir bağlam kullanacağım. Modülden örtülü olarak geçmenin bir yolu olmadığını umuyorum, ama bunu açıkça nasıl yaparım? Başka bir deyişle, yaklaşık olarak bir şey yazabilir miyim:

Bu, birinci sınıf modüller ile yapılabilecek bir şey mi?

Düzenleme: Tamam, aslında bu özel kodu kullanarak denemek için bana oluşmaz bu yüzden ve bunun Beklediğimden daha çalışmaya daha yakın görünür! Görünüşe sözdizimi aslında geçerlidir, ancak bu sonucu elde:

Error: This expression has type 'a M.t but an expression was expected of type 'a M.t 
The type constructor M.t would escape its scope  

hatasının ilk bölümü Eşleştiklerinden beri kafa karıştırıcı gibi görünüyor, bu yüzden sorunu tahmin ediyorum ikinci ile - burada sorun var mı dönüş tipi belirlenmemiş gibi görünüyor? Sanırım içeri aktarılan modüle bağlı - bu bir problem mi? Bu uygulamayı düzeltmenin bir yolu var mı?

+0

Bu eski soru sizin için yararlı olabilir: http://stackoverflow.com/questions/1986374/higher-order-type-constructors-and-functors-in-ocaml – rgrinberg

cevap

18

Birincisi, burada el altında Çekirdek var ve hala örnek derlemek için denemek istemeyen insanlar için (miras standart kütüphanenin List.fold_left kullanarak) bir kod kendine yeten bir versiyonudur.

module type MonadSig = sig 
    type 'a t 
    val bind : 'a t -> ('a -> 'b t) -> 'b t 
    val return : 'a -> 'a t 
end 

let sequence (module M : MonadSig) foo = 
    let open M in 
    let (>>=) = bind in 
    List.fold_left (fun acc x -> 
    acc >>= fun acc' -> 
    x >>= fun x' -> 
    return (x' :: acc') 
) (return []) foo;; 

Alacağınız hata mesajı araçlar (kafa karıştırıcı ilk satırı göz ardı edilebilir) Mt tanımı M modülüne yerel ve size ne yapacağını kapsamını, kaçmak gerektiğini Yazmak için çalışıyoruz. Eğer modülleri soyut izin birinci sınıf modülleri, kullanıyor, ancak dönüş type argümanının modül değerine bağlıdır örneğin olarak bağımlı görünümlü türleri için değil, ya da en azından yol nedeniyle

Bu

olduğunu (burada M).

bu örneği düşünün:

module type Type = sig 
    type t 
end 

let identity (module T : Type) (x : T.t) = x 

Bu yanlıştır.hata iletileri (x : T.t) üzerinde puan ve der ki:

Error: This pattern matches values of type T.t 
     but a pattern was expected which matches values of type T.t 
     The type constructor T.t would escape its scope 

Ne can hiçbir kaçış artık kalmayacak şekilde, birinci sınıf modülü T soyut önce istenen tipine soyut yapmak.

let identity (type a) (module T : Type with type t = a) (x : a) = x 

Bu yeteneği dayanır için a değişken türü üzerinde açıkça soyut. Ne yazık ki, bu özellik daha yüksek değerli değişkenler üzerinde soyutlamaya genişletilmemiştir. Şu anda olamaz yazma:

çözüm bir functor kullanmaktır
let sequence (type 'a m) (module M : MonadSig with 'a t = 'a m) (foo : 'a m list) = 
    ... 

: yerine değeri düzeyinde çalışma, daha zengin bir tür dili vardır modül düzeyinde çalışır. Bunun yerine monad üzerinden her monadic operasyonu (sequence, map vs.) soyut sahip

module MonadOps (M : MonadSig) = struct 
    open M 
    let (>>=) = bind 

    let sequence foo = 
    List.fold_left (fun acc x -> 
     acc >>= fun acc' -> 
     x >>= fun x' -> 
     return (x' :: acc') 
    ) (return []) foo;; 
end 

, bir modül çapında soyutlama yapmak.

+0

Evet, noktaya vardım Soruna neden olan bağımlı (-ish) olduğunu varsayarak! Çok detaylı bir cevap için teşekkürler. – Impredicative