仅替换列表中的元素一次 - Haskell

Aff*_*tus 6 haskell list

我想仅在第一次出现时用新值替换列表中的元素.我编写了下面的代码,但使用它,所有匹配的元素都会改变.

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

重点是mapf(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)

关于此类签名有两点需要注意:

  1. 因为我们可能会停止f在列表中向下部分应用,所以输入列表和输出列表必须具有相同的类型.(map因为整个列表将始终被映射,因此类型可以更改.)

  2. 类型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)