使用更高阶函数,Monads或者你有什么能简化以下函数吗?
cube list = [(x, y, z) | x <- list, y <- list, z <- list]
该函数只是创建列表元素的所有三重排列的列表。例如:
> 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)]
答案 0 :(得分:10)
从Bill的回答来看,因为这是代码使用列表monad,我们可以使用“applicative”样式来做“具有更高阶函数”。这是否是一个好主意留给了工程师。
import Control.Applicative
cube :: [a] -> [b] -> [c] -> [(a,b,c)]
cube x y z = (,,) <$> x <*> y <*> z
答案 1 :(得分:8)
虽然它为您提供了列表而不是元组,但您可以使用Control.Monad中的sequence
函数:
> 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]]
sequence
函数很简洁,因为虽然它的“预期”目的是获取一个操作列表,按顺序执行它们,然后将它们的结果返回到列表中,在列表中使用它monad会给你组合免费。
> sequence $ replicate 3 "01"
["000","001","010","011","100","101","110","111"]
答案 2 :(得分:7)
实际上,您的列表理解是List monad的用法。
另一种写这个的方法是:
cube :: [a] -> [(a,a,a)]
cube list = do
x <- list
y <- list
z <- list
return (x, y, z)
答案 3 :(得分:6)
这不是一个真正严肃的答案,但无论如何我都要提出建议。主要是为了疯狂。
import Control.Monad
import Control.Monad.Instances
cube :: [a] -> [(a, a, a)]
cube = join . join $ liftM3 (,,)
玩得开心。 :)
答案 4 :(得分:3)
以乔伊亚当斯所做的为榜样:
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]]
对于完整的解决方案(传递一个列表并获得3元组),可以这样做:
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)]
但恕我直言,爱德华Z.杨的解决方案至高无上。
答案 5 :(得分:2)
如果你有位,谁需要monads?
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)