2013-11-21 16 views
6

Haskell fonksiyonunu daha yüksek mertebeden bir lambda hesaplaması kodlamasında kaldırmak istiyorum. Bu, Oleg'in Typed Tagless Final kodlamasından neredeyse aynı şekilde alınmıştır.Genelleştirilmiş çok parametreli fonksiyon kaldırma için tipik numaralar

class Lam r where 
    emb :: a -> r a 
    (^) :: r (r a -> r a) -> (r a -> r a) 
    lam :: (r a -> r a) -> r (r a -> r a) 

instance Lam Identity where 
    emb = Identity 
    f^x = f >>= ($ x) 
    lam f = return (f . return =<<) -- call-by-value 

eval = runIdentity 

Ben emb kullanarak Lam içine keyfi Haskell türlerini gömebilirsiniz ama sonra uygulama için (^) kullanamazsınız. Ayrıca, kaldırılmış fonksiyonlar tembel davranırdı. Bunun yerine, uygulamayı uygulamaya göre kaldırmak zorundayım.

emb1 :: (Applicative r, Lam r) 
    => (a -> b) -> r (r a -> r b) 
emb1 f = lam $ \ra -> f <$> ra 

emb2 :: (Applicative r, Lam r) 
    => (a -> b -> c) -> r (r a -> r (r b -> r c)) 
emb2 f = lam $ \ra -> lam $ \rb -> f <$> ra <*> rb 

emb3 :: (Applicative r, Lam r) 
    => (a -> b -> c -> d) 
    -> r (r a -> r (r b -> r (r c -> r d))) 
emb3 f = lam $ \ra -> lam $ \rb -> lam $ \rc -> f <$> ra <*> rb <*> rc 

>>> eval $ emb2 (+)^emb 1^emb 2 
3 

Bu bir çok boilerplate var. Herhangi bir işlev için çalışacak genel bir kaldırma işlevi oluşturmak istiyorum. Printf'un PrintfType veya fixed-vector'ların Cont türlerine benzer bir şey kullanmanın mümkün olabileceğini hissediyorum. Ben türü işlevleri

type family Low h  o 
type instance Low ()  o = o 
type instance Low (a, h) o = a -> Low h o 

type family Lift r h  o 
type instance Lift r()  o = o 
type instance Lift r (a, h) o = r a -> r (Lift r h o) 

class Emb r h o where 
    embed :: Low h o -> r (Lift r h o) 

instance (Lam r) => Emb r() o where 
    embed = emb 

instance (Lam r, Applicative r, Emb r h o) => Emb r (a, h) o where 
    embed = ? 

kullanarak istediğiniz Ama çok genellikle nedeniyle birebirlik sorunları nedeniyle, bu yöntemle takılıp neler belirtebilirsiniz. Yeni tip sarmalayıcılar ve kapsamlı değişkenler arasında gerçekten iğrenç bir kombinasyonla enjeksiyonu çözebildim, ancak aslında hiçbir zaman yazılmadı.

Bu Haskell'de ifade etmek mümkün mü?

+0

Cevabı bilmiyorum, ancak bir sonraki bağlantı yararlı olabilir: http://hackage.haskell.org/package/layers-0.1/docs/Documentation-Layers-Overview.html – wit

cevap

3

Ordinary and one-pass CPS transformation etiketsiz final stilinde bakmak isteyebilirsiniz. Hile, nesne türünde Ok türünü genelleştirmektir. Haskell'in tip kurucusunu -> sık sık kullandığımız, nesne dilinde (gömülecek) işlev tipleri için bir tesadüf ve kolaylıktır. Genellikle, nesne fonksiyonları Haskell işlevlerini basitçe eşleştirmez. değinilen makalede kod Şimdi belirli bir repr bağlı Arr yorumlamak için yeterli özgürlüğe sahip ESymantics

-- How to interpret arrows and other types 
type family Arr (repr :: * -> *) (a :: *) (b :: *) :: * 

class ESymantics repr where 
    int :: Int -> repr Int 
    add :: repr Int -> repr Int -> repr Int 

    lam :: (repr a -> repr b) -> repr (Arr repr a b) 
    app :: repr (Arr repr a b) -> repr a -> repr b 

içerir. Başvurulan makale, CPS örneği için Arr'ı yorumluyor.

Düzenleme: yılında çıkıyor biz aynı etkiyi elde edebilirsiniz - bir nesne dili için ok anlamını yeniden tanımlamak - (kendi birebirlik sorunları ile) ve ESemantics olmadan Varış türünü tanıtan olmadan. Yukarıdaki bağlantı, sıradan ve tek geçişli CPS dönüşümlerine, standart Semantikleri kullanarak ve işlev tipi kurucunun anlamını yeniden yorumlayarak yeni kodu gösterir. Artık herhangi bir enjeksiyon problemi yok.

+0

Dün gece buna baktım ve gerçekten bilgilendirici olduğunu buldum, ama tip aile non-injectivity ile çalışmak için en iyi nasıl anlamaya ihtiyacım var. Ben genellikle, Haskell oklarının nesne dili temsilinde kalması beklentilerinin çok büyük olduğunu düşünüyorum. Cevap verdiğin için teşekkürler! –