2015-08-17 36 views
6

Bazı Haskell öğreniyorum ve bu Monad'larla ilgili bir sorunum var, onlar hakkında anladım ve neyle ilgili olduklarını biliyorum ama bu özel durumda bazı sorunlarım var.Haskell: Monads of monad

varsayarsak,

: LYAH üzerinde öğrenme ederken ben (satranç oyunundan) bir şövalye ile 3 hareketlerinde Sizin alabilir pozisyonları hesaplamak ilgiliydi bir egzersizi koştu, böyle liste monad kullanılan
type KnightPos = (Int,Int) 

moveKnight :: KnightPos -> [KnightPos] 
moveKnight (c,r) = do 
    (c',r') <- [(c+2,r-1),(c+2,r+1),(c-2,r-1),(c-2,r+1) 
       ,(c+1,r-2),(c+1,r+2),(c-1,r-2),(c-1,r+2) 
       ] 
    guard (c' `elem` [1..8] && r' `elem` [1..8]) 
    return (c',r') 

Bu, eğer bu işleve konumumu verirsem, gelecekteki muhtemel konumları hesaplayabilir, ancak şimdi onun içindeki Yazar Monad'ı uygulamaya çalışıyorum, böylece bu noktaya nasıl ulaşabildim? Ben o ben fonksiyonunu başka bir zaman çalıştırmak için bir KnightRoute bir KnightPos açamadı bir KnightPos ancak kullanarak monads verirsen Yani Çalışıyor Bu işlevi,

varsayarsak,

type KnightRoute = Writer [KnightPos] KnightPos 

moveKnight' :: KnightPos -> [KnightRoute] 
moveKnight' (c,r) = do 
    (c',r') <- [(c+2,r-1),(c+2,r+1),(c-2,r-1),(c-2,r+1) 
       ,(c+1,r-2),(c+1,r+2),(c-1,r-2),(c-1,r+2) 
       ] 
    guard (c' `elem` [1..8] && r' `elem` [1..8]) 
    return $ toKr (c',r') (c,r) 
where toKr pos oldpos = Writer (pos,[oldpos]) 

yaptı ...

*Main> let a = moveKnight' (2,4) !! 0 
*Main> runWriter a 
((4,3),[(2,4)]) 
*Main> a >>= moveKnight' 

<interactive>:4:7: 
Couldn't match type ‘[]’ with ‘Writer [KnightPos]’ 
Expected type: KnightPos -> Writer [KnightPos] KnightRoute 
    Actual type: KnightPos -> [KnightRoute] 
In the second argument of ‘(>>=)’, namely ‘moveKnight'’ 
In the expression: a >>= moveKnight' 

Ben niye işe yaramadığı, benim Writer den (4,3) ayıklamak ama sonra KnightPos' bunu vermek anlıyoruz. Ancak KnightPos', KnightRoute'un bir listesini döndürür; burada bir KnightRoute'a ihtiyacım var, bu bir mantık hatasıdır, ancak nasıl yapılacağını bilmiyorum. Bunu Monad'larla yapmanın basit bir yolu var mı? İki monads ” ait “ kombinasyonu Bu tür Haskell son derece yaygın bir şeydir

+0

Not kullanarak o ':

asList :: (Int -> a) -> [a] asList f = map f [1..] 

Sonra a' için tüm yolların listesi

a's :: [KnightRoute] a's = asList a' 

Her şeyi birleştirme olduğunu Yazarın veya WriterT'in log-monoid olarak listelenmesi oldukça verimsizdir (ikinci dereceden zaman), çünkü sağa eklemeye devam edersiniz. Fark listeleri veya daha uzmanlaşmış konteynerler daha iyi bir bahis. – leftaroundabout

+0

Son zamanlarda bunu öğrendim, aslında Fark listesini kullanmak için daha verimli görünüyor.Her halükarda, daha hızlı bir şey olmadığı için Fark Listelerini her zaman log-monoids olarak kullanmalıyız. –

cevap

6

peşin :) tarafından

teşekkürler. Neyse ki, dil bu konuda güzel bir şekilde soyutlayabileceğimiz kadar esnektir.

İstediğiniz şeyi matematiksel olarak söyleyin, bir composition of two functors. Bu yeni tip yerine, bu genellikle transformatörleri konseptiyle ifade edilir: Writer monad'ını doğrudan kullanmak yerine, WriterT monad trafosunu kullanırsınız. WriterT w [] a[Writer w a] olarak basically the same, bu nedenle sizin durumda kullanabilirsiniz:

import Control.Monad.Trans.Class 
import Control.Monad.Trans.Writer 

moveKnight'' :: KnightPos -> WriterT [] [KnightPos] KnightPos 
moveKnight'' (c,r) = do 
    (c',r') <- lift [(c+2,r-1),(c+2,r+1),(c-2,r-1),(c-2,r+1) 
        ,(c+1,r-2),(c+1,r+2),(c-1,r-2),(c-1,r+2) 
        ] 
    guard (c' `elem` [1..8] && r' `elem` [1..8]) 
    tell [(c,r)] 
    return (c',r') 
+0

Teşekkür ederim çalışıyor! Monad transformatörlerine daha çok bakacağım. Onları bilmiyordum :) –

1

Sen

İşte i
a' :: Int -> KnightRoute 
a' i = a >>= \p -> moveKnight' p !! i 

yazarların iç listesini ortadan kaldırmak için kullanılır yazabilir. Ve, tembellik sayesinde, [a] içine Int -> a açabilirsiniz:

moveKnight :: KnightRoute -> [KnightRoute] 
moveKnight k = map (\i -> k >>= \p -> moveKnight' p !! i) [1..] 
+0

Hey, cevabınız için çok teşekkürler. Kusura bakma, açıkça anlamadım ... sahte kod yazdın mı? Monad olarak kullandığınız, ancak asla tanımlamayacağınız için, sizin için "a" isimli değişkenin ne olduğunu göremiyorum. Belki de yanıldım :) –

+0

@Bryce Tichit, rica ederim. “A” sizin “a” kelimenizdir: “a = moveKnight” (2,4)! 0 ', yani sadece bir örnek. Gerçek işlevi 'moveKnight', sağladığınız KnightRoute için çalışır. – user3237465

+0

Şimdi anladım çünkü tembelliği kullandığı için bunu yapmanın oldukça akıllı bir yolu, bunun ne kadar güçlü olduğunu gösteren Haskell olduğunu :) –