创建列表的另一种方式而不是理解?

时间:2012-02-13 15:51:51

标签: haskell

目前我在我的代码中做了类似的事情:

--Generate a list of n 'Foo's
generateFoos n = [createFoo (show i) | i <- [1..n]]

-- Create a Foo with a given name
createFoo :: String -> Foo

如果有另一种方法,那就是徘徊,而不是一直创建范围[1..n] ......

4 个答案:

答案 0 :(得分:8)

我想说不要担心。 “创建范围[1..n]”并不是真正在这里作为一个独特的步骤;那个[1..n]去了enumFromTo 1 n,它就像其他一切一样懒洋洋地构建了。这里没有隐藏的成本需要消除。

答案 1 :(得分:6)

扩展我上面的评论 - map函数自然出现的原因如下:

在Haskell中,列表推导只是用于表示法的语法糖:

[ 2 * x | x <- [1..10] ]

相当于

do { x <- [1..10]; return (2 * x) }

反过来,符号是monadic binds的语法糖 - 上面相当于

[1..10] >>= \x -> return (2 * x)

这是有效的,因为List是一个monad。使List成为monad的代码是(忽略一些不相关的东西)

instance Monad [] where  
    return x = [x]  
    xs >>= f = concat (map f xs)

所以上面对>>=的调用等同于

concat (map (\x -> return (2 * x)) [1..10])

如果我们将调用替换为bind,则相当于

concat (map (\x -> [2 * x]) [1..10])

因此,我们将函数\x -> [2 * x]映射到列表[1..10]上,然后在结果上调用concat。但由于我们的函数只构建了一个元素列表,我们可以跳过对concat的调用并用

替换代码
map (\x -> 2 * x) [1..10]

因此,相对简单的列表推导可以转化为涉及在范围内映射函数的表达式是很自然的。

答案 2 :(得分:2)

我更喜欢这样:

generateFoos n = map (createFoo . show) [1..n]

或者范围本身就是问题?然后我建议:

generateFoos n = map (createFoo . show) (enumFromTo 1 n)

答案 3 :(得分:1)

map,没有范围。

generateFoos n = unfoldr (doit (createFoo . show)) 1 where 
    doit f acc = if acc > n then Nothing else Just (f acc, acc + 1)

我不保证此代码的任何特定质量或属性;)