2015-02-25 30 views
21

birisi beni/Bunu anlamak biraz okuma materyallerine bana gelin yardımcı olabilir misiniz? İnce aşağıdaki çalışır:Bu eta genişlemesi neden gereklidir?

type F a b = Functor f => f a -> f b 
fComp :: F b c -> F a b -> F a c 
fComp f f' = f . f' 

yerine fComp = (.) yazarsanız Ama yazın denetleyicisi yakınır:

Couldn't match type ‘b0 -> f c’ 
       with ‘forall (f1 :: * -> *). Functor f1 => f1 b -> f1 c’ 

(Bu spesifik bir örnek özellikle yararlı değildir, ben sadece bir örnek küçültmek çalışıyorum lensleri okurken o geldi.)

cevap

12

fComp yüksek rütbe türleri için daha yüksek rütbe tipi ve tipi çıkarım vardır çok sınırlıdır. f ve f' ait

fComp :: forall f a b c. Functor f => 
       (forall f1. Functor f1 => f1 b -> f1 c) -> 
       (forall f2. Functor f2 => f2 a -> f2 b) -> 
       (f a -> f c) 

yüksek rütbe tipleri bu tür imzası açıkça belirtilir: Biz tipi eşanlamlı genişletmek eğer biraz anlamak daha kolay (! Ama çok daha uzun) olabilir. Bu tür kesmesi . türü ile bunları birleştirmek mümkün yüzden f ve f' türlerini bilerek şimdiden başlayıp sağlar. Ancak, f ve f''dan kurtulursanız, .'un alması gereken tür bilinmemektedir. Ne yazık ki, sistem bu gibi daha yüksek sıralı türler çıkarıyor, bu yüzden bir tür hatası alıyorsunuz. Özünde

ve tür kesmesi sırasında bilinmeyenler doldurmak için daha yüksek rütbe türlerini oluşturamaz derleyici programcı ek açıklamaları güvenmek zorundadır ve biz bu haberler adı (f ve f') ve tipi imza hem ihtiyaç ek açıklamalar. anlamak

daha kolay bir örnek daha yüksek rütbe id fonksiyonu olacaktır:

myId :: (forall a. a) -> (forall b. b) 

çözünürlüklü myId x = id x derler, ama myId = id aşağıdaki hatayı veriyor:

/home/tikhon/Documents/so/eta-expansion-needed.hs:11:8: 
    Couldn't match type ‘b’ with ‘forall a. a’ 
     ‘b’ is a rigid type variable bound by 
      the type signature for myId :: (forall a. a) -> b 
      at /home/tikhon/Documents/so/eta-expansion-needed.hs:11:1 
    Expected type: (forall a. a) -> b 
     Actual type: b -> b 
    In the expression: id 
    In an equation for ‘myId’: myId = id 
Failed, modules loaded: none. 

(unutmayın forall b. (forall a. a) -> b o (forall a. a) -> (forall b. b) aynıdır.)

+0

Bunu tam olarak anlamak için hangi kitapları okumam gerekir? –

+0

@ErikAllik: Kesinlikle emin değilim. Ben giderken eşyaları topluyorum. [Tyk Haskell in Haskell] (http://web.cecs.pdx.edu/~mpj/thih/thih.pdf) makalesine göz atabilir ve ayrıca * Türler ve Programlama Dilleri'nde * yer alabilir. TAPL) bir ton diğer malzeme ile birlikte. –

6

bana e yeniden yazılmalı System-F benzeri bir notasyon kullanarak örnekleme yapın; Aşağıda, \\, tip soyutlama (büyük lambda) ve sözlük soyutlamayı temsil eder. Ayrıca, @ tipi/sözlük uygulaması anlamına gelir.

İşte
(.) :: forall a b c . (b -> a) -> (c -> b) -> (c -> a) 

(değil kalbin zayıf, dikkat) açıklamalı kod::

Bunu yapmadan önce, (.) tipini hatırlamak ben davrandı Üstü (

fComp :: F b c -> F a b -> F a c 
fComp (f :: forall f1. Functor f1 => f1 b -> f1 c) 
     (f':: forall f2. Functor f2 => f2 a -> f2 b) 
    = \\ ff :: (* -> *) -> 
    \\ ffD :: Functor ff -> 
    ((.) @ (ff c) @ (ff b) @ (ff a)) -- instantiated composition 
    (f @ ff @ ffD)     -- first argument of (.) 
    (f' @ ff @ ffD)     -- second argument of (.) 

a, bc, tip-düzey lambdalardan kaçınmak için tip sabitlerdir.)

önemli parçaları:

  • f ve f' belirli türleri de kullanılmaktadır. Bu, (.)'a beslenmeden önce tür düzeyinde argümanlara uygulanmaktadır.
  • (.)
  • Gördüğünüz gibi f ait politipine ve f'

olmayan tipler (ff c, vs) için tür düzeyinde uygulanıyor, orijinal kod uzak önemsiz olmaktan uzaktır. Tür çıkarımı, gerekli tip düzeyinde lambdaları ve uygulamaları ekleyebilir. Bunları ekledikten sonra, artık fComp sözleşmesini imzalayamayız. Pointfree değişkeninde, sonuç yazımının anlamlı durumdan daha fazlasını yapması gerekecektir. fComp'un ilk argümanı F a b türünde iken, (.)'un ilk argümanı, F a b = forall g . ... için birleşmeyen x -> y formunda olmalıdır. Nitekim başarıyla aşağıda yazarak girişimini çözmek için hiçbir yolu yoktur:

fComp :: F b c -> F a b -> F a c 
fComp 
    = \\ ff :: (* -> *) -> 
    \\ ffD :: Functor ff -> 
    ((.) @ ???a @ ???b @ ???c) 

Üstü hiçbir ???a var ... o istediği şeye yol açabilir.

tek olasılık F x y tiplerinde gizli forall -quantified değişkenleri örneğini, ama biz noktası gerektiğini yapmak olacaktır. Derleyici bu kodu sizin için genişletebilir, böylece noktalar görünür ve böylece teorik olarak konuşulabilir, ancak pratikte olmaz.

(Ayrıca, eta genişletme her zaman Haskell'de geçerli değildir: örn. seq (undefined::()->()) 3 döngüleri, seq (\x->(undefined::()->()) x) 33 döndürür).

+0

Bunu tam olarak anlamak için hangi kitapları okumam gerekir? –

+1

@ErikAllik Pierce's Türleri ve programlama dilleri güzel. Daha pratik bir yanda, Agda ya da Coq gibi bağımlı-yazılan bir dilde programlamayı öğrenerek genel fikirleri de edinebilirsiniz. Ayrıca, Haskell'i kullanabilir ve GHC'nin programınızın Çekirdek ara temsilini dökümünü isteyebilirsiniz. Burada, GHC'nin çıkarım sırasında eklediği tüm düzey düzeylerini görebilirsiniz. Elbette pratik bir teori kitabının yapabileceği her şeyi size söylemeyecektir, ancak bazı sezgiler oluşturmaya büyük ölçüde yardımcı olabilir (en azından benim için böyle oldu). – chi

+0

bu harika rehberlik; teşekkür ederim! –