2017-12-09 92 views
6

Cloud Haskell ile oynuyordum. in the hackage documentation fark ettim, bir çeşit uygulama arayüzü var. Ama özellikle ben bulmak veya aşağıdaki imzası ile bir işlev closurePure yazmaya çalışıyorum:Cloud Haskell - Kapanışlar için "saf" nasıl yazılır?

closurePure :: (Typeable a, Binary a) => a -> Closure a 

Bu temelde saf bir kısıtlı versiyonu. Closure veri türü kendisi soyut iken

aşağıdaki closure sağlanan:

closure :: Static (ByteString -> a) -> ByteString -> Closure a 

Bu yüzden bu kadar alabilirsiniz:

closurePure :: (Typeable a, Binary a) => a -> Closure a 
closurePure x = closure ??? (encode x) 

sorun ??? ler nerede koymak budur.

myDecode :: (Typeable a, Binary a) => Static (ByteString -> a) 
myDecode = staticPtr (static decode) 

Ama GHC docs on static pointers okunması üzerine

, show örnek kısıtlı fonksiyon Typeable örneği olmadığı için bir kısıtlaması olamaz bana önerdi:

Benim ilk girişimi izleyen oldu. Bu yüzden etrafında işi denedi Dict kullanarak önerdi:

myDecode :: Typeable a => Static (Dict (Binary a) -> ByteString -> a) 
myDecode = staticPtr (static (\Dict -> decode)) 

Ama şimdi yukarıda closure işlevi uymuyor türü yanlış var.

closurePure veya benzeri bir şey yazmak için var mı (veya Cloud Haskell belgelerinde bunu özledim)? binary düz tiplerini Closure s ye yükseltmek, verilen uygulama arabirimini kullanmak için çok önemli görünüyor, ancak nasıl yapılacağını bilemiyorum. Bunu yapabilirim

Not: iyi çalışıyor ama temelde her Binary örneğin bir örneğini tekrarlamamı gerektirir

class StaticDecode a where 
    staticPtrDecode :: StaticPtr (ByteString -> a) 

instance StaticDecode Int where 
    staticPtrDecode = static Data.Binary.decode 

instance StaticDecode Float where 
    staticPtrDecode = static Data.Binary.decode 

instance StaticDecode Integer where 
    staticPtrDecode = static Data.Binary.decode 

-- More instances etc... 

myPure :: forall a. (Typeable a, StaticDecode a, Binary a) => a -> Closure a 
myPure x = closure (staticPtr staticPtrDecode) (encode x) 

. Dağınık görünüyor ve başka bir yol tercih ederim.

+0

Eminim 'myDecode = staticPtr (statik kod çözme)' çalışmıyor mu? Bana öyle geliyor ki, '' StaticDecode '' kısıtlaması için 'Binary' sınırlamasını işlemiş oldunuz, ancak çalıştığınızı söylüyorsunuz. – 4castle

+0

Üzgünüz, son işlev 'myDecode' değil' myPure' olarak adlandırılmalıdır. Umarım bu daha mantıklıdır. Ama bir anlamda haklısın, ama StaticDecode 'örneğinin içinde durağan (hangi işe yarar) çağıracağımı ancak ilk olarak İkili örnek üzerinden kod çözdüğümde, statik uygulandığında başarısız olur. Tahmin ediyorum (bu tamamen bir tahmindir), her StatikDecode örneği benzersiz bir statik işaretçi üretir, bu yüzden bu iyi çalışır. – Clinton

cevap

4

, Closure bir applicative- gibi yapısını, arayüz ve distributed-closure uygulanmasında hem de daha açık yapılmış bir gerçeği vardır. Oldukça uygulanabilir değil, çünkü pure numaralı davada, argümanın bir şekilde serileştirilmesi gereken ek bir kısıtlamaya sahibiz.

Aslında, daha güçlü bir kısıtlamamız var. Argümanın sadece seri hale getirilmesi gerekmiyor, aynı zamanda kısıtlamanın da seri hale getirilmesi gerekiyor. Doğrudan işlevleri serileştirmek zor olduğu gibi, kısıtlamaları serileştirmenin zor olduğunu hayal edebilirsiniz. Ancak işlevler gibi, hile, bir statik işaretçi varsa, statik işaretçiyi kısıtlamalarına seri hale getirmektir. Böyle bir işaretçinin var olduğunu nasıl bilebiliriz? Bir kısıtlama verilen bize pointer adını veren tek yöntem ile bir tür sınıf uygulamasına olabilir:

class GimmeStaticPtr c where 
    gimmeStaticPtr :: StaticPtr (Dict c) 

