haskell,映射两个列表,将每个元素添加到另一个列表中

时间:2014-04-21 09:51:39

标签: haskell list-comprehension higher-order-functions

列表理解风格中给出了一个功能

f1 :: [Int] -> [Int] -> [Int]
f1 xs ys = [ x+y | x <- xs, y <-ys ]

那并不复杂。 示例输出:

  

*主&GT; f2 [1,2,3,4] [5,6,7,8]
  [6,7,8,9,7,8,9,10,8,9,10,11,9,10,11,12]

任务是仅使用mapfilterconcat来转换此功能和​​其他几项功能。 其他函数没有问题,但我不知道如何计算嵌套map。 第一个列表的每个元素都将添加到另一个列表中的每个元素。

4 个答案:

答案 0 :(得分:4)

我不是直接给出这个家庭作业的解决方案,而是用更一般的术语解释它。你现在可能不太了解它,但至少应该能够找出你需要的东西!

map只是&{34;促进&#34;的Functor方法的专用版本(用于列表仿函数)。函数函数的函数:

class Functor f where
  fmap :: (a->b) -> f a->f b

现在,列表是一种特别强大的仿函数: applicative 仿函数,甚至是monad。 Applicative让许多程序员感到困惑,但你的例子非常合适:

  

前奏&GT; :m + Control.Applicative
  Prelude Control.Applicative&gt;设f1 xs ys =(+)&lt; $&gt; xs&lt; *&gt; YS
  Prelude Control.Applicative&gt; :t f1
  f1 ::(Num b,Applicative f)=&gt; f b - &gt; f b - &gt; f b
  Prelude Control.Applicative&gt; f1 [1,2,3,4] [5,6,7,8]
  [6,7,8,9,7,8,9,10,8,9,10,11,9,10,11,12]

当然你也可以写简单

  

Prelude Control.Applicative&gt; (+)&lt; $&gt; [1,2,3,4]&lt; *&gt; [5,6,7,8]
  [6,7,8,9,7,8,9,10,8,9,10,11,9,10,11,12]

看起来很简单,但这是如何工作的?关于Applicative类的令人困惑的是,你继续将curried函数插入到functor中,在那里部分评估它们,并以某种方式从外部检索结果。对于monad,你不能这样做,所以他们可以更容易掌握。仅使用Monad类型类,也可以执行示例(Monad严格地比Applicative更严格。

Haskell列表的理解实际上只是monad操作的语法糖!

                   [ x+y | x <- xs, y <- ys ]

是糖的

                   xs >>= \x -> ys >>= \y -> return (x+y)

或附加括号:

                   xs >>= ( \x -> ( ys >>= ( \y -> return (x+y) ) ) )

好吧,您可以使用以下规则转换为仅包含mapconcat的内容:

  • ys >>= (\y -> return (f y))map f ys相同。
  • zs >>= (\z -> g z)concat (map g zs)相同。

答案 1 :(得分:2)

一种方式是:

f1 xs ys = concat $ map (\x -> map (\y -> x + y) ys) xs

ghci中的演示:

λ> f1 [1,2,3,4] [5,6,7,8]
[6,7,8,9,7,8,9,10,8,9,10,11,9,10,11,12]

答案 2 :(得分:1)

[ x+y | x <- xs, y <-ys ]

相同
do {x <- xs; y <- ys; return (x + y)}

相同
xs >>= \x -> ys >>= \y -> return (x + y)

>>=被称为bind。这里使用的是着名的monad列表。对于列表,返回定义为return x = [x],绑定定义为xs >>= f = concatMap f xs,顾名思义,concatMap只是concat和{{1}的组合}。

列表monad背后的想法是,使用map,您不确定地选择列表中的某个任意元素,然后使用它进行一些计算,最后,您将获得所有可能结果的列表得到。所以在你的例子中,

x <- xs

分别从do {x <- xs; y <- ys; return (x + y)} x选择yxs,并获得所有可能结果的列表。

现在,我将让您使用此知识将列表理解转换为仅使用ysmap的表达式。

对于concat,列表推导中的条件filter会转换为列表monad中的b,如果您想要非guard b,则可以用filter表示 - 单词表达。

答案 3 :(得分:0)

通用列表理解的格式为

[ e | qual1 , qual2 , ... , qualN ]

其中e是表达式,qual是限定符。限定符可以有三种形式:生成器(x<-list),布尔警卫(x/=0)和本地声明(let x = ...)。由于你只使用发电机,我将专注于那些。

根据Haskell definition,列表汇总可以翻译如下

[ e | x<-l , quals ] = concat $ map (\x -> [ e | quals ]) l
[ e | ]              = [ e ]  -- singleton list

所以你可以将这些应用到[ x+y | x <- xs, y <-ys ]并获得解决方案(基本上就是Sibi的答案)。