该函数应获取一个元组列表,并返回总和> 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中有可能吗?
答案 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
是要使用的工具。