从列表中提取一个随机元素(并删除它),学习单子
Extract a random element from a list (and remove it), learning monads
我在 Haskell 中使用 haskell wikibook 和我自己的新手实验学习 monad
作为我的第一步,我使用伟大的 HaTeX 库(Daniel Díaz)将书中与 monads 相关的部分复制粘贴到我自己的 PDF 中,同时轻轻阅读了如此难懂的文本(很难,因为它的内容)。
下面是我第一次尝试练习我学到的东西:一个函数的 7 个版本,它接受一个列表和 returns 来自该列表的随机元素
现在我的主要问题是,我应该在 "remove the element" 部分使用 monad Transformers 吗?我读过它们被用来混合单子,
我知道我将使用 State monad 和 List monad
除此之外,我们将不胜感激地收到对我的代码的任何评论(样式最多,因为 monad 是关于用样式编写的吗?:P)
import System.Random
import Control.Monad.Trans.State
import Control.Monad
------------------------ 随机性入门 ---------------- ------
extractR' :: [a] -> a
extractR' xs = xs !! randomPos
where
n = length xs
randomPos = fst pareja
pareja = randomR (0,n-1) stdGen
stdGen = mkStdGen 0
-- extractR' siempre devuelve la misma cosa, al llamarla sobre la misma
-- lista (por tanto NO SIRVE, NO ES ALEATORIO)
-- EJ:
-- *Deck> extractR' [1..100]
-- 46
-- (0.00 secs, 0 bytes)
-- *Deck> extractR' [1..100]
-- 46
-- (0.02 secs, 0 bytes)
-- *Deck> extractR' [1..100]
-- 46
-- (0.00 secs, 0 bytes)
------------------------ 随机的第二意图---------------- ------
stdGen = mkStdGen 0
extractR'' :: StdGen -> [a] -> (a, StdGen)
extractR'' gen xs = (xs !! randPos , newGen)
where
n = length xs
(randPos, newGen) = randomR (0,n-1) gen
-- esta version permite arrastrar el RNGenerator, pero es incomodisima de usar:
-- *Deck> extractR'' stdGen [1..100]
-- (46,40014 40692)
-- (0.00 secs, 0 bytes)
-- *Deck> let x = snd (extractR'' stdGen [1..100]) in extractR'' x [1..100]
-- (56,1601120196 1655838864)
-- (0.00 secs, 0 bytes)
------------------------ TERCER INTENTO DE RANDOMNESS ---------------- --------
extractR''' :: [a] -> State StdGen a
extractR''' xs = state sol
where
n = length xs
sol = \s -> ( xs !! (randPos s) , newGen s)
randPos st = fst $ randomR (0,n-1) st
newGen st = snd $ randomR (0,n-1) st
-- extractR''' xs =
-- state ( \s ->
-- ( xs !! (fst $ randomR (0, (length xs)-1) s )
-- ,
-- snd $ randomR (0, (length xs)-1) s ) )
-- pruebas en pantalla:
-- *Main> runState (extractR ['a'..'z']) (mkStdGen 0)
-- ('d',40014 40692)
-- (0.00 secs, 0 bytes)
-- *Main> runState (extractR ['a'..'z']) (mkStdGen 0)
-- ('d',40014 40692)
-- (0.00 secs, 0 bytes)
-- *Main> runState (extractR ['a'..'z']) (mkStdGen 7854)
-- ('n',314309970 40692)
-- (0.00 secs, 0 bytes)
-- works well, but the code is bad (non-monadic)
-- but we are in the State monad, so the following works:
extractR2 :: [a] -> State StdGen (a,a)
extractR2 xs = liftM2 (,) (extractR''' xs) (extractR''' xs)
------------------------ CUARTO INTENTO DE RANDOMNESS ---------------- --------
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) )
-- monadic code, se actualiza 1 vez el StdGen
------------------------ QUINTO INTENTO DE RANDOMNESS ---------------- --------
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)
顺便说一句,我这样做是为了完成我的数学学位,之后我将寻求通过 Haskell 谋生 :D(我要 miracle 吗?)
should i be using monad Transformers for the "remove the element" part? i've read they are used to mix monads, and i know i will be using the State monad and the List monad
但是你没有使用list monad!您只是在使用列表。说你正在使用列表 monad 意味着你正在使用专门用于列表的 (>>=)
或 return
(或类似的 Monad
-专门用于列表的多态函数),而你没有这样做。所以我认为使用 State
而不使用任何变形金刚是完全合理的。
Other than that, any comments on my code will be gratefully recieved (the style ones the most, as monads are about writing with style? :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
有点太复杂了。由于您根本没有修改状态,因此不需要使用 State
特定的函数;可以写
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)
MonadRandom
约束由 IO
和 RandT g m
满足,它本质上是一个基于 StateT StdGen
的单子,可用于纯代码。
此外,该库定义了 uniform
,它等同于您的 extractR
(尽管其实现相当复杂)。
我在 Haskell 中使用 haskell wikibook 和我自己的新手实验学习 monad
作为我的第一步,我使用伟大的 HaTeX 库(Daniel Díaz)将书中与 monads 相关的部分复制粘贴到我自己的 PDF 中,同时轻轻阅读了如此难懂的文本(很难,因为它的内容)。
下面是我第一次尝试练习我学到的东西:一个函数的 7 个版本,它接受一个列表和 returns 来自该列表的随机元素
现在我的主要问题是,我应该在 "remove the element" 部分使用 monad Transformers 吗?我读过它们被用来混合单子, 我知道我将使用 State monad 和 List monad
除此之外,我们将不胜感激地收到对我的代码的任何评论(样式最多,因为 monad 是关于用样式编写的吗?:P)
import System.Random
import Control.Monad.Trans.State
import Control.Monad
------------------------ 随机性入门 ---------------- ------
extractR' :: [a] -> a
extractR' xs = xs !! randomPos
where
n = length xs
randomPos = fst pareja
pareja = randomR (0,n-1) stdGen
stdGen = mkStdGen 0
-- extractR' siempre devuelve la misma cosa, al llamarla sobre la misma
-- lista (por tanto NO SIRVE, NO ES ALEATORIO)
-- EJ:
-- *Deck> extractR' [1..100]
-- 46
-- (0.00 secs, 0 bytes)
-- *Deck> extractR' [1..100]
-- 46
-- (0.02 secs, 0 bytes)
-- *Deck> extractR' [1..100]
-- 46
-- (0.00 secs, 0 bytes)
------------------------ 随机的第二意图---------------- ------
stdGen = mkStdGen 0
extractR'' :: StdGen -> [a] -> (a, StdGen)
extractR'' gen xs = (xs !! randPos , newGen)
where
n = length xs
(randPos, newGen) = randomR (0,n-1) gen
-- esta version permite arrastrar el RNGenerator, pero es incomodisima de usar:
-- *Deck> extractR'' stdGen [1..100]
-- (46,40014 40692)
-- (0.00 secs, 0 bytes)
-- *Deck> let x = snd (extractR'' stdGen [1..100]) in extractR'' x [1..100]
-- (56,1601120196 1655838864)
-- (0.00 secs, 0 bytes)
------------------------ TERCER INTENTO DE RANDOMNESS ---------------- --------
extractR''' :: [a] -> State StdGen a
extractR''' xs = state sol
where
n = length xs
sol = \s -> ( xs !! (randPos s) , newGen s)
randPos st = fst $ randomR (0,n-1) st
newGen st = snd $ randomR (0,n-1) st
-- extractR''' xs =
-- state ( \s ->
-- ( xs !! (fst $ randomR (0, (length xs)-1) s )
-- ,
-- snd $ randomR (0, (length xs)-1) s ) )
-- pruebas en pantalla:
-- *Main> runState (extractR ['a'..'z']) (mkStdGen 0)
-- ('d',40014 40692)
-- (0.00 secs, 0 bytes)
-- *Main> runState (extractR ['a'..'z']) (mkStdGen 0)
-- ('d',40014 40692)
-- (0.00 secs, 0 bytes)
-- *Main> runState (extractR ['a'..'z']) (mkStdGen 7854)
-- ('n',314309970 40692)
-- (0.00 secs, 0 bytes)
-- works well, but the code is bad (non-monadic)
-- but we are in the State monad, so the following works:
extractR2 :: [a] -> State StdGen (a,a)
extractR2 xs = liftM2 (,) (extractR''' xs) (extractR''' xs)
------------------------ CUARTO INTENTO DE RANDOMNESS ---------------- --------
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) )
-- monadic code, se actualiza 1 vez el StdGen
------------------------ QUINTO INTENTO DE RANDOMNESS ---------------- --------
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)
顺便说一句,我这样做是为了完成我的数学学位,之后我将寻求通过 Haskell 谋生 :D(我要 miracle 吗?)
should i be using monad Transformers for the "remove the element" part? i've read they are used to mix monads, and i know i will be using the State monad and the List monad
但是你没有使用list monad!您只是在使用列表。说你正在使用列表 monad 意味着你正在使用专门用于列表的 (>>=)
或 return
(或类似的 Monad
-专门用于列表的多态函数),而你没有这样做。所以我认为使用 State
而不使用任何变形金刚是完全合理的。
Other than that, any comments on my code will be gratefully recieved (the style ones the most, as monads are about writing with style? :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
有点太复杂了。由于您根本没有修改状态,因此不需要使用 State
特定的函数;可以写
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)
MonadRandom
约束由 IO
和 RandT g m
满足,它本质上是一个基于 StateT StdGen
的单子,可用于纯代码。
此外,该库定义了 uniform
,它等同于您的 extractR
(尽管其实现相当复杂)。