如何将函数仅应用于列表的单个元素? 有什么建议吗?
示例:
let list = [1,2,3,4,3,6]
function x = x * 2
in ...
我想仅将function
应用于第一次出现3并停在那里。
输出:
List = [1,2,6,4,3,6] -- [1, 2, function 3, 4, 3, 6]
答案 0 :(得分:0)
您需要维护某种类型的状态来指示值的第一个实例,因为map
会将该函数应用于所有值。
也许是这样的
map (\(b,x) -> if (b) then f x else x) $ markFirst 3 [1,2,3,4,3,6]
和
markFirst :: a -> [a] -> [(Boolean,a)]
markFirst a [] = []
markFirst a (x:xs) | x==a = (True,x): zip (repeat False) xs
| otherwise = (False,x): markFirst a xs
我确信有一种更简单的方法,但这是我在感恩节前一天的最佳时刻。
以下是基于以下评论的另一种方法
> let leftap f (x,y) = f x ++ y
leftap (map (\x -> if(x==3) then f x else x)) $ splitAt 3 [1,2,3,4,3,6]
答案 1 :(得分:0)
要映射或不映射,这就是问题。
最好不要映射。
为什么呢?因为map id == id
无论如何,你只想通过一个元素进行映射,第一个被发现等于给定的参数。
因此,将列表拆分为两个,更改找到的元素,然后将它们全部粘合在一起。简单。
请参阅:span :: (a -> Bool) -> [a] -> ([a], [a])
。
写:revappend (xs :: [a]) (ys :: [a])
== append (reverse xs) ys
,只有效率。
或者将所有部件融合在一起成为一个功能。您可以使用手动递归或使用foldr
直接对其进行编码。请记住,
map f xs = foldr (\x r -> f x : r) [] xs
takeWhile p xs = foldr (\x r -> if p x then x : r else []) [] xs
takeUntil p xs = foldr (\x r -> if p x then [x] else x : r) [] xs
filter p xs = foldr (\x r -> if p x then x : r else r) [] xs
duplicate xs = foldr (\x r -> x : x : r) [] xs
mapFirstThat p f xs = -- ... your function
等。虽然foldr
不是直接适合,但因为您需要(\x xs r -> ...)
种类的组合功能。这被称为paramorphism,can be faked通过向tails xs
提供foldr
来代替。{/ p>