【问题标题】:Haskell - List Comprehension - get Input-ElementsHaskell - 列表理解 - 获取输入元素
【发布时间】:2013-05-14 17:44:12
【问题描述】:

如果输入是一个列表,我对列表理解有一些问题。

在所有 III 练习中都不允许使用:mapfilterconcat!!!


第一部分

要求:

一个函数f1 得到一个列表xs 三元组(a, b, cs) 其中 ab 的类型为 Int c 的类型为 [Int]

该函数应该生成一个对列表(a · b, b + c),对于所有 cs 中的 c AND 在生成的列表中应该只出现第一个元素大于第二个元素的那些对 - (a · b) > b + c

示例:

f1  [(10,20,[1,10,100]),  (4,5,[5,15,25])] 

应该返回以下列表:

[(200,21),(200,30),(200,120),(20,10)]

我的尝试:

f1 :: Int -> Int -> [Int] -> [(Int, Int)]
f1 a b cs = [(a*b, b+c)| c<-cs, (a*b)>(b+c)]

它工作正常,但不适用于列表作为输入。

所以我尝试了几种方法,但不幸的是不是正确的:-(

f1 :: [(Int, Int, [Int])] -> [(Int, Int)]

第一种方法:

f1 xs = [((xs !! 0)*(xs !! 1), (xs !! 1)+c)| c<-(xs !! 2), ((xs !! 0)*(xs !! 1))>((xs !! 1)+c)]

第二种方法:

f1 let (a, b, cs) = xs = [(a*b, b+c)| c<-cs, (a*b)>(b+c)]

第三种方法:

f1 (a b cs) = [(a*b, b+c)| c<-cs, (a*b)>(b+c)]

这三个都不行!

dave4420 的解决方案:

f1 :: [(Int, Int, [Int])] -> [(Int, Int)]
f1 xs = [ (a*b, b+c) | (a, b, cs) <- xs, c <- cs, (a*b)>(b+c) ]

第二部分

要求:

函数 g1 获取相同类型对的列表并从中生成一个普通列表。

示例:

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

我的尝试:

g1 :: [(Int, Int)] -> [Int]
g1 xs = [a,b | (a,b)<-xs]

我得到一个编译错误,因为列表理解输出中的 a,b 没有正确的语法。

但是我可以返回 a 或 b 或例如a+b:

g1 xs = [a | (a,b)<-xs]

g1 xs = [a+b | (a,b)<-xs]

你能帮我解决这个问题吗?

再次感谢

第三部分来了……

【问题讨论】:

    标签: list haskell list-comprehension let


    【解决方案1】:
    f1 :: [(Int, Int, [Int])] -> [(Int, Int)]
    f1 xs = [ {-TODO-} | (a, b, cs) <- xs, c <- cs, {-TODO-} ]
    

    我留下了几个 {-TODO-} 供你填写。


    第二部分。

    如果你不得不写

    g1' :: [[Int]] -> [Int]
    

    你会怎么做?然后你能把g1'修改成你想要的g1吗?

    【讨论】:

    • 不错的答案,它帮助我更好地理解。
    • 我不确定你们是否都通过编辑我的问题得到通知,所以我想提一下,我的问题分为三个部分......谢谢
    • @John 如果您的问题包含三个部分,您应该一次将它们全部发布。此网站的正确礼仪是接受正确答案,然后在新帖子中提出您的新问题。
    • 好的,很抱歉。因为这三个问题很相似,所以我想如果我得到第一个,那么我将能够在没有帮助的情况下解决其他两个问题。好的,如果我不能得到它,我会在新帖子中发布第三部分。再次抱歉。
    • 你能告诉我像g1'这样的函数的名称,以便我阅读它吗?我以前从未见过这种功能。
    【解决方案2】:

    你已经接近了。使用你的

    f1 :: Int -> Int -> [Int] -> [(Int, Int)]
    f1 a b cs = [(a*b, b+c)| c<-cs, (a*b)>(b+c)]
    

    您首先需要重写它以获取三元组(Int, Int, [Int])。这是一个微不足道的变化,

    f1_a :: (Int, Int, [Int]) -> [(Int, Int)]
    f1_a (a,b,cs) = [(a*b, b+c) | c <- cs, a*b > b+c]
    

    现在,您需要将该函数应用于三元组输入列表的每个元素。如果你可以使用map,那就是map f1_a xs,但既然你不能,那就把它写成列表理解

    f2 :: [(Int, Int, [Int])] -> [[(Int, Int)]]
    f2 xs = [f1_a x | x <- xs]
    

    但是单级列表太多了,你想要一个平面列表,所以你需要concat列表列表。你也不应该使用concat,所以你需要把它写成一个列表理解。

    现在,concat 做了什么?

    对于参数中的每个列表,对于该列表中的每个元素,将该元素放入结果中,所以

    concat' xss = [x | xs <- xss, x <- xs]
    

    现在将其应用于f2

    【讨论】:

      【解决方案3】:

      您已经完成了 90% 的工作。 请记住,在 GHCI 中,您在定义之前使用 let, 但是在常规源代码中,您不需要。 所以让我们看看你到目前为止有什么。

      λ> let f1 (a,b,cs) = [(a*b, b+c)| c<-cs, (a*b)>(b+c)]
      

      请注意,我在您的元组中添加了逗号。让我们找出f1的类型。

      λ> :t f1
      f1 :: (Num t, Ord t) => (t, t, [t]) -> [(t, t)]
      

      现在,您可以忽略 (Num t, Ord t) =&gt; 部分。 这是一个函数,它接受一个包含一个元素的元组,另一个 元素和元素列表。 所以我们不能把整个元组列表传递给它, 只有一个元组。

      λ> f1 (10,20,[1,10,100])
      [(200,21),(200,30),(200,120)]
      λ> f1 (4,5,[5,15,25])
      [(20,10)]
      

      这是您想要的结果的第一部分。

      λ> f1 (4,5,[5,15,25])
      [(20,10)]
      

      这是第二部分。 所以现在你需要另一个接受输入的函数,如下所示:

      [(10,20,[1,10,100]),  (4,5,[5,15,25])]
      

      也就是说,我们想要一个接受元组列表的函数。 在f1 的基础上,我们可以这样写:

      λ> let f2 xs = [f1 x | x <- xs]
      λ> f2 [(10,20,[1,10,100]),  (4,5,[5,15,25])]
      [[(200,21),(200,30),(200,120)],[(20,10)]]
      

      请注意,结果是一个列表列表,我们只需要一个普通列表。 由于不允许使用concat,因此请看一下 groovy 或 Daniel Fisher 是如何解决这个问题的。 两种不同的方法,都不错。

      【讨论】:

      • @Daniel,mhwombat 感谢你们两位的解释。我会在明天完成其他练习后立即测试它们并给你反馈。现在我将使用 dave4420 的解决方案。
      猜你喜欢
      • 2023-04-10
      • 2015-02-28
      • 1970-01-01
      • 2022-12-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-04
      • 2020-02-07
      相关资源
      最近更新 更多