fredoverflow
fredoverflow

Reputation: 263118

Can I compute the cube list in a neat way?

Can the following function be simplified with higher order functions, Monads or what have you?

cube list = [(x, y, z) | x <- list, y <- list, z <- list]

The function simply creates a list of all triple-permutations of the elements of the list. For example:

> cube [1..2]
[(1,1,1),(1,1,2),(1,2,1),(1,2,2),(2,1,1),(2,1,2),(2,2,1),(2,2,2)]

Upvotes: 4

Views: 513

Answers (6)

identity
identity

Reputation: 969

To model after what Joey Adams did:

g>replicateM 3 [1..2]
[[1,1,1],[1,1,2],[1,2,1],[1,2,2],[2,1,1],[2,1,2],[2,2,1],[2,2,2]]

For the full solution(pass it a list and get 3-tuples), something like this can be done:

g>let cube = map (\(a:b:c:_) -> (a, b, c)) . replicateM 3
cube :: [t] -> [(t, t, t)]
(0.00 secs, 526724 bytes)
g>cube [1..2]
[(1,1,1),(1,1,2),(1,2,1),(1,2,2),(2,1,1),(2,1,2),(2,2,1),(2,2,2)]
it :: [(Integer, Integer, Integer)]

But IMHO, Edward Z. Yang's solution reigns supreme.

Upvotes: 3

Landei
Landei

Reputation: 54584

Who needs monads if you can have bits?

import Data.Bits

cube :: [(Int,Int,Int)]
cube = map tuple [0..7] where
   tuple x = (1 + div (x .&. 4)  4, 1 + div (x .&. 2)  2, 1 + x .&. 1)

Upvotes: 2

Carl
Carl

Reputation: 27003

This isn't really a serious answer, but I have to suggest it anyway. Mostly for the sake of craziness.

import Control.Monad
import Control.Monad.Instances

cube :: [a] -> [(a, a, a)]
cube = join . join $ liftM3 (,,)

Have fun with that one. :)

Upvotes: 6

Edward Z. Yang
Edward Z. Yang

Reputation: 26742

Going from Bill's answer, because this is code uses the list monad, we can use "applicative" style to do "with higher-order functions". Whether or not this is a good idea is left as an exercise for the engineer.

import Control.Applicative

cube :: [a] -> [b] -> [c] -> [(a,b,c)]
cube x y z = (,,) <$> x <*> y <*> z

Upvotes: 10

Joey Adams
Joey Adams

Reputation: 43380

Although it gives you lists instead of tuples, you can use the sequence function in Control.Monad:

> let list = [1..2]
> sequence [list, list, list]
[[1,1,1],[1,1,2],[1,2,1],[1,2,2],[2,1,1],[2,1,2],[2,2,1],[2,2,2]]

The sequence function is neat because, although its "intended" purpose is to take a list of actions, do them in order, and return their results in a list, using it on the list monad gives you combinations for free.

> sequence $ replicate 3 "01"
["000","001","010","011","100","101","110","111"]

Upvotes: 8

Bill
Bill

Reputation: 45418

In fact, your list comprehension is a usage of the List monad.

Another way to write this is:

cube :: [a] -> [(a,a,a)]
cube list = do
  x <- list
  y <- list
  z <- list
  return (x, y, z)

Upvotes: 7

Related Questions