我想仅在第一次出现时用新值替换列表中的元素.我编写了下面的代码,但使用它,所有匹配的元素都会改变.
replaceX :: [Int] -> Int -> Int -> [Int]
replaceX items old new = map check items where
check item | item == old = new
| otherwise = item
Run Code Online (Sandbox Code Playgroud)
如何修改代码,以便更改只发生在第一个匹配的项目?
谢谢你的帮助!
dav*_*420 11
重点是map和f(check在你的例子中)只沟通如何转换单个元素.他们不会就列表在多大程度上改变元素map进行沟通:始终一直持续到最后.
map :: (a -> b) -> [a] -> [b]
map _ [] = []
map f (x:xs) = f x : map f xs
Run Code Online (Sandbox Code Playgroud)
让我们写一个新版本map---我会称它为mapOnce因为我想不出一个更好的名字.
mapOnce :: (a -> Maybe a) -> [a] -> [a]
Run Code Online (Sandbox Code Playgroud)
关于此类签名有两点需要注意:
因为我们可能会停止f在列表中向下部分应用,所以输入列表和输出列表必须具有相同的类型.(map因为整个列表将始终被映射,因此类型可以更改.)
类型f没有改变a -> a,但是a -> Maybe a.
Nothing 将意味着"保持这个元素不变,继续下去"Just y 将意味着"改变这个元素,并保持其余元素不变"所以:
mapOnce _ [] = []
mapOnce f (x:xs) = case f x of
Nothing -> x : mapOnce f xs
Just y -> y : xs
Run Code Online (Sandbox Code Playgroud)
你的例子现在是:
replaceX :: [Int] -> Int -> Int -> [Int]
replaceX items old new = mapOnce check items where
check item | item == old = Just new
| otherwise = Nothing
Run Code Online (Sandbox Code Playgroud)