映射列表,最后一个列表元素除外

mor*_*ort 7 haskell functional-programming list map-function

除了最后一个列表元素外,如何最好地映射列表的所有元素?

假设我们有一个列表let l = [1,2,3,4]并希望得到[2,3,4,4].

我确实有一个解决方案,但它感觉不像是"功能"的方式(在ghci中):

let l = [1,2,3,4]
let len = toIntegral $ length l -- to avoid a type mismatch Integer <-> Int
let l1 = zip l [1..]
let l2 = map (\(x,y) -> if y < len then (x + 1,y) else (x,y)) l1
let l3 = map (fst) l2
Run Code Online (Sandbox Code Playgroud)

不太好......我希望有更好的方法!由于我是函数式编程的新手,我不知道从哪里开始寻找它.

bhe*_*ilr 13

只需重写,map但只有一个元素时才会出现特殊情况:

mapBut1 :: (a -> a) -> [a] -> [a]
mapBut1 f [] = []
mapBut1 f [x] = [x]
mapBut1 f (x:xs) = f x : mapBut1 f xs
Run Code Online (Sandbox Code Playgroud)

现在,即使对于无限列表也是如此,它比计算长度快得多,并使其更具可读性.请注意,这确实将您的函数限制为类型a -> a而不是a -> b.

或者,你可以做到

mapBut1 f (x:y:xs) = f x : mapBut1 f (y:xs)
mapBut1 f other = other
Run Code Online (Sandbox Code Playgroud)

它们是等价的定义,但后者使用的模式匹配减少1.不过,我更喜欢前者,因为处理案件的情况更为明显.

  • @mort首先,Haskell并不关心我们命名变量,因此将`xs`重命名为`x`不会改变代码的含义.其次,该行匹配任何与模式`(x:xs)`不匹配的东西,它可以是`[_]`或`[]`(`[_]`表示一个元素的列表).所以它所说的是除了模式`(x:xs)`之外的任何东西都会匹配,而不是单个元素.但是,你确实让我发现了我在这段代码中遇到的一个小错误. (2认同)

Wil*_*ess 9

像往常一样,这是假装 - paramorphism的工作:

import Data.List (tails)

mapButLast :: (a -> a) -> [a] -> [a]
mapButLast f = foldr g [] . tails where
  g (x:_:_) r = f x : r
  g xs      _ = xs
Run Code Online (Sandbox Code Playgroud)

或者正确地说para我们只是写

mapButLast f = para g [] where
  g x [] r = [x]
  g x _  r = f x : r
Run Code Online (Sandbox Code Playgroud)

哪里

para f z (x:xs) = f x xs (para f z xs)
para f z []     = z
Run Code Online (Sandbox Code Playgroud)

  • 这是一个很好的模式! (3认同)