2011-08-11 17 views
10

Temelde bir c-dizi float olan bir tür Image var. , map :: (Float -> Float) -> Image -> Image veya zipWith :: (Float -> Float -> Float) -> Image -> Image -> Image gibi işlevler oluşturmak kolaydır. Bununla birlikte, ((+) <$> image1 <*> image2) veya ((\x y z -> (x+y)/z) <$> i1 <*> i2 <*> i3) gibi daha esnek piksel seviyesi manipülasyonlarına izin vererek, bu işlevlerin üzerine uygulamalı bir örnek gibi görünen bir şey sağlamanın da mümkün olacağını hissediyorum. Ancak, naif yaklaşım başarısızdır, çünkü görüntü tipi, şamandıralardan başka şeyler içeremez, bu nedenle fmap'u uygulamak imkansız hale gelir.Bir functor olmadan uygulama

Bu nasıl uygulanabilir?

+3

Neden bir Resim yüzen dışındaki şeyi içermesini izin vermedi? Tabii, ekranınız :: Görüntü Float -> IO() 'sadece float ile görüntü alabiliyordu, ancak 'map' gibi diğer fonksiyonlar için önemli değil. –

+1

Görüntü türü, dönüşümler yapmak için çok fazla zaman harcamadan c işlevlerine geçirilmesi gereken bir c dizisidir. Ayrıca, fonksiyonlar gibi şeyleri tutabilseydi, “saf” olarak adlandırdıktan sonra birkaç milyon kısmi olarak değerlendirilen fonksiyona sahip olmanın, oldukça çirkin bir performans olacağını düşünürdüm. (Görüntülerin boyutlarını bilemediğinden, işlevlerin bir görüntüsünün olmasıyla 'pure' da sorunludur.) – aleator

+0

türünüzü "type Image = CArray Float" gibi tanımlayabilir ve fritip ile CArray için bir Functor örneği oluşturabilirsiniz. –

cevap

15

Yorumları okuyarak, buradaki halının buranın altında olduğundan biraz endişeliyim. Boyut uyuşmazlığı olduğunda mantıklı bir davranış var mı?

Bu sırada, aşağıdaki satırlarda mantıklı bir şekilde yapabileceğiniz bir şey olabilir. Dizileriniz polimorfik yapmak için kolay olmasa bile, bunun gibi bir Applicative örneğini oluşturabilirsiniz.

data ArrayLike x = MkAL {sizeOf :: Int, eltOf :: Int -> x} 

instance Applicative ArrayLike where 
    pure x     = MkAL maxBound (pure x) 
    MkAL i f <*> MkAL j g = MkAL (min i j) (f <*> g) 

(Meraklılar I (maxBound, min) Monoid tarafından uyarılan bununla (Int ->) uygulamalı ürününü geçtiniz dikkat edecektir.)

Temiz yazışmalar yapabilir misiniz

imAL :: Image -> ArrayLike Float 
alIm :: ArrayLike Float -> Image 

projeksiyon ve tablolama ile? Eğer öyleyse, böyle bir kod yazabilirsiniz. Daha sonra, aşırı yüklenmiş bir operatörü olarak

imapp :: (Float -> ... -> Float) -> (Image -> ... -> Image) 

o deseni tamamlamayı istiyorsanız

alIm $ (f <$> imAL a1 <*> ... <*> imAL an) 

Ayrıca, typeclass programlamada standart bir egzersiz! (Daha fazla ipucuna ihtiyacınız varsa sorun.)

Buradaki en önemli nokta, ambalajlama stratejisinin, üst yapı üzerinde fonksiyonel üstyapı koymak için dizi yapılarınızla birlikte maymun yapmanıza gerek olmadığı anlamına geliyor.

+0

Harika! Tam olarak aradığım şey. Bunu neden görmediğimi anlayamıyorum. N varyasyon işlevleri için N örnekleri oluşturmayı mı yoksa yazı tipi yorumuna göre daha zeki bir şey mi kastettiniz? – aleator

+2

Sadece iki örneğe gereksiniminiz vardır: aritlik 0 için temel bir durum (ya da çıktının boyutunu sınırlamak için bir dizi girişine ihtiyacınız varsa 1) ve bir adım vakası. Bekle (üzüntü kodu yorumlarda azdır) ... 'sınıf NAry ff fi | ff -> fi, fi -> ff Burada {naryHelp :: (ArrayLike (Float -> ff)) -> (Resim -> fi); nary :: (Float -> ff) -> (Resim -> fi); nary = naryYardım. saf} örnek NAry Float Image nerede {naryHelp f i = alIm $ f <*> imAL i}; Örneğin nary ff fi => nary (Float -> ff) (Görüntü -> fi) {naryHelp fi = naryHelp (<*> minimal- f i)} ' – pigworker

+1

Sadece ek bir düşünce burada:' ArrayLike' oldukça repa gecikmeli diziler gibi temelde , sağ? Atleast 'al'm'de paralel hesaplamaları kolayca nasıl ekleyebildiğimi ve' güç '' imAl olarak nasıl tanımlayabildiğimi görmek için yalın bir şeydir. alIm'. – aleator

6

Görüntüdeki piksellerle işlem yapmayı nasıl beklersiniz? Yani, ((+) <$> image1 <*> image2) için, Haskell'deki tüm işlemleri gerçekleştirmek ve yeni bir sonuç görüntüsü oluşturmak mı istiyorsunuz, yoksa tüm işlemleri yapmak için C işlevlerini çağırmanız mı gerekir?

Bu eskiyse, domuz işçilerinin yanıtı benim alacağım yaklaşım.

Bunun yerine, tüm görüntü işlemlerinin C ile ele alınması gerekiyor, bu işlemleri göstermek için küçük bir DSL oluşturmaya ne dersiniz? Eğer & sürekli etki alanını sonsuz için Float gelen "piksel" türü genellemek ve sonlu & ayrık alanı (diziler) uzanmaktadır eğer

+0

görüntü ne Peşinde olduğum Haskell basit piksel seviyesi operasyonları yapmak için bir yoldur C. tarafından çoğunlukla manipüle olacaktır - atan2 gibi basit bir işlev eklemek için c'ye tüm yol düşmesi bıktırıcı olur. – aleator

6

Sen çok daha kompozisyon Image türü alırsınız. Bu genelleştirmelerin bir gösterimi olarak, Functional Images numaralı kağıda ve ilgili (sonlu örnekleme) example images galerisine bakın. Sonuç olarak, Monoid, Functor, Applicative, Monad ve Comonad örneklerini olsun. Kağıt Denotational design with type class morphisms tarif edildiği gibi Ayrıca, bu örneklerin anlamları tamamen semantik tip sınıfı Morfizm ilkesini, tatmin edici fonksiyonlar için karşılık gelen örnekleri tarafından belirlenir. Bu makalenin 13.2. Bölümü görüntüleri kısaca tanımlar.

İlgili konular