在haskell列表理解中应用列表中的乘法

时间:2014-12-11 02:40:47

标签: haskell list-comprehension

这里有哈克尔诺布。我正在做Learn you a Haskell并遇到了这个问题:

[ x*y | x <- [2,5,10], y <- [8,10,11]]

我把它改写如下

[ x*y | x <- [[1,2,3], [2,3,4]], y <- [[4,5,6],[5,6,7]] ]
编译器对我大吼大叫可能是因为我试图将列表与另一个列表进行多次复制。但是,如果我想递归地乘以xy的每个子列表,我该怎么做?

这是我得到的错误:

No instance for (Num [t0]) arising from a use of `*'
    Possible fix: add an instance declaration for (Num [t0])
    In the expression: x * y

更新

到目前为止,我已到达这里:

[ [a*b | a <- x, b <- y] | x <- [[1,2,3],[2,3,4]], y <- [[4,5,6], [5,6,7]] ]

但是这仍然会返回一个列表列表。什么是在Haskell中展平列表的优雅方式?

2 个答案:

答案 0 :(得分:3)

所以让我们尝试几种方式。我将使用ghci来说明一些例子:

% ghci
GHCi, version 7.8.2: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
λ [ x*y | x <- [2,5,10], y <- [8,10,11]]
[16,20,22,40,50,55,80,100,110]
λ -- so let's abstract that to a function
λ let multList xs ys = [ x*y | x <- xs, y <- ys ]
λ multList [2,5,10] [8,10,11]
[16,20,22,40,50,55,80,100,110]
λ -- let's try a simpler example
λ multList [1] [1]
[1]
λ -- now let's see if we can get your code working
λ -- (I tweaked the variable names, but that's just cosmetic)
λ [ xs*ys | xs <- [[1,2,3], [2,3,4]], ys <- [[4,5,6],[5,6,7]] ]

<interactive>:13:1:
    No instance for (Num [t0]) arising from a use of ‘it’
    In a stmt of an interactive GHCi command: print it
λ -- yup, that's the error alright
λ -- let's skip multiplying. what else can we do with xs and ys?
λ -- well, we could create the pair (xs,ys)
λ [ (xs,ys) | xs <- [[1,2,3], [2,3,4]], ys <- [[4,5,6],[5,6,7]] ]
[([1,2,3],[4,5,6]),([1,2,3],[5,6,7]),([2,3,4],[4,5,6]),([2,3,4],[5,6,7])]
λ -- that's each pair of sublists, but we want to compute the products of each element
λ -- fortunately, that's exactly what multList does!
λ :t multList
multList :: Num t => [t] -> [t] -> [t]
λ [ multList xs ys | xs <- [[1,2,3], [2,3,4]], ys <- [[4,5,6],[5,6,7]] ]
[[4,5,6,8,10,12,12,15,18],[5,6,7,10,12,14,15,18,21],[8,10,12,12,15,18,16,20,24],[10,12,14,15,18,21,20,24,28]]
λ -- so that creates four sublists, one for each pair of lists.
λ -- what if we want to flatten that out?
λ -- well, we could just use `concat`
λ :t concat
concat :: [[a]] -> [a]
λ concat [ multList xs ys | xs <- [[1,2,3], [2,3,4]], ys <- [[4,5,6],[5,6,7]] ]
[4,5,6,8,10,12,12,15,18,5,6,7,10,12,14,15,18,21,8,10,12,12,15,18,16,20,24,10,12,14,15,18,21,20,24,28]
λ -- alternately, we could try to inline our definition of `multList` and see where that gets us
λ [ [ x*y | x <- xs, y <- ys ] | xs <- [[1,2,3], [2,3,4]], ys <- [[4,5,6],[5,6,7]] ]
[[4,5,6,8,10,12,12,15,18],[5,6,7,10,12,14,15,18,21],[8,10,12,12,15,18,16,20,24],[10,12,14,15,18,21,20,24,28]]
λ -- nothing yet, but see how we've got two list comprehensions?
λ -- let's combine them into one!
λ [ x*y | xs <- [[1,2,3], [2,3,4]], ys <- [[4,5,6],[5,6,7]], x <- xs, y <- ys ]
[4,5,6,8,10,12,12,15,18,5,6,7,10,12,14,15,18,21,8,10,12,12,15,18,16,20,24,10,12,14,15,18,21,20,24,28]
λ -- hey, that worked!

答案 1 :(得分:1)

在GHCI中试试这个:

Prelude> let combinate xs ys = [ x*y | x<-xs, y<-ys ]
Prelude> concat [ combinate x y | x <- [[1,2,3], [2,3,4]], y <- [[4,5,6],[5,6,7]] ]
[4,5,6,8,10,12,12,15,18,5,6,7,10,12,14,15,18,21,8,10,12,12,15,18,16,20,24,10,12,14,15,18,21,20,24,28]