在 monadic 上下文中生成列表

Generating lists in a monadic context

据我了解,您可以在 haskell 中使用 'draw from' (<-) 关键字从 do-notation 中的 monadic 上下文中获取值:

func = do
    x <- getRandom
    let y = (x + 1)
    return y

生成列表时如何应用它?假设我正在映射一个函数 f :: (MonadRandom m) => Int -> m a,它在 MonadRandom 上下文中接受一个整数和 returns 一个值。我想在 MonadRandom 上下文中生成 a 类型的值列表,即 m [a] 。我相信做这样的事情:

func = do
    xs <- map f [0..10]
    return xs

将生成一个值列表,每个值都在一个单子上下文中,然后尝试从不在 MonadRandom 上下文中的列表中提取

抱歉,如果我的 terminology/understanding 不正确,我是 haskell 的新手。

更新

对于您使用 MonadRandom 进行的编辑,我想您只需要 mapM:

import System.Random (randomRIO)

f :: Int -> IO Int
f n = randomRIO (n,n+n)

g :: [Int] -> IO [Int]
g xs = mapM f xs

例子

λ> g [1..3]
[1,4,5]
λ> g [1..3]
[1,3,4]
λ> g [1..3]
[1,4,6]

顺便说一句:当然你可以自己使用 do:

g :: [Int] -> IO [Int]
g [] = return []
g (x:xs) = do
  r <- f x
  rs <- g xs
  return (r:rs)

请记住不要混淆列表和此处的 IO monad - 因此此处的 do<-returnIO 中- 对于这个答案的其余部分,它将在 list-monad


首先,您的示例 (if f :: a -> [b]) 将创建一个 值列表列表 (您肯定已经发现了)- 如果您想要 flatten 看下面(基本上你只需要再拉一次)


现在我不明白你要去哪里,但这里有一个简短的例子,说明如何将 do 符号用于列表:

看看这个函数:

combs :: [a] -> [b] -> [(a,b)]
combs xs ys = do
  x <- xs
  y <- ys
  return (x,y)

这是一个实际的例子:

λ> combs [1..3] "Hi"
[(1,'H'),(1,'i'),(2,'H'),(2,'i'),(3,'H'),(3,'i')]

如您所见,技巧 是从所有 xs (当然你会做所有的事情——因此你可以认为这是在使用组合数学)和 ys 中的 y 然后用它们做一些事情(这里只是做一个元组)最后 return正在处理它。

现在你当然可以先以某种方式映射它(这里只是将 xs 加倍):

combs :: [a] -> [b] -> [(a,b)]
combs xs ys = do
  x <- xs ++ xs
  y <- ys
  return (x,y)

它会提取映射值:

λ> combs [1..3] "Hi"
[(1,'H'),(1,'i'),(2,'H'),(2,'i'),(3,'H'),(3,'i'),(1,'H'),(1,'i'),(2,'H'),(2,'i'),(3,'H'),(3,'i')]

这对你有帮助吗?


这是另一个 f 自己创建列表的例子:

func :: (a -> [b]) -> [a] -> [b]
func f xs = do
  x <- xs
  b <- f x
  return b

如您所见,我们首先从 xs 中提取了一个 x,应用 f 来获取 b 的列表,然后使用 b <- f x 然后只返回那些。

这当然只是concatMap

示例

λ> func (\x -> [x,x]) [1..5]
[1,1,2,2,3,3,4,4,5,5]

这是你要去的地方吗?