burada devam hafif teknik numara yok. StaticPtr için tür indeksi tür * tür, bir kısıtlama ise Constraint tür. Bu nedenle, * türündeki tüm veri türleri gibi bir veri türüne (Dict) bir kısıtlama sarmaktan oluşan constraints kitaplığından bir numara tekrar kullanırız. İlişkilendirilmiş bir GimmeStaticPtr örneğine sahip olan kısıtlamalara statik kısıtlamalar denir.

Genel olarak, daha fazla statik kısıtlama elde etmek için statik kısıtlamalar oluşturmak bazen yararlıdır. StaticPtr, bileşik olabilir, ancak Closure olduğunu.yani ne distributed-closure aslında yok biz

class GimmeClosure c where 
    gimmeClosure :: Closure (Dict c) 

Şimdi yaptığın benzer bir şekilde closurePure tanımlayabilirsiniz diyeceğiz ki benzer bir sınıfını tanımlamak geçerli: harika olurdu

closurePure :: (Typeable a, GimmeClosure (Binary a)) => a -> Closure a 

yılında ise Gelecekte, derleyici, gerektiğinde statik işaretçiler oluşturarak, anında GimmeClosure kısıtlamalarını çözebilir. Ama şimdilik, en yakın olan şey Template Haskell. dağıtılmış kapatma, Cls sınıfı için tanım alanında GimmeClosure (Cls a) kısıtlamalarını otomatikleştirmek için bir modül sağlar. Bakınız withStatichere. Bu arada, Edsko de Vries, dağıtılmış kapanma ve burada yer alan fikirler hakkında bir great talk vermiştir.

2

Ne istediğini düşünmek için biraz zaman alalım. Tiplerin, sözlük geçişi için temelde kısa olduğunu hatırlayın. O yüzden tekrar yazalım: Biz açıkça neler olduğunu görebiliriz görebilirsiniz Şimdi

closurePure bdict = closure (staticPtr (static (bdDecode bdict))) . bdEncode bdict 

:

closurePure :: (Typeable a) => BinaryDict a -> a -> Closure a 

girişiminiz geçerli:

data BinaryDict a = BinaryDict 
    { bdEncode :: a -> ByteString 
    , bdDecode :: ByteString -> a 
    } 

Artık bir işlevi yazmak isteyen static 'in argümanı kapalı olamaz. Eğer kullanıcı verisinden BinaryDict s willy nilly yaratılmışsa, bu fonksiyon imkansız olacaktır. Bunun yerine gerekir:

olduğunu
closurePure :: (Typeable a) => Static (BinaryDict a) -> a -> Closure a 

, biz statik işaretçi tabloda gerekli Binary örnekleri için girişleri gerekir. Dolayısıyla numaralandırma çözümünüz ve neden böyle bir çözümün gerekli olduğundan şüpheleniyorum.Ayrıca, sonsuz sayıda çok örnek olduğu için otomatik olarak numaranızı da numaralandırmasını bekleyemeyiz.

Bana göre aptalca görünüyor, çünkü örnekler sadece otomatik olarak statik olmak isteyeceğiniz şeyler gibi görünüyor. Onlar doğa tarafından statiktirler (bu ne, reflection? Seni duyamıyorum). Bu, en azından dağıtılmış Haskell gazetelerinde (en azından onları okumamıştım) en azından aydınlatılmıştı.

Bu problemi, genel olarak her sınıfın her örneğini somut olarak sıralayan bir sınıf oluşturarak çözebiliriz (déjà vu?).

class c => StaticConstraint c where 
    staticConstraint :: StaticPtr (Dict c) 
instance StaticConstraint (Show Int) where 
    staticConstraint = static Dict 
-- a handful more lines... 

Biraz daha ciddi, gerçekten (Seni suçlamıyorum), en az bir çağrı kuralı ile değilmişsin numaralandırmak istemiyorsanız:

closurePure :: (Typeable a, Binary a) => StaticPtr (ByteString -> a) -> a -> Closure a 
closurePure decodePtr = closure (staticPtr decodePtr) . encode 

someClosure :: Closure Int 
someClosure = closurePure (static decode) 42 

Bu saçmalık static bir işlevden ziyade bir "sözdizimsel form" olduğu için gereklidir - bunu belirterek, Int için Binary örneğinin aslında statik işaretçi tablosunda oluşturulup kaydedilmesi gerektiğini belirtiriz.

Eğer {-# LANGUAGE CPP #-} ve
-- PURE :: (Binary a, Typeable a) => a -> Closure a, I promise 
#define PURE (closurePure (static decode)) 

someClosure :: Closure Int 
someClosure = PURE 42 

Belki bir gün Haskell için bir sonraki adım ve mezun alacak sağlayabilir arsız hissediyorsanız zaman içinde test bu kibirli tip hataları söylenip yerine selefine Segmentation fault (core dumped). Haklısın