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

List 映射到列表,最后一个列表元素除外,list,haskell,functional-programming,map-function,List,Haskell,Functional Programming,Map Function,如何最好地映射列表的所有元素(最后一个列表元素除外) 假设我们有一个列表让l=[1,2,3,4],并且想要得到[2,3,4,4] 我确实有一个解决方案,但它不像“功能性”的方式(在ghci中): 设l=[1,2,3,4] 让len=toIntegral$length l——以避免类型不匹配的整数Int 设l1=zip l[1..] 设l2=map(\(x,y)->如果ya,而不是a->b 或者,你也可以这样做 mapBut1 f (x:y:xs) = f x : mapBut1 f (y:xs)

如何最好地映射列表的所有元素(最后一个列表元素除外)

假设我们有一个列表
让l=[1,2,3,4]
,并且想要得到
[2,3,4,4]

我确实有一个解决方案,但它不像“功能性”的方式(在ghci中):

设l=[1,2,3,4]
让len=toIntegral$length l——以避免类型不匹配的整数Int
设l1=zip l[1..]
设l2=map(\(x,y)->如果y

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

只需重新编写
map
,但在只有一个元素时,请做一个特例:

mapBut1 :: (a -> a) -> [a] -> [a]
mapBut1 f [] = []
mapBut1 f [x] = [x]
mapBut1 f (x:xs) = f x : mapBut1 f xs
现在,即使是无限列表,它也能工作,比计算长度快得多,并且更具可读性。请注意,这会将函数类型限制为
a->a
,而不是
a->b

或者,你也可以这样做

mapBut1 f (x:y:xs) = f x : mapBut1 f (y:xs)
mapBut1 f other = other
它们是等价的定义,但后者使用的模式匹配少了1个。不过,我更喜欢前者,因为它更能显示正在处理的案例。

如果您不关心性能,也可以使用标准库(无特殊导入)

你可以写 哪里
  • f
    :要映射的函数
  • 列表
    :要映射的列表

这是一份假装准形态的工作,和往常一样:

import Data.List (tails)

mapButLast :: (a -> a) -> [a] -> [a]
mapButLast f = foldr g [] . tails where
  g (x:_:_) r = f x : r
  g xs      _ = xs
或者用适当的方式,我们就写

mapButLast f = para g [] where
  g x [] r = [x]
  g x _  r = f x : r
在哪里


是什么让这最后一个元素如此特别

我知道它没有回答你的问题,但我会考虑一种类似

的类型。
data Foo a = Foo a [a]

和一个合适的函子。

我只想添加一个替代方法,使用列表理解并尝试比较解决方案(第一次尝试时,请告诉我是否做得不对)

执行

ghc -O2 --make allbutlast.hs
./allbutlast --output allbutlast.html

示例报告:

非常好!只有一件小事:代码最后一行中的
xs
不应该是
x
,因为我们正在匹配长度为1的列表吗?@mort首先,Haskell不关心变量的名称,因此将
xs
重命名为
x
不会改变代码的含义。其次,该行匹配的是与模式
(x:xs)
不匹配的任何内容,可以是
[\u]
[]
[\u]
表示一个元素的列表)。所以它的意思是除了模式
(x:xs)
之外的任何东西都会被匹配,而不是单个元素会被匹配。然而,您确实让我发现了代码中的一个小错误。这是一个很好的模式@我在中编辑了更多内容,带有链接
para
是“明显”的方式,但我喜欢使用
tails
来获得一个假装的para。尽管如此,与它们并排在一起,我不太确定它实际上比
para
本身更容易理解。@J.Abrahamson最终它们是一样的-使用
tails
para
所做的(最多跳过一个节拍)。使用
tails
它甚至可以重用结构。有时非标准的
parafz[]=z;parafzxs@(x:t)=fxxs(parafzt)
可能更可取,这正是
下面的内容。。。tails
variant.oh和。这并不是那么糟糕的性能,因为
init
是惰性的,并且
last list
expr。在评估之前,在WHNF中。我敢打赌,它的答案与O(n)遍历到最后一个ELM,这可能是很好的优化GHC。DavidUnric,这有相当差的性能特点。特别是,它不是一个好的拖缆:它会将整个输入列表保存在内存中,直到最后一个元素被计算。我喜欢这个解决方案,因为它甚至对初学者都可读;)
para f z (x:xs) = f x xs (para f z xs)
para f z []     = z
data Foo a = Foo a [a]
reverse $ last l : [f x | x <- tail (reverse l)]
cabal update
cabal install QuickCheck
cabal install -j --disable-tests criterion
ghc -O2 --make allbutlast.hs
./allbutlast --output allbutlast.html