Haskell地图,但删除不符合条件的项目

时间:2019-02-15 23:23:43

标签: dictionary haskell functional-programming

该函数应获取一个元组列表,并返回总和> 5的元组。

假设我有以下代码:

fn :: [(Int, Int)] -> [(Int, Int)]

fn tuples = map (\(x,y) -> if (x + y) > 5 then (x,y) else (0,0)) tuples

fn [(3,4), (4,4), (0,1)]返回[(3,4),(4,4),(0,0)],但实际上我只希望它返回[(3,4),(4,4)]

在仍然遵循类型签名的情况下,在haskell中有可能吗?

2 个答案:

答案 0 :(得分:8)

您要的是mapMaybe

mapMaybe :: (a -> Maybe b) -> [a] -> [b]
     

基本数据。也许

     

mapMaybe函数是map的一个版本,可以丢弃元素。特别是,函数参数返回类型为Maybe b的东西。如果这是Nothing,则不会将任何元素添加到结果列表。如果它是Just b,则b包含在结果列表中。

在您的代码中使用它的最小更改是:

import Data.Maybe

fn :: [(Int, Int)] -> [(Int, Int)]
fn tuples = mapMaybe (\(x,y) -> if (x + y) > 5 then Just (x,y) else Nothing) tuples

但是,在这种特定情况下,您实际上并没有进行转换,只是删除了。如果您不打算以后再添加转换,则filter更合适:

fn = filter (\(x,y) -> x+y > 5)

答案 1 :(得分:4)

一个奇怪的问题,但在评论之后

  

我在haskell中看不到“空元组”的概念

我想我知道你来自哪里。实际上,Haskell确实具有“空元组”:单元类型()是“具有零元素的元组”的类型。所以您在想的似乎是

fn tuples = map (\(x,y) -> if x + y > 5 then (x,y) else ()) tuples

但这不起作用,因为()(Int,Int)一种不同的类型。列表的元素必须全部具有相同的类型。即使它确实起作用(如动态类型一样),fn [(3,4), (4,4), (0,1)]的结果也将实际上为[(3,4), (4,4), ()]。即您仍然会得到三个元素,其中只有一个很“无聊”。

map实际上通过设计保证不会更改列表中元素的数量,仅更改其元素的值。因此,如果您要想要,则需要使用其他函数。最接近您的方法是concatMap

fn tuples = concatMap (\(x,y) -> if x + y > 5 then [(x,y)] else []) tuples

这里发生的事情也可以用两个步骤来描述:

  • 您映射了一个为每个元素生成列表的函数。结果就是列表列表。
  • 您将列表弄平了。

所以[(3,4), (4,4), (0,1)]-> [[(3,4)], [(4,4)], []]-> [(3,4), (4,4)]

尽管如此,实际上,这里根本不需要使用映射步骤-元素最终保留不变,因此filter是要使用的工具。