使用 random-fu shuffle 对列表进行混洗,对列表进行操作并在 Haskell 中显示结果

Shuffling a list using random-fu shuffle, doing an operation on a list and displaying result in Haskell

我的目标是从输入列表中获取 N 个随机项目的列表,并在 GHCI 中查看结果。我决定打乱输入列表,然后从中取出第一个 N 个元素(即切片第一个元素)。我正在使用来自 random-fu 模块 Data.Random.List.

shuffle 函数

这是我目前的代码,至少可以编译

import Data.Random
import Data.Random.List

rndSelect :: [a] -> Int -> RVar [a]
rndSelect l n
  = do 
       l' <- shuffle l;
       return $ take n l'

但是当我在 GHCI 提示符中 运行 rndSelect "abcdefg" 3 时,我得到以下错误:

<interactive>:1:1: error:
    • No instance for (Show (RVar [Char]))
        arising from a use of ‘print’
    • In a stmt of an interactive GHCi command: print it

我想我知道这意味着什么。 RVar 不推导 Show。我想我应该修改我的函数,以便它被打乱 RVar[a] 然后以某种方式获取第一个 N 元素的列表并将其转换为 IO 操作。

这是我失败的尝试之一:

rndSelect :: [a] -> Int -> IO ()
rndSelect l n
  = do 
       l' <- shuffle l;
       l'' <- take n l'
       s <- runRVar l'' StdRandom
       putStrLn s

我知道,它一团糟,并且在错误之上引发错误。我是 Monads 的初学者,在 Haskell

中“做”积木之类的事情

如果有人帮助我修正我的方法,我会很高兴,但如果你知道实现我的目标的替代方法,我也会很高兴看到它。非常感谢!

您的 rndSelect :: [a] -> Int -> RVar [a] 完全没问题,但很明显结果 RVar [a] 无法真正显示。毕竟这是一个概率分布。这种分布通常“包含”无限多可能的结果。您所希望做的就是从分布中显示 samples。由于 GHCi 允许您进行 IO,因此很容易在那里获得样本:

*Main> sample $ rndSelect "abcdefg" 3
"def"
*Main> sample $ rndSelect "abcdefg" 3
"ecb"
*Main> sample $ rndSelect "abcdefg" 3
"fbc"
*Main> :m +Control.Monad
*Main Control.Monad> sample . replicateM 20 $ rndSelect "abcdefg" 3
["gef","adf","cga","bfd","eab","bgd","gdf","abg","egc","bda","ceb","fbd","agb","egc","acb","bga","gbd","edb","egb","egd"]