Haskell 从列表中提取一个随机元素(并将其删除),学习单子

Haskell 从列表中提取一个随机元素(并将其删除),学习单子,haskell,random,monad-transformers,state-monad,Haskell,Random,Monad Transformers,State Monad,我通过Haskell维基和我自己的新手实验在Haskell学习单子 作为我的第一步,我已经使用great library(由Daniel Díaz编写)将书中与monads相关的部分复制粘贴到我自己的PDF中,同时轻松阅读这些硬文本(因为其内容而硬) 下面是我第一次尝试实践我学到的东西:一个函数的7个版本,它获取一个列表并从该列表中返回一个随机元素 现在我的主要问题是,我应该在“移除元素”部分使用monad变压器吗?我听说他们是用来混合单子的, 我知道我将使用State单子和List单子 除此之

我通过Haskell维基和我自己的新手实验在Haskell学习单子

作为我的第一步,我已经使用great library(由Daniel Díaz编写)将书中与monads相关的部分复制粘贴到我自己的PDF中,同时轻松阅读这些硬文本(因为其内容而硬)

下面是我第一次尝试实践我学到的东西:一个函数的7个版本,它获取一个列表并从该列表中返回一个随机元素

现在我的主要问题是,我应该在“移除元素”部分使用monad变压器吗?我听说他们是用来混合单子的, 我知道我将使用State单子和List单子

除此之外,对我的代码的任何评论都将不胜感激(风格的评论最多,因为monad是关于用风格写作的?:p)


------------------------去随机性------------------------
------------------------去随机性------------------------
------------------------TERCER打算消除随机性-------------------------
------------------------CUARTO打算消除随机性-------------------------
------------------------昆托意图去随机性-------------------------
------------------------性倾向于去随机性--------------------------
extractor\::[a]->状态StdGen a
提取器_xs=
做
发电机(st,st)
设n=长度xs
设(k,newGen)=randomR(0,n-1)发生器
放纽根
返回(xs!!k)
--德尔科迪戈贸易公司:
提取器_uxS=
获取>>=
\生成器->让n=长度xs英寸
(设(k,newGen)=随机r(0,n-1)发生器
(放入newGen>>返回(xs!!k)))
--*Main>:t提取器“
--提取器“::(随机生成t,单子m)=>[b]->StateT m b
--*Main>:t提取器_
--提取器::[a]->状态StdGen a
--=======o o======
--    ___________
--   |___________|    -------------------------------------------------------------------------------
--\\/\/\\\\\\\-------------------------------------最终版本------------------------
--    |_\/__\/__|     -------------------------------------------------------------------------------
--   |___________| 
--    ??????????????????? (不知道该选哪一个)
顺便说一句,我这样做是为了完成我的数学学位,之后我将通过Haskell:D(我是在要求a吗?)

我应该为“移除元素”部分使用monad变压器吗?我已经读到它们被用来混合单子,我知道我将使用状态单子和列表单子

但是你没有使用单子列表!您只是在使用列表。如果说您正在使用列表monad,则意味着您正在使用列表专用的
(>>=)
返回
(或类似的
monad
-列表专用的多态函数),而您没有这样做。因此,我认为使用
状态
,而不使用任何变压器是非常有意义的

除此之外,对我的代码的任何评论都将不胜感激(风格的评论最多,因为monad是关于用风格写作的?:p)

我最喜欢你的第四次尝试,提醒你的是:

extractR'''' :: [a] -> State StdGen a
extractR'''' xs = pr1 >>= f
  where
    n   = length xs
    pr1 = state $ randomR (0,n-1)
    f   = \k -> state ( \s -> (xs !! k , s) )
我唯一要做的调整是我发现你的
f
有点太复杂了。由于您根本没有修改状态,因此不需要使用特定于
状态的函数;可以写

    f   = \k -> return (xs !! k)
相反。然后我们可以应用单子定律,即:

m >>= (\x -> return (f x)) = fmap f m
因此,我希望看到的最终实施是:

extractR :: [a] -> State StdGen a
extractR xs = fmap (xs!!) pr1
  where
    n   = length xs
    pr1 = state $ randomR (0,n-1)

(当然,人们可以用几种其他方式拼写
fmap
,在这种情况下,它们主要在美学上有所不同,比如
()
liftA
,或
liftM

,您可能想看看
MonadRandom

import Control.Monad.Random

extractR :: MonadRandom m => [a] -> m a
extractR xs = (xs !!) <$> getRandomR (0, length xs - 1)
import Control.Monad.Random
提取器::MonadRandom=>[a]->MA
提取器xs=(xs!!)getRandomR(0,长度xs-1)
MonadRandom
约束由
IO
RandT g m
满足,它本质上是一个基于
StateT StdGen
的monad,在纯代码中可用


此外,该库定义了
uniform
,它相当于您的
extractor
(尽管它的实现相当复杂)。

除第一个版本外,其他所有版本都是合理的(其中一个版本是PRNG的误用,与Haskell或Monads无关),“应该”做的是对解决您的特定问题最有用的事情,没有唯一的办法。
extractR_ :: [a] -> State StdGen a
extractR_ xs = pr1 >>= f
  where
    n   = length xs
    pr1 = state $ randomR (0,n-1)
    f   = \k -> state ( \s -> (xs !! k , g s) )  
    g   = \stdG -> snd $ next stdG


-- monadic code, se actualiza 2 veces el StdGen
extractR_' :: [a] -> State StdGen a
extractR_' xs = 
  do
    generator <- get              -- get = state $ \st -> (st,st)
    let n = length xs
    let (k, newGen) = randomR (0,n-1) generator
    put newGen
    return (xs!!k)


-- traduccion del codigo:
extractR_'' xs = 
  get >>= 
    \generator -> let n=length xs in 
      ( let (k, newGen)=randomR (0,n-1) generator in 
        (put newGen >> return (xs!!k) ) )


-- *Main> :t extractR_''
-- extractR_'' :: (RandomGen t, Monad m) => [b] -> StateT t m b
-- *Main> :t extractR_
-- extractR_ :: [a] -> State StdGen a



-- ======o     o======
--    ___________
--   |___________|    -------------------------------------------------------------------------------
--    |\  /\  /\|     ------------------------        VERSION FINAL          ------------------------
--    |_\/__\/__|     -------------------------------------------------------------------------------
--   |___________| 



 --    ??????????????????? (dont know which to choose)
extractR'''' :: [a] -> State StdGen a
extractR'''' xs = pr1 >>= f
  where
    n   = length xs
    pr1 = state $ randomR (0,n-1)
    f   = \k -> state ( \s -> (xs !! k , s) )
    f   = \k -> return (xs !! k)
m >>= (\x -> return (f x)) = fmap f m
extractR :: [a] -> State StdGen a
extractR xs = fmap (xs!!) pr1
  where
    n   = length xs
    pr1 = state $ randomR (0,n-1)
import Control.Monad.Random

extractR :: MonadRandom m => [a] -> m a
extractR xs = (xs !!) <$> getRandomR (0, length xs - 1)