繁体   English   中英

缺少 Haskell 原语以将函数连续应用于列表的每个元素?

[英]Missing Haskell primitive to apply a function to each element of a list successively?

在 Haskell 中,众所周知, map原语可用于将给定函数应用于列表的所有元素:

 λ> map toUpper "abcd"
"ABCD"
 λ> 

在尝试生成有限集(列表)的所有分区时,以下类似的原语会很方便:

 λ> sap toUpper "abcd"
["Abcd","aBcd","abCd","abcD"]
 λ> 

sap代表连续应用 类型签名将是:

sap :: (a -> a) -> [a] -> [[a]]

例如,集合“abcd”的部分分区可以从“bcd”的分区中通过用('a':)sap'来获得。

 λ> pbcd = [["b","c","d"],["b","cd"],["bc","d"],["c","bd"],["bcd"]]
 λ> 
 λ> concatMap (sap ('a':)) pbcd
[["ab","c","d"],["b","ac","d"],["b","c","ad"],["ab","cd"],["b","acd"],["abc","d"],["bc","ad"],["ac","bd"],["c","abd"],["abcd"]]
 λ> 

然后可以通过添加 'a' 作为它自己单独的单例来获得 5 个丢失的分区。

我的问题是,我一直无法在语言库中找到这样的原语,而且给定类型签名的Hoogle没有返回任何感兴趣的内容。

Haskell 语言库中是否存在像sap这样的原语??? 或者有没有一种方法可以写得如此简短和简单,以至于它甚至不值得成为一个单独的函数,将其置于所谓的费尔贝恩阈值以下

脚注:可以这样写sap

sap :: (a -> a) -> [a] -> [[a]]
sap fn ls = fst  $  foldr  op  ([], [])  ls
   where  op x (ll,tl) = ( ((fn x):tl) : map (x:) ll , x:tl )

基本上你从[[fn (last ls)]]作为种子开始,然后向左前进。 但这似乎行人并不简单。

似乎最简单的版本是直接递归:

sap :: (a -> a) -> [a] -> [[a]]
sap _ [] = []
sap f (x:xs) = (f x : xs) : map (x:) (sap f xs)

对此的一种可能的探索是作为paramorphism ,它可以一起访问递归结果和未处理的余数。

sap f = para step where
    step Nil = []
    step (Cons x (xs, rest)) = (f x : xs) : map (x:) rest

(未检查,可能有愚蠢的错误)

不过,我不认为这是一个巨大的改进。 我没有看到从问题本身分解递归的任何深刻见解。

为此,嗯……我过去曾使用过holesOf作为通用版本。

sap :: Traversable t => (a -> a) -> t a -> [t a]
sap f = map (peeks f) . holesOf traverse

现在这肯定说明了什么 它已将类型概括为适用于Traversable所有实例。 另一方面,所涉及的理论块对于最终结果来说太过分了,以至于我不确定它所说的实际上是什么。 在第三(?)手上,它看起来很漂亮。

或者有没有一种方法可以将它写得如此简短和简单,以至于它甚至不值得成为一个单独的函数,使其低于所谓的费尔贝恩阈值?

这个。 很少需要该功能,并且(a -> a)参数不适用于非常通用的应用程序。

使用列表递归可以实现一个简短而简单的实现:

sap :: (a -> a) -> [a] -> [[a]]
sap _ []     = []
sap f (x:xs) = (f x:xs):((x:) <$> sap f xs)

我不认为它存在于任何地方,尽管否定地证明它当然是不可能的.. 另一种编写sap ,我可能更喜欢使用foldr

sap f ls = zipWith (alterWith f) [0..] (iterate ls)
  where alterWith f i ls = take i ls ++ f (ls !! i) : drop (i+1) ls

alterWith可在https://hackage.haskell.org/package/fft-0.1.8.6/docs/Math-FFT-Base.html#v:adjust 中作为adjust使用,但我不会带来如此重量级的东西那个功能。 不过,我经常已经在项目中定义了诸如alterWith东西,如果是这样,则可以省略sap以支持上面对 zipWith 的调用。

利用Data.List.HT.splitEverywhere

import Data.List.HT

sap :: (a -> a) -> [a] -> [[a]]
sap f xs = [ pre ++ f x : post | (pre,x,post) <- splitEverywhere xs]

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM