Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 如何洗牌列表?_Haskell - Fatal编程技术网

Haskell 如何洗牌列表?

Haskell 如何洗牌列表?,haskell,Haskell,如何在不替换一组数字([1,2,3])的情况下采样,直到我点击x? 我的计划是将列表重新排列,然后在x处切掉: -- chopAt 3 [2, 3, 1] == [2, 3] -- chopAt 3 [2, 1, 3] == [2, 1, 3] -- chopAt 3 [3, 1, 2] == [3] chopAt _ [] = [] chopAt x (y:ys) | x /= y = y : chopAt x ys | otherwise = [y] 然而,我不知道如何洗牌列

如何在不替换一组数字(
[1,2,3]
)的情况下采样,直到我点击
x
? 我的计划是将列表重新排列,然后在x处切掉:

-- chopAt 3 [2, 3, 1] == [2, 3]
-- chopAt 3 [2, 1, 3] == [2, 1, 3]
-- chopAt 3 [3, 1, 2] == [3]
chopAt _ [] = []
chopAt x (y:ys)
  | x /= y    = y : chopAt x ys
  | otherwise = [y]
然而,我不知道如何洗牌列表(或了解单子还没有)

——从[1,2,3]开始采样,不进行替换,直到有人点击3为止
--你在找什么

另外,
cropAt
似乎可以通过
takeWhile
实现。我个人更喜欢标准的组合器而不是手工制作的。

使用,甚至可能实现你的洗牌。有几个很好的答案

但这确实是可行的。下面是幕后发生的事情

我 随机性是Haskell中首先遇到的地方之一,你必须处理杂质——这似乎很令人反感,因为洗牌和样本看起来很简单,不觉得它们应该与打印到物理屏幕或发射核武器捆绑在一起,但通常情况下,
纯度==引用透明性
和引用透明随机性

因此,我们需要对随机性有一个不同的想法,使其变得纯粹

二,。 在用于增强再现性的科学代码中,一个典型的“欺骗”非常重要,那就是修复实验的随机种子,以便其他人可以在每次运行代码时验证他们得到的结果是否完全相同。这正是参考透明度!让我们试试看

type Seed = Int
random :: Seed -> (Int, Seed)
random s = (mersenneTwisterPerturb s, splitSeed s)
其中,
mersennetwister扰动
是从
Seed
s到
Int
的伪随机映射,
splitSeed
是从
Seed
s到
Seed
s的伪随机映射。请注意,这两个函数都是完全确定的(并且在引用上是透明的),所以
random
也是如此,但是我们可以创建一个无限的、懒惰的伪随机流,就像这样

randomStream :: Seed -> [Int]
randomStram s = mersenneTwisterPerturb s : randomStream (splitSeed s)
同样,此流是基于
种子
值确定的,但是只看到流而不看到种子的观察者应该无法预测其未来值

三,。 我们能用一个随机的整数流洗牌一个列表吗?当然可以,通过使用模运算

shuffle' :: [Int] -> [a] -> [a]
shuffle' (i:is) xs = let (firsts, rest) = splitAt (i `mod` length xs) xs
                     in (last firsts) : shuffle is (init firsts ++ rest)
或者,为了使其更加独立,我们可以预合成流生成函数以获得

shuffle :: Seed -> [a] -> [a]
shuffle s xs = shuffle' (randomStream s) xs
另一个“种子消耗”引用透明的“随机”函数

shuffle :: StdGen -> [a] -> [a]
shuffle g xs = shuffle' (randoms g) xs
四,。 所以这似乎是一个重复的趋势。事实上,如果你浏览模块
System.Random
,你会看到很多像我们上面写的那样的函数(我专门化了一些类型类)

其中,
Random
是可以随机生成的事物的类型类,
StdGen
是一种
Seed
。这已经足够编写必要的洗牌函数了

shuffle :: StdGen -> [a] -> [a]
shuffle g xs = shuffle' (randoms g) xs
还有一个
IO
函数
newStdGen::IO StdGen
,它可以让我们构建一个随机种子

main = do gen <- newStdGen
          return (shuffle gen [1,2,3,4,5])
Seed f::Seed->(a,Seed)
的结果类型
是一个相当普遍的结果。让我们给它起个名字

newtype Random a = Random (Seed -> (a, Seed))
我们知道我们可以在
IO
中创建有意义的
Seed
s,因此有一个明显的函数可以将
随机类型转换为
IO

runRandom :: Random a -> IO a
runRandom (Random f) = do seed <- newSeed
                          let (result, _) = f seed
                          return result
但这有点愚蠢,因为我们只是扔掉了
\u aValue
。让我们组合它们,使第二个随机数实际上取决于第一个随机值

bindRandom :: Random a -> (a -> Random b) -> Random b
bindRandom (Random fa) getRb = 
    Random $ \seed -> let (aValue, newSeed) = fa seed
                          (Random fb)       = getRb aValue
                      in fb newSeed
我们还应该注意,我们可以对
Random
值执行“纯”操作,例如,将随机数乘以2:

randomTimesTwo :: Random Int -> Random Int
randomTimesTwo (Random f) = Random $ \seed -> let (value, newSeed) = f seed
                                              in (value*2, newSeed)
我们可以将其抽象为函子实例

instance Functor Random where
  fmap f (Random step) = Random $ \seed -> let (value, newSeed) = step seed
                                           in (f value, newSeed)
现在我们可以创建很酷的随机效果,比如布朗运动

