如何将函数应用于列表的特定元素

时间:2017-11-22 21:49:28

标签: haskell

如何将函数仅应用于列表的单个元素? 有什么建议吗?

示例:

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]

2 个答案:

答案 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>