GHC'de Otomatik Uzmanlaşmanın Geçişliliği


392

Gönderen docs ghc 7.6 için:

[Y] Genellikle ilk etapta UZMANLIK pragmasına bile ihtiyaç duymazsınız. Bir modül M derlenirken, GHC'nin iyileştiricisi (-O ile) M'de bildirilen her üst düzey aşırı yük fonksiyonunu otomatik olarak dikkate alır ve M'de çağrıldığı farklı tipler için uzmanlaşır. İyileştirici ayrıca içe aktarılan her INLINABLE aşırı yük fonksiyonunu, ve M'de adlandırıldığı farklı türler için uzmanlaşmıştır.

ve

Dahası, bir f işlevi için ÖZELLEŞTİRİLMİŞ pragma verildiğinde, GHC, SPECIALIZE pragma ile aynı modüldeyse veya INLINABLE ise, f tarafından çağrılan tüm tip-aşırı yüklenmiş işlevler için otomatik olarak uzmanlıklar oluşturur; ve benzeri, geçişli.

Bu yüzden GHC, pragma olmadan işaretlenmiş bazı / çoğu / tüm (?) İşlevlerini otomatik olarak uzmanlaştırmalıdır ve eğer açık bir pragma kullanırsam, uzmanlık geçişlidir. Sorum şu: oto- uzmanlaşma geçişli mi?INLINABLE

Özellikle, küçük bir örnek:

Main.hs:

import Data.Vector.Unboxed as U
import Foo

main =
    let y = Bar $ Qux $ U.replicate 11221184 0 :: Foo (Qux Int)
        (Bar (Qux ans)) = iterate (plus y) y !! 100
    in putStr $ show $ foldl1' (*) ans

Foo.hs:

module Foo (Qux(..), Foo(..), plus) where

import Data.Vector.Unboxed as U

newtype Qux r = Qux (Vector r)
-- GHC inlines `plus` if I remove the bangs or the Baz constructor
data Foo t = Bar !t
           | Baz !t

