Haskell 在列表中的元素链对上映射函数
我想将一个函数映射到列表中元素的链式对上。考虑列表:Haskell 在列表中的元素链对上映射函数,haskell,functional-programming,Haskell,Functional Programming,我想将一个函数映射到列表中元素的链式对上。考虑列表: a = [1,2,3,4,5] 通过使用函数f a1 a2=a1(a,p a prev:res))(last xs,[])(init xs来保持运行时间的线性,但它确实不是很优雅(它对无限列表不起作用:-)@yatima2975这就是我的意思^^fp=foldr g[]。tails,其中g(x:y:u)r=pxy:r;g u=[]。这是一个伪装的准形像。顺便说一句带pxs(tail xs)=(带p tail的zipwhith)xs。我会写f
a = [1,2,3,4,5]
通过使用函数f a1 a2=a1
,我想得到:
[True,True,True,True]
以下几点似乎在总体上起作用:
zipWith f a (tail a)
不过,我觉得这有点老土。有没有更合适的方法,比如使用fold?您可以编写如下函数
movingApply :: (a -> a -> b) -> [a] -> [b]
movingApply f (x:y:xs) = f x y : movingApply f (y:xs)
movingApply f _ = []
(请随意选择一个更好的名称,这个名称很糟糕),但当您将其展开时,它在计算上与使用f x(drop 1 x)的zipWith相同。请注意,我使用了
drop 1
而不是tail
,这是因为tail
是一个部分函数,tail[]
导致运行时错误,而drop 1[]
返回[]
。由于这与zipWith变体几乎相同,我更喜欢zipWith,因为它是一个单行程序,我不需要手动执行递归
movingApply :: (a -> a -> b) -> [a] -> [b]
movingApply f (x:y:xs) = f x y : movingApply f (y:xs)
movingApply f _ = []
(请随意选择一个更好的名称,这个名称很糟糕),但当您将其展开时,它在计算上与使用f x(drop 1 x)的zipWith相同。请注意,我使用了
drop 1
而不是tail
,这是因为tail
是一个部分函数,tail[]
导致运行时错误,而drop 1[]
返回[]
。由于这与zipWith
变体几乎相同,我更喜欢zipWith
,因为它是一个单行程序,我不必手动执行递归。我想我可以代表Haskell社区发言,如果我告诉你这是在Haskell中执行此操作的最惯用的方式。您可以使用折页将某些东西拼凑在一起,但它显然不如第一个变体可读:
f p xs = snd $ foldl (\acc x -> (x, snd acc ++ [p (fst acc) x])) (head xs, []) (tail xs)
感谢@WillNess为上述函数提供了一个更具可读性的版本,尽管它在简洁性和清晰性方面仍然不如zipWith
f p = foldr g [] . tails where g (x:y:_) r = p x y:r; g _ _ = []
这真是太粗俗了。在这种情况下使用折叠的问题是,通常情况下,元素将被单独处理,并且它们不“知道”它们的邻居。他们只知道累加器和他们自己的值
在本例中,使用
f(我想我可以代表Haskell社区发言,如果我告诉你,这是Haskell中最惯用的方法。你可以使用折叠将一些东西拼凑在一起,但显然不如第一个变体可读:
f p xs = snd $ foldl (\acc x -> (x, snd acc ++ [p (fst acc) x])) (head xs, []) (tail xs)
感谢@WillNess为上述函数提供了一个更具可读性的版本,尽管它在简洁性和清晰性方面仍然不如zipWith
f p = foldr g [] . tails where g (x:y:_) r = p x y:r; g _ _ = []
在这种情况下使用折叠的问题是,通常元素将被单独处理,它们不“知道”它们的邻居。它们知道的唯一值是累加器和它们自己的值
在本例中,执行f(可以在状态函子上使用可遍历实例来实现预期结果,如下所示:
traverseSt :: Traversable t => (a -> a -> b) -> a -> t a -> t b
traverseSt f x ta = runState (traverse (\a -> get >>= \a' -> f a a'<$put a) ta) x
通过这种方式拆分代码,您还可以在其他结构上定义zipSelf
,例如Tree
s或Maybe
s,或第一个元素容易提取的任何类型
Cheerio,您可以在状态函子上使用可遍历实例来实现预期结果,如下所示:
traverseSt :: Traversable t => (a -> a -> b) -> a -> t a -> t b
traverseSt f x ta = runState (traverse (\a -> get >>= \a' -> f a a'<$put a) ta) x
通过这种方式拆分代码,您还可以在其他结构上定义zipSelf
,例如Tree
s或Maybe
s,或第一个元素容易提取的任何类型
干杯,您可以使用mapAccumL
import Data.List
a = [1,2,3,4,5]
compareAdjacent = snd $ mapAccumL (\acc x -> (x,(x > acc))) 0 a
这将生成输出[True,True,True,True,True]。如果希望它忽略第一个列表项,可以创建如下函数:
compareAdjacent' (x:xs) = snd $ mapAccumL (\acc x -> (x,(x > acc))) x xs
compareAdjacent' [] = []
你可以使用mapAccumL
import Data.List
a = [1,2,3,4,5]
compareAdjacent = snd $ mapAccumL (\acc x -> (x,(x > acc))) 0 a
这将生成输出[True,True,True,True,True]。如果希望它忽略第一个列表项,可以创建如下函数:
compareAdjacent' (x:xs) = snd $ mapAccumL (\acc x -> (x,(x > acc))) x xs
compareAdjacent' [] = []
那么,你会如何使用折叠呢?使用zipWith f a(tail a)
有什么不妥之处?我会说这是惯用的Haskell。map f$zip xs(tail xs)
会按照你的标题所说的做。或者[f x y|(x,y)那么,你会如何使用折叠呢?使用zipWith f a(tail a)有什么不妥之处
?我想说这是惯用的Haskell。映射f$zip xs(tail xs)
会按照你的标题所说的做。或者[f x y|(x,y)实际上,在中使用tail
是很好的
,即使原因有点违反直觉。zipWith
的第一种定义类似于zipWith f[].=[]
,因此当xs=[]时,zipWith f xs(tail xs)
不会计算tail xs
@chi很好,但我喜欢使用drop 1
而不是tail where,因为我偏爱。listToMaybe和head也是如此。事实上,在zipWith f xs(tail xs)中使用tail
很好
,即使原因有点违反直觉。zipWith
的第一种定义类似于zipWith f[].=[]
,因此当xs=[]时,zipWith f xs(tail xs)
不会计算tail xs
@chi很好,但我喜欢使用drop 1
而不是tail where,因为我偏爱它。listToMaybe和head也是如此。我会写f p xs=snd$foldr(\a(prev,res)->(a,p a prev:res))(last xs,[])(init xs
来保持运行时间的线性,但它确实不是很优雅(它对无限列表不起作用:-)@yatima2975这就是我的意思^^fp=foldr g[]。tails,其中g(x:y:u)r=pxy:r;g u=[]
。这是一个伪装的准形像。顺便说一句带pxs(tail xs)=(带p tail的zipwhith)xs
。我会写fpxs=snd$f