2015-02-09 19 views
6

John Hughes'in Okları ile Programlama okuyorum. Gerçekten anlamadığım bir kod parçası var. Kod takip ediyor:Haskell Ok gecikme işlevi

import Control.Arrow.Operations 
import Control.Arrow 
import Control.Category 
import Prelude hiding ((.),id) 

newtype SF a b = SF {runSF :: [a] -> [b]} 

instance Category SF where 
     id = SF id 
     (.) (SF f) (SF g) = SF $ \x -> f (g x) 

(.*.) :: (a -> b) -> (c -> d) -> (a,c) -> (b,d) 
(.*.) f g (a,c) = (f a, g c) 


instance Arrow SF where 
     arr f = SF (map f) 
     first (SF f) = SF (uncurry zip . (f .*. id) . unzip) 

instance ArrowLoop SF where 
     loop (SF f) = SF $ \as -> let (bs,cs) = unzip (f (zip as (stream cs))) in bs 
             where stream ~(x:xs) = x:stream xs 
instance ArrowChoice SF where 
    left (SF f) = SF (\xs -> combine xs (f [y | Left y <- xs])) 
      where combine (Left y: xs) (z:zs) = Left z : combine xs zs 
       combine (Right y :xs) zs = Right y : combine xs zs 
       combine [] zs = [] 

instance ArrowCircuit SF where 
     delay x = SF (x:) 

ve ne anlayamıyorum ben sonuç sadece her birinin başında bir 0 ekleyerek olması gerektiğini düşündük

> runSF (mapA (delay 0)) [[1,2,3],[4,5],[6],[7,8],[9,10,11],[12,13,14,15]] 
[[0,0,0],[1,2],[4],[6,5],[7,8,3],[9,10,11,0]] 

olmasıdır sonra

mapA :: ArrowChoice arr => arr a b -> arr [a] [b] 

listcase []  = Left() 
listcase (x:xs) = Right (x,xs) 

mapA f = arr listcase >>> 
     arr (const []) ||| (f *** mapA f >>> arr (uncurry (:))) 

delay 0'dan beri liste SF (0:) olarak tanımlanmıştır.

Ve daha da garip,

diag :: (ArrowCircuit a , ArrowChoice a) => a [b] [b] 
diag = arr listcase >>> 
     arr (const []) ||| (arr id *** (diag >>> delay []) >>> arr (uncurry (:))) 

runSF diag [[1,2,3],[4,5,6],[7,8,9],[10,11,12]] 
[[1],[4,2],[7,5,3],[10,8,6]] 

Ben diag ve mapA (delay 0) yaptığını görebilirsiniz, ama oldukça delay kullanarak hesaplama işlemini anlayamıyorum. Birisi yardım edebilir mi? Teşekkürler.

+0

Bunlardan herhangi birini anlamak için gerçekten de "ArrowChoice" ve özellikle de kodda yer almadığınız "ArrowChoice SF" örneğini anlamanız gerekir. mapA, sadece bir "ArrowChoice" örneğine sahip olan oklar için tanımlanmıştır, mapA :: ArrowChoice a => a b c -> a [b] [c] '. Diag’daki '|||' 'Arrow' için' Arrow’in 'ArrowChoice' analogudur. – Cirdec

+0

ArrowChoice'i ihmal ettiğim için özür dilerim. Yorumunuza yardımcı olur. Thanks ~ –

cevap

4

Oklar hakkında düşünmenin bir yolu, bir çeşit fabrika şemasıdır. SF sadece (->) ise haklısınız. Git ve dene; Eğer almalısınız:

Prelude Control.Arrow> mapA (0 :) [[1,2,3],[4,5],[6],[7,8],[9,10,11],[12,13,14,15]] 
[[0,1,2,3],[0,4,5],[0,6],[0,7,8],[0,9,10,11],[0,12,13,14,15]] 

Ancak fabrikada makineler sadece kendi dönüştürülmüş girdi, bu arada -> eserler üzerinde göndermekten daha işler daha karmaşık yapabilirsiniz. Sizin SF makineleri bir a "almak" ve b "söndürmek", ancak bunları a s akışı beslemek sağlayan bir işleve [a] -> [b] tarafından desteklenen konum ve daha sonra -> yapar daha sofistike bir şeyler yapabiliriz.

delay 0 makine, bir sayı akışı alır ve bu şekilde düşünmek istiyorsanız, 0'a kadar hazırlar, kolay peasy, orijinal akışı bir "zaman adımı" ile "geciktirir".

Benzer şekilde, a1 &&& a2 makinesi, giriş akışını alt makinelerin her ikisine de beslemek zorunda kalacak ve her ikisi de değerlere sahip olduklarında, bunları birlikte "zip" edebilir. Sonuçta, [b] -> [c] ve [b] -> [d] alt makineleri [b] -> [(c, d)] üretir.

a1 ||| a2 makine daha zordur: benzer alt makineleri [b] -> [d] ve [c] -> [d] alır ve [Either b c] -> [d] oluşturmak için bunları kullanır. Bu tamamen kendini açıklayıcı görünüyorsa, tekrar bakın! Either [b] [c], hangi biz tamamen basit olurdu (ve hangi ile -> fırsatlar yukarıda), daha ziyade [Either b c] var. Burada yapılacak ne için bariz bir çözümdür:

  1. tut sol alt liste, sol makine
  2. Kepçe sağ alt liste için bunu sağlamak doğru makine
  3. bunu sağlamak Ortaya çıkan [d] s'yi karmaşık karışık ara sıra düzende iade edin.

Hangi sipariş?En kolay yol orijinal listeye geri dönmek ve bir Sol gördüğünüzde sol makinenin listesinden d verin; Bir Sağ gördüğünüzde, doğru listeden bir d verin. Bu arka plan tümünü içeren

, biz mapA geliyor:

mapA f = arr listcase >>> arr (const []) ||| (f *** mapA f >>> arr (uncurry (:))) 

SF için, listcase listelerin gelen akışı alacak ve bu akışı boş olmasına bağlı, Either() (x, [x]) akışı üretirler. Listeden ilk geçişte, runSF'unuzdaki girişlerin hiçbiri boş değildir, bu nedenle her liste bir doğru değer yayan bir Right dalıdır.

Bu yüzden [1, 4, 6, ...] ve [[2,3], [5], [], ...]: [1, 4, 6, ...] ve [[2,3], [5], [], ...] iki liste halinde bölünmüş [Right (1, [2,3]), Right (4, [5]), Right (6, []), ...] var.

İlk liste, gecikme işlevine beslenir, böylece 0 ile hazırlanır. İkinci liste, tekrarlı olarak mapA f'a beslenir, böylece [2, 5] önekler de geciktirilir; ve bunun gibi.

Onları bir araya getirdiğinizde, listelerdeki her bir yuvalama düzeyinin gecikiyor olduğunu, böylece ilk yayılan listenin [0, 0, 0] ve ikincisinin [1, 2] olduğunu göreceksiniz.

+0

Cevabınız çok yardımcı oldu. Tekrar tür sınıflarının tanımlarına bakacağım! Çok teşekkürler –