【问题标题】:Can you create more than one element of a list at a time with a list comprehension in haskell?你可以在haskell中使用列表理解一次创建多个列表元素吗?
【发布时间】:2010-10-08 17:53:12
【问题描述】:

因此,例如,假设我有一个数字列表,我想创建一个列表,其中包含每个数字乘以 2 和 3。有什么方法可以执行以下操作,但返回一个列表数字而不是数字列表?

mult_nums = [ [(n*2),(n*3)] | n <- [1..5]] 
-- this returns [[2,3],[4,6],[6,9],[8,12],[10,15]]
-- but we want [2,3,4,6,6,9,8,12,10,15]

【问题讨论】:

    标签: haskell list list-comprehension


    【解决方案1】:

    我发现扩展列表理解使这更容易阅读:

    [ m | n <- [1..5], m <- [2*n,3*n] ]
    

    准确检查它的作用以及它与其他解决方案的关系可能会有所帮助。让我们将它定义为一个函数:

    mult lst = [ m | n <- lst, m <- [2*n,3*n] ]
    

    时尚之后,这个desugars

    mult' lst = 
        concatMap (\n -> concatMap (\m -> [m]) [2*n,3*n]) lst
    

    表达式concatMap (\m -&gt; [m])m 包装在一个列表中以便立即将其展平——它等同于map id

    将此与@FunctorSalad 的答案进行比较:

    mult1 lst = concatMap (\n -> [n*2,n*3]) lst
    

    我们已经优化了concatMap (\m -&gt; [m])

    现在@vili 的回答:

    mult2 lst = concat [ [(n*2),(n*3)] | n <- lst]
    

    这意味着:

    mult2' lst = concat (concatMap (\n -> [[2*n,3*n]]) lst)
    

    与上面的第一个解决方案一样,我们不必要地创建了一个列表列表,我们必须 concat 离开。

    我认为没有使用列表推导的解决方案,但对mult1 进行了取消处理。我的直觉是 Haskell 编译器通常足够聪明,这无关紧要(或者,由于惰性评估,不必要的 concats 很便宜(而它们在急切的语言中是致命的))。

    【讨论】:

      【解决方案2】:

      在一些类似的情况下,concatMap 也可以很方便,虽然这里变化不大:

      concatMap (\n -> [n*2,n*3]) [1..5]

      【讨论】:

      • 对于instance Monad [](&gt;&gt;=) == flip concatMap... 克里斯的回答似乎掩盖了那部分,但这个答案是上述答案的一个子集。
      【解决方案3】:

      你可以使用 concat。

      concat [ [(n*2),(n*3)] | n <- [1..5]] 
      output: [2,3,4,6,6,9,8,12,10,15]
      

      【讨论】:

        猜你喜欢
        • 2021-12-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多