2012-12-14 27 views
0

具有不确定性的单子变压器我想建在Haskell一个不确定的单子转换,我认为,从ListT和ListT建议在http://www.haskell.org/haskellwiki/ListT_done_right替代不同的行为。其中第一个将monad与一系列项目联系起来;第二种将单子与单个项目联系起来,但具有以下特性:给定元素中的单子动作影响列表中后续插槽中的单子元素。我们的目标是建立形式建立在Haskell

data Amb m a = Cons (m a) (Amb m a) | Empty 

的单子转换,使该列表的每一个元素都有与它相关联自己的单子,并且连续元素具有独立的单子。在这篇文章的最后,我对这个monad应该给出的这种行为有一些证明。如果你知道如何获得ListT的一些变体来提供这种行为,那也是有帮助的。

以下是我的尝试。它不完整,因为unpack函数未定义。我怎样才能定义它?下面是在它定义一个不完整的企图,但是当单子M含有的Empty大使名单不采取了这样的情况:

unpack :: (Monad m) => m (Amb m a) -> Amb m a                             
unpack m = let first = join $ do (Cons x ys) <- m                            
           return x                              
       rest = do (Cons x ys) <- m                              
          return ys                               
      in Cons first (unpack rest) 

满(不完全)代码:

import Prelude hiding (map, concat)                               
import Control.Monad                                   
import Control.Monad.Trans  

data Amb m a = Cons (m a) (Amb m a) | Empty                             

infixr 4 <:>                                     
(<:>) = Cons                                     

map :: Monad m => (a -> b) -> Amb m a -> Amb m b                            
map f (Cons m xs) = Cons y (map f xs)                               
    where y = do a <- m                                  
       return $ f a                                 
map f Empty = Empty                                   

unpack :: m (Amb m a) -> Amb m a                                
unpack m = undefined                                   


concat :: (Monad m) => Amb m (Amb m a) -> Amb m a                            
concat (Cons m xs) = (unpack m) `mplus` (concat xs)                           
concat Empty = Empty                                   

instance Monad m => Monad (Amb m) where                              
    return x = Cons (return x) Empty                               
    xs >>= f = let yss = map f xs                                
       in concat yss                                 

instance Monad m => MonadPlus (Amb m) where                             
    mzero = Empty                                    
    (Cons m xs) `mplus` ys = Cons m (xs `mplus` ys)                           
    Empty `mplus` ys = ys                                  

instance MonadTrans Amb where                                 
    lift m = Cons m Empty   

期望的行为的实例

这里,基单子是State Int

instance Show a => Show (Amb (State Int) a) where                            
    show m = (show . toList) m                                


toList :: Amb (State Int) a -> [a]                                
toList Empty = []                                    
toList (n `Cons` xs) = (runState n 0 : toList xs)                            


x = (list $ incr) >> (incr <:> incr <:> Empty)                             
y = (list $ incr) >> (incr <:> (incr >> incr) <:> Empty)                          

main = do                                      
    putStr $ show x -- | should be [2, 2]                              
    putStr $ show y -- | should be [2, 3] 

谢谢。

更新:为什么LogicT没有做我想做的例子。

这里就是LogicT做上面的简单的例子:

import Control.Monad                                   
import Control.Monad.Logic                                  
import Control.Monad.State                                  

type LogicState = LogicT (State Int)                               


incr :: State Int Int                                   
incr = do i <- get                                    
      put (i + 1)                                   
      i' <- get                                   
      return i'                                   

incr' = lift incr                                    
y = incr' >> (incr' `mplus` incr')                               

main = do                                      
    putStrLn $ show (fst $ runState (observeAllT y) 0) -- | returns [2,3], not [2,2]                          
+1

你看过[logict](http://hackage.haskell.org/package/logict)吗? –

+0

请注意,在你的不完整的'unpack'中,'first = do {(Cons x _)< - m; x}'。你不需要额外的'join'和'return'层。 – huon

+0

@DanielWagner根据你的建议,我看了一下逻辑记录,并在帖子末尾添加了一个示例,说明为什么我认为逻辑不符合要求。 – Eyal

回答

2

我相信你可以使用StateT。例如:

import Control.Monad.State 

incr = modify (+1) 
sample1 = incr `mplus` incr 
sample2 = incr `mplus` (incr >> incr) 

monomorphicExecStateT :: StateT Int [] a -> Int -> [Int] 
monomorphicExecStateT = execStateT 

main = do 
    print (monomorphicExecStateT sample1 0) -- [1, 1] 
    print (monomorphicExecStateT sample2 0) -- [1, 2] 
+0

我的示例要求“incr >>(incr'mplus' incr)”而不是''incr'mplus'(incr >> incr)''的行为。神秘的是如何将外部“incr”的效果“分配”到内部效果。 – Eyal

+0

@Eyal试试吧,看看。 'print(monomorphicExecStateT(incr >> sample1)0)'打印'[2,2]',就像你所要求的一样。最初的'incr >>'在你的问题中实际上并不有趣 - 只有'mplus'行为很有趣而且很难。至于你说你不要求'incr \'mplus \'(incr >> incr)',那么看看你的示例代码中'y'的定义。 =) –

+0

嗯,我明白你的观点。也许它和你的建议一样简单。在我的实际使用案例中,我的基地monad不是国家,而是我自己制作的一些monad。所以这意味着,我不需要用一些monad变换器来改变我的monad基础单元,我需要开发一个monad变压器版本的基础monad,并用它来改变monad单元格? – Eyal

1

我不认为这是可能在一般情况下(和单子转换应该是能够改变任何单子)。你提到的解压缩选项是不可能的,一般单子 - 它所对应的操作:

extract :: (Comonad w) => w a -> a 

这是一个comonad(数学双单子的)的操作。

有些事情可以通过采取(m(Amb ma))并将其映射几次以产生单个(ma)来解压缩它,但这需要您事先知道(或者更确切地说,来自monad外部)正在创建多少个选择,如果没有某种形式的提取操作,这些选择是不可能知道的。

在第二个ListT中列表的尾部取决于一次性动作的原因是因为我们需要在某些情况下执行一次性动作,以便找出正在生成多少个选项(以及多长时间列表是)。

+0

谢谢,我想这就是我所期望的。你能想到如何实现这个问题的解决方案吗?我应该尝试为我的基地monad定义一个comonad实例,还是你会做一些不同的事情? – Eyal

+0

我几乎写完了一些我认为尽可能接近的东西 - 它基本上是一个免费的monad。在几分钟之内通过进一步的评论与你同在。 – DarkOtter

+0

好吧,它似乎工作,虽然我不会建议使用它没有比我更专家看看。 https://gist.github.com/4288510 一些解释可能比你需要更多的细节,我不确定你是多么熟悉Haskell(而且我不是专家) 。 – DarkOtter