haskell - 在列表理解中拥有许多相同生成器的惯用方式

标签 haskell list-comprehension idioms

在统计学课上,我的老师向我们展示了两个骰子加到 4 的所有可能掷骰的概率模型。记住 Haskell 列表推导非常棒,我决定将其带到下一步并编写此代码以找到 所有可能的 4 个骰子加到 10 :
[(d1,d2,d3,d4) | d1 <- [1..6], d2 <- [1..6], d3 <- [1..6], d4 <- [1..6], (d1 + d2 + d3 + d4) == 10]
这可以按预期工作,给我输出

[(1,1,2,6),(1,1,3,5),(1,1,4,4),(1,1,5,3),(1,1,6,2),(1,2,1,6),(1,2,2,5),(1,2,3,4),(1,2,4,3),(1,2,5,2),(1,2,6,1),(1,3,1,5),(1,3,2,4),(1,3,3,3),(1,3,4,2),(1,3,5,1),(1,4,1,4),(1,4,2,3),(1,4,3,2),(1,4,4,1),(1,5,1,3),(1,5,2,2),(1,5,3,1),(1,6,1,2),(1,6,2,1),(2,1,1,6),(2,1,2,5),(2,1,3,4),(2,1,4,3),(2,1,5,2),(2,1,6,1),(2,2,1,5),(2,2,2,4),(2,2,3,3),(2,2,4,2),(2,2,5,1),(2,3,1,4),(2,3,2,3),(2,3,3,2),(2,3,4,1),(2,4,1,3),(2,4,2,2),(2,4,3,1),(2,5,1,2),(2,5,2,1),(2,6,1,1),(3,1,1,5),(3,1,2,4),(3,1,3,3),(3,1,4,2),(3,1,5,1),(3,2,1,4),(3,2,2,3),(3,2,3,2),(3,2,4,1),(3,3,1,3),(3,3,2,2),(3,3,3,1),(3,4,1,2),(3,4,2,1),(3,5,1,1),(4,1,1,4),(4,1,2,3),(4,1,3,2),(4,1,4,1),(4,2,1,3),(4,2,2,2),(4,2,3,1),(4,3,1,2),(4,3,2,1),(4,4,1,1),(5,1,1,3),(5,1,2,2),(5,1,3,1),(5,2,1,2),(5,2,2,1),(5,3,1,1),(6,1,1,2),(6,1,2,1),(6,2,1,1)]



这就是我的问题所在。Ruby 是我背景的重要组成部分,所以我对 DRY 原则非常重视。在我的代码中包含 d1 <- [1..6], d2 <- [1..6], d3 <- [1..6], d4 <- [1..6] 似乎没有必要,我想相信有更好的方法来做到这一点。

据我了解,我当前的方法通过在幕后运行 4 个嵌套循环来发挥作用——每个生成器一个。有没有办法让一个 <- [1..6] 生成器为所有变量工作,有效地创建 4 个嵌套循环?如果没有,是否有一种更少冗余或惯用的方式来编写此代码以实现相同的结果?

注意:我对这种语言很陌生,所以如果这应该是显而易见的,我深表歉意。如果您使用了新手命令式/面向对象程序员不熟悉的任何单词/概念,请尝试为我解释它们。

最佳答案

如果您关心的是 [1..6]重复(范围独立变化的能力),您可以使用:

let die = [1..6] in [ (d1,d2,d3,d4) | d1 <- die, d2 <- die
                                    , d3 <- die, d4 <- die
                                    , (d1 + d2 + d3 + d4) == 10 ]

总体而言,要删除显式模具命名,虽然这并不完全相同,因为它将是列表而不是元组:
let die = [1..6] in [dice | dice <- sequence (replicate 4 die), sum dice == 10]

要恢复元组,您可以进行模式匹配,但是如果输入表达式发生更改,则可能会引入难以跟踪的错误,因为模式匹配失败将简单地排除元素:
let die = [1..6] in
  [ (d1,d2,d3,d4) | dice@[d1,d2,d3,d4] <- sequence (replicate 4 die)
                  , sum dice == 10 ]

关于haskell - 在列表理解中拥有许多相同生成器的惯用方式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46814606/

相关文章:

haskell - 处理(深度嵌套)仿函数的正确方法是什么?

javascript - 如何用 Ruby 编写 IIFE?

ruby - 在 Ruby 中什么时候使用 dup,什么时候使用 clone?

haskell - 列表理解 : making lists of lists

python - 从多个属性创建列表

c++ - 使用数据库模型(键)来引用运行时对象,好主意还是坏主意?

haskell - 绑定(bind)函数替代方案,无需显式返回 Monad

haskell - 是否可以在 Haskell 中递归定义列表?

haskell - 组成延续和状态单子(monad)更改器(mutator)的正确方法

python - 如何使用列表理解使嵌套列表的长度等于列表中数字的值?