2013-10-04 16 views
6

VEYA VEYA VEYA VEYA VEYA VEYA VEYA VEYA VEYA VEYA YOL AÇIĞI için mplus ile eşlenen VEYA VEYA karar ağacı oluşturmak için bir EDSL oluşturmak için ücretsiz bir monad kullanmaya çalışıyorum. A AND (B OR C) AND (D OR E) gibi bir şeyi tanımlamak istiyorum, ancak bunu dağıtımın (A AND B AND D) OR (A AND B AND E) OR (A AND C AND D) OR (A AND C AND E)'a dönüştürmesini istemiyorum. Sonuç olarak, çözücünün ele almasını istediğim alternatiflerin sayısında kombinatoryal patlamaya neden olmadan AND/OR düğümlerini bir kısıtlayıcı çözücüde birleştirilmiş kısıtlamalara dönüştürmek istiyorum. Control.MonadPlus.Free olarakControl.MonadPlus.Free dağıtımsız ücretsiz

, Plus ms >>= ffms her monadın altında Pure yaprakların her tatbik edilmesine neden olur. Bu gereklidir, çünkü f, değiştirdiği her bir Pure yaprak için farklı bir değer verebilir.

Ancak Plus ms >> g yılında, g yüzden Plus üzerinde dağıtmadan gereksiz görünüyor, ms yapraklarından herhangi etkilenen edilemez. ardından İşte

data Free f a = Pure a 
       | Free (f (Free f a)) 
       | Then [Free f()] (Free f a) 
       | Plus [Free f a] 

, yeni Then yapıcı değeri biz görmezden monads dizisi tutar:

deneme yanılma yoluyla, ben yeni Then kurucu ile Control.MonadPlus.Free monad uzatmak olabilir bulundu Gerçek değeri veren son monad.

instance Functor f => Monad (Free f) where 
    return = Pure 

    Pure a >>= f = f a 
    Free fa >>= f = Free $ fmap (>>= f) fa 
    Then ms m >>= f = Then ms $ m >>= f 
    Plus ms >>= f = Plus $ map (>>= f) ms 

    Pure a >> mb = mb 
    Then ms ma >> mb = Then (ms ++ [ma >>= (const $ return())]) mb 
    ma >> mb = Then [] ma >> mb 

>> operatör "kapakları" Pure() ile Pure a değiştirerek varolan herhangi yaprakları, listeye şapkalı monad ekler ve yenisi ile değer monad yerine geçer: gibi yeni Monad örneği görünüyor. ++ ile yeni monad eklenmesi verimsizliğinin farkındayım, amafmap ile zincirinin sonuna yeni monosunu dikiş gibi (ve her şey devamları kullanarak yeniden yazılabilir) kadar kötü olduğunu düşünüyorum.

Bu, yapılması mantıklı bir şey gibi görünüyor mu? Bu, monad yasalarını ihlal ediyor mu (bu mesele mi?) Veya mevcut Control.Monad.Free'u kullanmanın daha iyi bir yolu var mı?

cevap

2

Ücretsiz monad'lardan farklı olan operational paketimize bir göz atmak isteyebilirsiniz.

Özellikle, BreadthFirstParsing.hs örneğine bakın. Bir mplus işlemine sahiptir, böylece >>= otomatik olarak dağıtmaz. Bu, ayrıştırıcı kombinatorlerini geniş kapsamlı bir şekilde uygulamanıza olanak tanır. Control.Monad.Free dile çevrildi

, nokta sonra functor

data F b = MZero | MPlus b b 

kullanırsanız Free F otomatik mplus üzerinde >>= dağıtacak olmasıdır. Sen otomatik >>= dağıtımının MPlus için semantiğini uygulamak istiyorsanız, bunun yerine funktor

data F b = MZero | forall a. MPlus (Free f a) (Free f a) (a -> b) 

kullanmak zorunda.(Bu, işletim kütüphanemden ücretsiz kütüphaneyi tercih etmemin ana sebebidir.)