2016-04-10 17 views
2

Monad'ları öğrendim ve Control.Monad'da pek çok işlevi uygulamaya çalışıyorum. Sadece ap'a ulaştım, ancak çalışamam. almostAp :: Monad m => m (a -> b) -> m a -> m (m b) işlevini yaptım ve yaptığım başka bir işlevle oluşturmaya çalıştım, flatten :: Monad m => m (m b) -> m b. Ben ap = flatten . almostAp kullanmaya çalıştığınızda sorun (flatten .) GHCi göre Monad m => (a -> m (m b)) -> a -> m b tip vardır, benMonadic işlevler oluşturmaya çalışırken hata

Occurs check: cannot construct the infinite type: m ~ (->) (m a) 
    Expected type: m (a -> b) -> m a -> m a -> m b 
    Actual type: m (a -> b) -> m a -> m (m b) 
In the second argument of ‘(.)’, namely ‘almostAp’ 
In the expression: (flatten . almostAp)` 

olsun Ama, neden böyle oluyor? İşte

fonksiyon tanımları vardır (ben =<< onları temizlemek biliyorum ve funktor kanunları):

almostAp :: Monad m => m (a -> b) -> m a -> m (m b) 
almostAp = (flip (\x -> fmap ($x))) . (fmap (flip (>>=))) . (fmap (return .)) 

flatten :: Monad m => m (m a) -> m a 
flatten = (>>= id) 
+4

Kodunuzu okumak zor bir hale getiren noktadan arınmış bir stile sahip görünüyorsunuz (ve yazmayı da çok zor biliyorum!) "Bağlama" veya "Yapma" dan korkma notasyonu. –

+2

"Bırakın noktadan arındırılmış stil: sadece" kullan "anlamında mantıklı ve" daha iyi "yapacaksın" – Cactus

cevap

5

Bir tek argüman oluşturmak için çalışıyorlardı çünkü senin tipin hatasını elde edildi işlevi flatten (iki argümanlı işlevi işleviyle, genellikle join adı ile gider). (.) :: (b -> c) -> (a -> b) -> (a -> c), sağdaki işlevin bir argüman işlevi olduğu zaman içindir. Ne yazık ki hata mesajı çok yardımcı olmadı.

ghci> let ap = ((.).(.)) flatten almostAp 
ghci> :t ap 
ap :: Monad m => m (a -> b) -> m a -> m b 

Ama apdo gösterimi ile çok daha basit bir biçimde gerçekleştirilebilir: istediğini yapar (veya "göğüsler" " -dot- noktanokta" telaffuz)

(.).(.). Versiyonunuzun bundan daha kolay anlaşılması mı?

ap mf mx = do 
    f <- mf 
    x <- mx 
    return (f x) 

do notasyonu >>= için sadece sözdizimsel şeker olduğunu. (Ben çok do versiyonunu tercih rağmen) İşte o olmadan nasıl göründüğü:

ap mf mx = mf >>= \f -> fmap f mx 
+2

"(.). (.)" Aklımda "baykuş gözleri" Daha fazlası ... aile dostu görünüyor. – dfeuer

3

Ama (flatten .) GHCi göre Monad m => (a -> m (m b)) -> a -> m b tipi vardır, neden böyle oluyor?

Gerçekten de öyle. Düşünün:

flatten :: Monad m => m (m a) -> m a 

almostAp :: Monad m => m (a -> b) -> m a -> m (m b) 

Böylece (flatten .) türüdür:

flatten  :: Monad m => m (m a) -> m a -- renaming a to b 
          |  | | | 
          ------- --- 
          |  | 
(.)   ::    (b -> c) -> (a -> b) -> a -> c 
                |    | 
                -------   --- 
                |  |   | | 
(flatten .) :: Monad m =>     (a -> m (m b)) -> a -> m b 

Ancak tipleri uyumsuz çünkü almostAp için (flatten .) uygulayamazsınız:

almostAp :: Monad m => m (a -> b) -> m a -> m (m b) 
          |  | |   | 
          ---------- -------------- 
           |    | 
           |   ------- 
           |   |  | 
(flatten .) :: Monad m => ( a  ->  m (m b)) -> a -> m b 

Bunu beklenen :

almostAp :: Monad m => m (a -> b) -> m a -> m (m b) 
          |    | |  | 
          ----------------- ------- 
            |    | 
            |   ------- 
            |   |  | 
(flatten .) :: Monad m => (  a   -> m (m b)) -> a -> m b 

Ancak, currying çalışma şekli bu değil. a -> b -> c tipinin bir işlevi a -> (b -> c) ve (a -> b) -> c anlamına gelir.İlk işlev a -> (b -> c) iki argüman , a ve b alır ve c değerini döndürür. İkinci işlev (a -> b) -> c bir bağımsız değişken alır a -> b ve c döndürür.

Peki, flatten ve almostAp'u nasıl oluşturuyorsunuz?

(.) :: (b -> c) -> (a -> b) -> a -> c 
     |  | |  | 
     -------- -------- 
      |   | 
     flatten  +-- almostAp can't be used because it needs two arguments 
         -- but (.) only gives it one argument (the `a` in a -> b) 

Onları oluşturmak için özel bir kompozisyon operatörü gerekir:: Artık

(.:) :: (c -> d) -> (a -> b -> c) -> a -> b -> d 
     |  | |   | 
     -------- ------------- 
      |    | 
     flatten  almostAp 

(.:) f g x y = f (g x y) 

, biz sadece flatten .: almostAp yazabilirsiniz Sen almostAp iki argüman gerektirir çünkü normal bir fonksiyon kompozisyonu kullanılarak bunu yapamaz. Yazmanın başka bir yolu (flatten .) . almostAp olacaktır. Bunun nedeni (.:) = (.) . (.). Daha fazla detay için aşağıdaki okuyun:

What does (f .) . g mean in Haskell?


Aslında tip a -> (b -> c) bir fonksiyonu sadece bir argüman a alır ve ikinci argüman b alır ve c döndüren başka işlevi b -> c döndürür.

İlgili konular