brownianMotion :: Random [Int]
brownianMotion = 
   bindRandom random $ \x -> 
       fmap (\rest -> x : map (+x) rest) brownianMotion
不及物动词。 这就触及了我一直在写的整个事情的核心。随机性可以完美地存在于
IO
monad中,但它也可以作为一个更简单的
Random
monad单独存在。我们可以立即编写实例

instance Monad Random where
  return x = Random (\seed -> (x, seed))
  rx >>= f = bindRandom rx f
既然它是单子,我们就可以得到免费的
do
notation

brownianMotion' = do x <- random
                     rest <- brownianMotion'
                     return $ x : map (+x) rest

brownianMotion'=doxBellow从我开始学习哈斯克尔时,你可能会找到一些简单的解决方案。如果说实话,我还处于起步阶段或者只是稍微落后;-)

导入系统。随机
导入控制
随机播放::[a]->IO[a]
洗牌[]=返回[]
洗牌lst=do
(e,rest)错误$“在索引“++显示n”处失败--不应匹配
(r,s)->(最后一个r,初始r++s)

似乎每个人都在某个时间点遇到过这种情况。这是我对问题的快速解决方案:

import System.Random

shuffle :: [a] -> IO [a]
shuffle [] = return []
shuffle xs = do randomPosition <- getStdRandom (randomR (0, length xs - 1))
                let (left, (a:right)) = splitAt randomPosition xs
                fmap (a:) (shuffle (left ++ right))
导入系统。随机
随机播放::[a]->IO[a]
洗牌[]=返回[]
shuffle xs=do randomPosition a i e->i->i->m()

swapElements_uarri j=do a要洗牌列表,请使用库:

import System.Random(newStdGen)
导入System.Random.Shuffle(Shuffle')
main=do

rng将此函数添加到您的代码中,然后像这样调用它
shuffle(mkStdGen 5)[1,2,3,4,5]

import System.Random

shuffle gen [] = [] 
shuffle gen list = randomElem : shuffle newGen newList
  where 
   randomTuple = randomR (0,(length list) - 1) gen
   randomIndex = fst randomTuple
   newGen      = snd randomTuple
   randomElem  = list !! randomIndex
   newList     = take randomIndex list ++ drop (randomIndex+1) list
或者像这样把它包含在你的
do
块中

main = do
     r <- randomIO
     str <- getLine 
     putStrLn (show (shuffle (mkStdGen r) str))
main=do

r另请参见。random fu只是将洗牌向下踢到s
shuffle::[a]->[Int]->[a]
,老实说,这是一种比我上面提到的更好的洗牌算法。还有一个
shuffle':RandomGen gen=>[a]->Int->gen->[a]
直接连接到
系统。Random
随机功能。如果你不想要种子,因为你想要一个硬件RNG,你会怎么做?最终你可能想要种子(否则速度会非常慢)所以你只需要确保你从一个好的熵源得到它们,然后把它们放到一个好的PRNG中。如果你真的想要纯硬件的随机性,那么有一个简单的函数来编写
IO位类型的
[837687365, 83748347, 2390293,         817218, 8127283, 2893827,         83748475, 94859485, 9343984,         458745878, 94854959,
instance Monad Random where
  return x = Random (\seed -> (x, seed))
  rx >>= f = bindRandom rx f
brownianMotion' = do x <- random
                     rest <- brownianMotion'
                     return $ x : map (+x) rest
import System.Random
import Control.Applicative

shuffle :: [a] -> IO [a]
shuffle [] = return []
shuffle lst = do
    (e, rest) <- pickElem <$> getIx
    (e:) <$> shuffle rest
    where
    getIx = getStdRandom $ randomR (1, length lst)
    pickElem n = case splitAt n lst of
        ([], s) -> error $ "failed at index " ++ show n -- should never match
        (r, s)  -> (last r, init r ++ s)
import System.Random

shuffle :: [a] -> IO [a]
shuffle [] = return []
shuffle xs = do randomPosition <- getStdRandom (randomR (0, length xs - 1))
                let (left, (a:right)) = splitAt randomPosition xs
                fmap (a:) (shuffle (left ++ right))
import Data.Array.IO
import System.Random

swapElements_ :: (MArray a e m, Ix i) => a i e -> i -> i -> m ()
swapElements_ arr i j = do a <- readArray arr i
                           b <- readArray arr j
                           writeArray arr i b
                           writeArray arr j a
                           return ()

shuffle :: [a] -> IO [a]
shuffle xs = do let upperBound = length xs
                arr <- (newListArray (1, upperBound) :: [a] -> IO (IOArray Int a)) xs
                mapM_ (shuffleCycle arr) [2..upperBound]
                getElems arr
  where shuffleCycle arr i = do j <- getStdRandom (randomR (1, i))
                                swapElements_ arr i j
import System.Random (newStdGen)
import System.Random.Shuffle (shuffle')

main = do
  rng <- newStdGen

  let xs = [1,2,3,4,5]

  print $ shuffle' xs (length xs) rng
import System.Random

shuffle gen [] = [] 
shuffle gen list = randomElem : shuffle newGen newList
  where 
   randomTuple = randomR (0,(length list) - 1) gen
   randomIndex = fst randomTuple
   newGen      = snd randomTuple
   randomElem  = list !! randomIndex
   newList     = take randomIndex list ++ drop (randomIndex+1) list
main = do
     r <- randomIO
     str <- getLine 
     putStrLn (show (shuffle (mkStdGen r) str))