在 Haskell 中动态构建列表理解

发布于 2024-08-23 08:44:12 字数 496 浏览 3 评论 0原文

我很好奇是否可以在 Haskell 中动态构建列表理解。

举个例子,如果我有以下内容:

all_pows (a,a') (b,b') = [ a^y * b^z | y <- take a' [0..], z <- take b' [0..] ]

我得到了我想要的东西

*Main> List.sort $ all_pows (2,3) (5,3)
[1,2,4,5,10,20,25,50,100]

但是,我真正想要的是拥有类似的东西

all_pows [(Int,Int)] -> [Integer]

这样我就可以支持 N 对参数而无需构建 all_pows 的 N 个版本。我对 Haskell 还很陌生,所以我可能忽略了一些明显的事情。这可能吗?

I am curious if it is possible to dynamically build a list comprehension in Haskell.

As an example, if I have the following:

all_pows (a,a') (b,b') = [ a^y * b^z | y <- take a' [0..], z <- take b' [0..] ]

I get what I am after

*Main> List.sort $ all_pows (2,3) (5,3)
[1,2,4,5,10,20,25,50,100]

However, what I'd really like is to have something like

all_pows [(Int,Int)] -> [Integer]

So that I can support N pairs of arguments without building N versions of all_pows. I'm still pretty new to Haskell so I may have overlooked something obvious. Is this even possible?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

黯然 2024-08-30 08:44:12

列表单子的魔力:

ghci> let powers (a, b) = [a ^ n | n <- [0 .. b-1]]
ghci> powers (2, 3)
[1,2,4]
ghci> map powers [(2, 3), (5, 3)]
[[1,2,4],[1,5,25]]
ghci> sequence it
[[1,1],[1,5],[1,25],[2,1],[2,5],[2,25],[4,1],[4,5],[4,25]]
ghci> mapM powers [(2, 3), (5, 3)]
[[1,1],[1,5],[1,25],[2,1],[2,5],[2,25],[4,1],[4,5],[4,25]]
ghci> map product it
[1,5,25,2,10,50,4,20,100]
ghci> let allPowers list = map product $ mapM powers list
ghci> allPowers [(2, 3), (5, 3)]
[1,5,25,2,10,50,4,20,100]

这可能值得更多解释。

您可以自己编写

cartesianProduct :: [[a]] -> [[a]]
cartesianProduct [] = [[]]
cartesianProduct (list:lists)
  = [ (x:xs) | x <- list, xs <- cartesianProduct lists ]

这样的 cartesianProduct [[1],[2,3],[4,5,6]][[1,2,4],[1 ,2,5],[1,2,6],[1,3,4],[1,3,5],[1,3,6]]

但是, 推导式monad 是故意相似的。标准 Prelude 具有 sequence :: Monad m => [ma]-> m [a],当 m 是列表 monad [] 时,它实际上完全按照我们上面写的方式执行。

作为另一个快捷方式, mapM :: Monad m => (a→mb)→ [一]-> m [b] 只是 sequencemap 的组合。

对于每个底数的不同幂的每个内部列表,您希望将它们乘以一个数字。您可以递归地

product list = product' 1 list
  where product' accum [] = accum
        product' accum (x:xs)
          = let accum' = accum * x
             in accum' `seq` product' accum' xs

或使用折叠来

import Data.List
product list = foldl' (*) 1 list

编写此代码,但实际上 产品 :: Num a => [一]-> a 已经定义了!我喜欢这门语言☺☺☺

The magic of the list monad:

ghci> let powers (a, b) = [a ^ n | n <- [0 .. b-1]]
ghci> powers (2, 3)
[1,2,4]
ghci> map powers [(2, 3), (5, 3)]
[[1,2,4],[1,5,25]]
ghci> sequence it
[[1,1],[1,5],[1,25],[2,1],[2,5],[2,25],[4,1],[4,5],[4,25]]
ghci> mapM powers [(2, 3), (5, 3)]
[[1,1],[1,5],[1,25],[2,1],[2,5],[2,25],[4,1],[4,5],[4,25]]
ghci> map product it
[1,5,25,2,10,50,4,20,100]
ghci> let allPowers list = map product $ mapM powers list
ghci> allPowers [(2, 3), (5, 3)]
[1,5,25,2,10,50,4,20,100]

This probably deserves a bit more explanation.

You could have written your own

cartesianProduct :: [[a]] -> [[a]]
cartesianProduct [] = [[]]
cartesianProduct (list:lists)
  = [ (x:xs) | x <- list, xs <- cartesianProduct lists ]

such that cartesianProduct [[1],[2,3],[4,5,6]][[1,2,4],[1,2,5],[1,2,6],[1,3,4],[1,3,5],[1,3,6]].

However, comprehensions and monads are intentionally similar. The standard Prelude has sequence :: Monad m => [m a] -> m [a], and when m is the list monad [], it actually does exactly what we wrote above.

As another shortcut, mapM :: Monad m => (a -> m b) -> [a] -> m [b] is simply a composition of sequence and map.

For each inner list of varying powers of each base, you want to multiply them to a single number. You could write this recursively

product list = product' 1 list
  where product' accum [] = accum
        product' accum (x:xs)
          = let accum' = accum * x
             in accum' `seq` product' accum' xs

or using a fold

import Data.List
product list = foldl' (*) 1 list

but actually, product :: Num a => [a] -> a is already defined! I love this language ☺☺☺

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文