instance (Num r, Unbox r) => Num (Qux r) where
    {-# INLINABLE (+) #-}
    (Qux x) + (Qux y) = Qux $ U.zipWith (+) x y

{-# INLINABLE plus #-}
plus :: (Num t) => (Foo t) -> (Foo t) -> (Foo t)
plus (Bar v1) (Bar v2) = Bar $ v1 + v2

GHC çağrısı uzmanlaşmış plus, ama yok değil uzmanlaşmak (+)içinde Qux Numperformans öldürür örneği.

Ancak, açık bir pragma

{-# SPECIALIZE plus :: Foo (Qux Int) -> Foo (Qux Int) -> Foo (Qux Int) #-}

dokümanlar belirtildiği gibi geçişsel uzmanlaşma ile sonuçlanır , bu yüzden (+)uzmanlaşmıştır ve kod 30x daha hızlıdır (her ikisi de derlenmiştir -O2). Bu beklenen davranış mı? Sadece (+)açık bir pragma ile geçici olarak uzmanlaşmayı beklemeli miyim ?


GÜNCELLEME

7.8.2 için dokümanlar değişmedi ve davranış aynı, bu yüzden bu soru hala alakalı.


33
Cevabı bilmiyorum ama bununla ilgili gibi görünebilir: ghc.haskell.org/trac/ghc/ticket/5928 Muhtemelen 5928 ile ilgili olduğunu düşünüyorsanız yeni bir bilet açmaya veya bilgilerinizi buraya eklemeye değer
jberryman

6
@jberryman o bileti ve benim soruya arasında iki fark var gibi görünüyor: bir eşdeğer 1) bilet olarak plusyapıldı değil INLINABLE ve 2 olarak işaretlenen) simonpj bazı bilet koduyla oluyor inlining, ama belirtti çekirdek örneğim, işlevlerin hiçbirinin satır içi olmadığını gösterir (özellikle ikinci Fooyapıcıdan, aksi takdirde GHC satır içi öğelerinden kurtulamadım ).
crockeea

5
Ah tamam. plus (Bar v1) = \(Bar v2)-> Bar $ v1 + v2LHS'nin çağrı sitesinde tam olarak uygulanması için tanımladığınızda ne olur ? Satır içi olur ve uzmanlaşma devreye girer mi?
jberryman

3
@jberryman Komik sormalısın. Bu trac raporuna yol açan bu soru ile o yoldaydım . Başlangıçta plusözellikle bu bağlantılar nedeniyle tamamen başvurmak için çağrı vardı , ama aslında daha az uzmanlık aldım : çağrı plusda uzman değildi. Bunun için bir açıklamam yok, ama başka bir soru için bırakmayı ya da bunun bir cevabında çözüleceğini umuyordum.
crockeea

11
Gönderen ghc.haskell.org/trac/ghc/wiki/ReportABug : "Şüpheniz varsa, sadece hatayı bildirmek." Kendinizi kötü hissetmemelisiniz, özellikle de burada yeterince deneyimli haskeller soruya nasıl cevap vereceğini bilmediğinden. Bunun gibi test örnekleri, GHC geliştiricileri için muhtemelen gerçekten değerlidir. Her neyse, iyi şanslar! Bilet
gönderirseniz

Yanıtlar:


4

Kısa cevaplar:

Sorunun anladığım kadarıyla kilit noktaları şunlardır:

  • "Otomatik uzmanlaşma geçişli mi?"
  • Sadece (+) 'nın açık bir pragma ile geçici olarak uzmanlaşmasını beklemeli miyim?
  • (görünüşte amaçlanmıştır) Bu bir GHC hatası mı? Belgelerle tutarsız mı?

AFAIK, cevaplar Hayır, çoğunlukla evet ama başka yollar var ve Hayır.

Kod satır içi ve tür uygulama uzmanlığı, hız (yürütme süresi) ve kod boyutu arasında bir değiş tokuştur. Varsayılan seviye, kodu şişirmeden biraz hızlanır. Daha kapsamlı bir seviye seçmek SPECIALISEpragma yoluyla programcının takdirine bırakılmıştır .

Açıklama:

Optimize edici ayrıca, içe aktarılan her INLINABLE aşırı yüklenmiş fonksiyonunu dikkate alır ve M'de adlandırıldığı farklı tipler için uzmanlaşır.

Diyelim fki türü, abir tür sınıfı tarafından kısıtlanan bir tür değişkeni içeren bir işlevdir C a. Varsayılan olarak GHC uzmanlaşmış fbir tür uygulama (ikame ile ilgili aiçin tise) faynı modülde, (a) herhangi bir fonksiyon ya da (b) 'nin, kaynak kodunda bu tür uygulama ile denir, fişaretlenmiş INLINABLEbir başka modül, o zaman bu ithalat f den B. Bu durumda, otomatik uzmanlık geçişli değildir, sadece temas INLINABLEithal ve adı fonksiyonları kaynak kodu arasında A.

Örneğinizde, örneğini Numaşağıdaki gibi yeniden yazarsanız :

instance (Num r, Unbox r) => Num (Qux r) where
    (+) = quxAdd

quxAdd (Qux x) (Qux y) = Qux $ U.zipWith (+) x y
  • quxAddtarafından özel olarak içe aktarılmadı Main. Mainörneğinin sözlüğünü içe aktarır Num (Qux Int)ve bu sözlük quxAddiçin kayıtta bulunur (+). Ancak, sözlük içe aktarılsa da, sözlükte kullanılan içerikler aktarılmaz.
  • plusçağırmazsa quxAdd, (+)kayıt için depolanan işlevi örnek sözlüğünde kullanır Num t. Bu sözlük Mainderleyici tarafından çağrı sitesinde (in ) ayarlanır .
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.